Merge "Merge "Merge "Merge "Merge "DO NOT MERGE: Add test to ensure media stack has no sticky SSLv3 fallback DO NOT MERGE" into kitkat-cts-dev am: ea13c86803  -s ours am: a997adead8  -s ours" into lollipop-mr1-cts-dev am: a0ad4a804c  -s ours am: 8aa7d2639a  -s ours" into nougat-cts-dev am: da77c9cff3  -s ours" into nyc-dev am: e86d36d770 am: dae3a1bfd7 am: cc02a970be am: 55dace8753 am: bb32c62838" into nyc-mr2-dev-plus-aosp
am: bdc66ef4a4  -s ours

Change-Id: I696ae10a98a45499e58740903cbd40de14e83e59
diff --git a/.gitignore b/.gitignore
index dbd5bcf..07a80d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,5 +7,3 @@
 /bin
 .idea/*
 .idea/
-gen/
-*.iml
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..9defdf3
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,10 @@
+[Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+                  -fw apps/CtsVerifier/src/com/android/cts/verifier/usb/
+                      apps/CtsVerifierUSBCompanion/
+                      tests/tests/animation/
+                      tests/tests/print/
+                      tests/tests/text/
+                      tests/tests/transition/
+                      tests/tests/view/
+                      tests/tests/widget/
diff --git a/apps/CameraITS/pymodules/its/cv2image.py b/apps/CameraITS/pymodules/its/cv2image.py
new file mode 100644
index 0000000..83e654e
--- /dev/null
+++ b/apps/CameraITS/pymodules/its/cv2image.py
@@ -0,0 +1,197 @@
+# 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 matplotlib
+matplotlib.use('Agg')
+
+import its.error
+from matplotlib import pylab
+import sys
+from PIL import Image
+import numpy
+import math
+import unittest
+import cStringIO
+import scipy.stats
+import copy
+import cv2
+import os
+
+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)
+
+class Chart(object):
+    """Definition for chart object.
+
+    Defines PNG reference file, chart size and distance, and scaling range.
+    """
+
+    def __init__(self, chart_file, height, distance, scale_start, scale_stop,
+                 scale_step):
+        """Initial constructor for class.
+
+        Args:
+            chart_file:     str; absolute path to png file of chart
+            height:         float; height in cm of displayed chart
+            distance:       float; distance in cm from camera of displayed chart
+            scale_start:    float; start value for scaling for chart search
+            scale_stop:     float; stop value for scaling for chart search
+            scale_step:     float; step value for scaling for chart search
+        """
+        self._file = chart_file
+        self._height = height
+        self._distance = distance
+        self._scale_start = scale_start
+        self._scale_stop = scale_stop
+        self._scale_step = scale_step
+
+    def _calc_scale_factors(self, cam, props, fmt, s, e, fd):
+        """Take an image with s, e, & fd to find the chart location.
+
+        Args:
+            cam:            An open device session.
+            props:          Properties of cam
+            fmt:            Image format for the capture
+            s:              Sensitivity for the AF request as defined in
+                            android.sensor.sensitivity
+            e:              Exposure time for the AF request as defined in
+                            android.sensor.exposureTime
+            fd:             float; autofocus lens position
+        Returns:
+            template:       numpy array; chart template for locator
+            img_3a:         numpy array; RGB image for chart location
+            scale_factor:   float; scaling factor for chart search
+        """
+        req = its.objects.manual_capture_request(s, e)
+        req['android.lens.focusDistance'] = fd
+        cap_chart = its.image.stationary_lens_cap(cam, req, fmt)
+        img_3a = its.image.convert_capture_to_rgb_image(cap_chart, props)
+        img_3a = its.image.flip_mirror_img_per_argv(img_3a)
+        its.image.write_image(img_3a, 'af_scene.jpg')
+        template = cv2.imread(self._file, cv2.IMREAD_ANYDEPTH)
+        focal_l = cap_chart['metadata']['android.lens.focalLength']
+        pixel_pitch = (props['android.sensor.info.physicalSize']['height'] /
+                       img_3a.shape[0])
+        print ' Chart distance: %.2fcm' % self._distance
+        print ' Chart height: %.2fcm' % self._height
+        print ' Focal length: %.2fmm' % focal_l
+        print ' Pixel pitch: %.2fum' % (pixel_pitch*1E3)
+        print ' Template height: %dpixels' % template.shape[0]
+        chart_pixel_h = self._height * focal_l / (self._distance * pixel_pitch)
+        scale_factor = template.shape[0] / chart_pixel_h
+        print 'Chart/image scale factor = %.2f' % scale_factor
+        return template, img_3a, scale_factor
+
+    def locate(self, cam, props, fmt, s, e, fd):
+        """Find the chart in the image.
+
+        Args:
+            cam:            An open device session
+            props:          Properties of cam
+            fmt:            Image format for the capture
+            s:              Sensitivity for the AF request as defined in
+                            android.sensor.sensitivity
+            e:              Exposure time for the AF request as defined in
+                            android.sensor.exposureTime
+            fd:             float; autofocus lens position
+
+        Returns:
+            xnorm:          float; [0, 1] left loc of chart in scene
+            ynorm:          float; [0, 1] top loc of chart in scene
+            wnorm:          float; [0, 1] width of chart in scene
+            hnorm:          float; [0, 1] height of chart in scene
+        """
+        chart, scene, s_factor = self._calc_scale_factors(cam, props, fmt,
+                                                          s, e, fd)
+        scale_start = self._scale_start * s_factor
+        scale_stop = self._scale_stop * s_factor
+        scale_step = self._scale_step * s_factor
+        max_match = []
+        # check for normalized image
+        if numpy.amax(scene) <= 1.0:
+            scene = (scene * 255.0).astype(numpy.uint8)
+        if len(scene.shape) == 2:
+            scene_gray = scene.copy()
+        elif len(scene.shape) == 3:
+            if scene.shape[2] == 1:
+                scene_gray = scene[:, :, 0]
+            else:
+                scene_gray = cv2.cvtColor(scene.copy(), cv2.COLOR_RGB2GRAY)
+        print 'Finding chart in scene...'
+        for scale in numpy.arange(scale_start, scale_stop, scale_step):
+            scene_scaled = scale_img(scene_gray, scale)
+            result = cv2.matchTemplate(scene_scaled, chart, cv2.TM_CCOEFF)
+            _, opt_val, _, top_left_scaled = cv2.minMaxLoc(result)
+            # print out scale and match
+            print ' scale factor: %.3f, opt 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))
+        wnorm = float((bottom_right[0]) - top_left[0]) / scene.shape[1]
+        hnorm = float((bottom_right[1]) - top_left[1]) / scene.shape[0]
+        xnorm = float(top_left[0]) / scene.shape[1]
+        ynorm = float(top_left[1]) / scene.shape[0]
+        return xnorm, ynorm, wnorm, hnorm
+
+
+class __UnitTest(unittest.TestCase):
+    """Run a suite of unit tests on this module.
+    """
+
+    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 *
+                    its.image.compute_image_sharpness(blur / white_level))
+        self.assertTrue(numpy.isclose(sharpness[2]/sharpness[4],
+                                      numpy.sqrt(2), atol=0.1))
+        self.assertTrue(numpy.isclose(sharpness[4]/sharpness[8],
+                                      numpy.sqrt(2), atol=0.1))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index 0057eb7..60a2173 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -16,15 +16,16 @@
 matplotlib.use('Agg')
 
 import its.error
-import pylab
+from matplotlib import pylab
 import sys
-import Image
+from PIL import Image
 import numpy
 import math
 import unittest
 import cStringIO
 import scipy.stats
 import copy
+import os
 
 DEFAULT_YUV_TO_RGB_CCM = numpy.matrix([
                                 [1.000,  0.000,  1.402],
@@ -43,6 +44,10 @@
 
 MAX_LUT_SIZE = 65536
 
+NUM_TRYS = 2
+NUM_FRAMES = 4
+
+
 def convert_capture_to_rgb_image(cap,
                                  ccm_yuv_to_rgb=DEFAULT_YUV_TO_RGB_CCM,
                                  yuv_off=DEFAULT_YUV_OFFSETS,
@@ -403,8 +408,9 @@
     Returns:
         The black level value for the specified channel.
     """
-    if cap_res.has_key("android.sensor.dynamicBlackLevel"):
-        black_levels = cap_res["android.sensor.dynamicBlackLevel"]
+    if (cap_res.has_key('android.sensor.dynamicBlackLevel') and
+            cap_res['android.sensor.dynamicBlackLevel'] is not None):
+        black_levels = cap_res['android.sensor.dynamicBlackLevel']
     else:
         black_levels = props['android.sensor.blackLevelPattern']
     idxs = its.image.get_canonical_cfa_order(props)
@@ -720,6 +726,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 +739,63 @@
     """
     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 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 - numpy.amin(img))/(numpy.amax(img) - numpy.amin(img))
+
+def flip_mirror_img_per_argv(img):
+    """Flip/mirror an image if "flip" or "mirror" is in argv
+
+    Args:
+        img: 2-D numpy array of image values
+    Returns:
+        Flip/mirrored image
+    """
+    img_out = img
+    if "flip" in sys.argv:
+        img_out = np.flipud(img_out)
+    if "mirror" in sys.argv:
+        img_out = np.fliplr(img_out)
+    return img_out
+
+def stationary_lens_cap(cam, req, fmt):
+    """Take up to NUM_TRYS caps and save the 1st one with lens stationary.
+
+    Args:
+        cam:    open device session
+        req:    capture request
+        fmt:    format for capture
+
+    Returns:
+        capture
+    """
+    trys = 0
+    done = False
+    reqs = [req] * NUM_FRAMES
+    while not done:
+        print 'Waiting for lens to move to correct location...'
+        cap = cam.do_capture(reqs, fmt)
+        done = (cap[NUM_FRAMES-1]['metadata']['android.lens.state'] == 0)
+        print ' status: ', done
+        trys += 1
+        if trys == NUM_TRYS:
+            raise its.error.Error('Cannot settle lens after %d trys!' % trys)
+    return cap[NUM_FRAMES-1]
+
 class __UnitTest(unittest.TestCase):
     """Run a suite of unit tests on this module.
     """
@@ -755,7 +812,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 +820,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:
@@ -779,4 +836,3 @@
 
 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/dng_noise_model/dng_noise_model.py b/apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
index e86ebd2..ff8e4b8 100644
--- a/apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
+++ b/apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
@@ -17,11 +17,10 @@
 import its.objects
 import its.image
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot as plt
 import math
-import Image
 import time
 import numpy as np
 import scipy.stats
@@ -155,7 +154,7 @@
                         np.var(tile(hp, tile_size), axis=(0, 1)).flatten()
 
                     for (mean, var) in zip(means_tiled, vars_tiled):
-                        # Don't include the tile if it has samples that might 
+                        # Don't include the tile if it has samples that might
                         # be clipped.
                         if mean + 2*math.sqrt(var) < max_signal_level:
                             samples_e.append([mean, var])
@@ -173,7 +172,7 @@
             samples.extend([(round(s), mean, var) for (mean, var) in samples_s])
 
             # Add the linear fit to the plot for this sensitivity.
-            plt_s.plot([0, max_signal_level], [O, O + S*max_signal_level], 'r-', 
+            plt_s.plot([0, max_signal_level], [O, O + S*max_signal_level], 'r-',
                        label="Linear fit")
             xmax = max([x for (x, _) in samples_s])*1.25
             plt_s.set_xlim(xmin=0, xmax=xmax)
@@ -217,7 +216,7 @@
 
         [A, B, C, D], _, _, _ = np.linalg.lstsq(a, b)
 
-        # Plot the noise model components with the values predicted by the 
+        # Plot the noise model components with the values predicted by the
         # noise model.
         S_model = A*sens + B
         O_model = \
@@ -226,14 +225,14 @@
         (fig, (plt_S, plt_O)) = plt.subplots(2, 1)
         plt_S.set_title("Noise model")
         plt_S.set_ylabel("S")
-        plt_S.loglog(sens, S_measured, 'r+', basex=10, basey=10, 
+        plt_S.loglog(sens, S_measured, 'r+', basex=10, basey=10,
                      label="Measured")
         plt_S.loglog(sens, S_model, 'bx', basex=10, basey=10, label="Model")
         plt_S.legend(loc=2)
 
         plt_O.set_xlabel("ISO")
         plt_O.set_ylabel("O")
-        plt_O.loglog(sens, O_measured, 'r+', basex=10, basey=10, 
+        plt_O.loglog(sens, O_measured, 'r+', basex=10, basey=10,
                      label="Measured")
         plt_O.loglog(sens, O_model, 'bx', basex=10, basey=10, label="Model")
         fig.savefig("%s.png" % (NAME))
@@ -244,7 +243,7 @@
             dg = max(s/sens_max_analog, 1)
             S = A*s + B
             O = C*s*s + D*dg*dg
-            plt_s.plot([0, max_signal_level], [O, O + S*max_signal_level], 'b-', 
+            plt_s.plot([0, max_signal_level], [O, O + S*max_signal_level], 'b-',
                        label="Model")
             plt_s.legend(loc=2)
 
diff --git a/apps/CameraITS/tests/inprog/test_black_level.py b/apps/CameraITS/tests/inprog/test_black_level.py
index 37dab94..e4038de 100644
--- a/apps/CameraITS/tests/inprog/test_black_level.py
+++ b/apps/CameraITS/tests/inprog/test_black_level.py
@@ -15,7 +15,7 @@
 import its.image
 import its.device
 import its.objects
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/inprog/test_blc_lsc.py b/apps/CameraITS/tests/inprog/test_blc_lsc.py
index ce120a2..32c0c49 100644
--- a/apps/CameraITS/tests/inprog/test_blc_lsc.py
+++ b/apps/CameraITS/tests/inprog/test_blc_lsc.py
@@ -15,7 +15,7 @@
 import its.image
 import its.device
 import its.objects
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
index fa37174..6215dc7 100644
--- a/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
+++ b/apps/CameraITS/tests/inprog/test_burst_sameness_fullres_auto.py
@@ -18,7 +18,7 @@
 import its.caps
 import os.path
 import numpy
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/inprog/test_param_black_level_lock.py b/apps/CameraITS/tests/inprog/test_param_black_level_lock.py
index 7d0be92..f76406d 100644
--- a/apps/CameraITS/tests/inprog/test_param_black_level_lock.py
+++ b/apps/CameraITS/tests/inprog/test_param_black_level_lock.py
@@ -15,7 +15,7 @@
 import its.image
 import its.device
 import its.objects
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/inprog/test_param_edge_mode.py b/apps/CameraITS/tests/inprog/test_param_edge_mode.py
index e928f21..3245b4b 100644
--- a/apps/CameraITS/tests/inprog/test_param_edge_mode.py
+++ b/apps/CameraITS/tests/inprog/test_param_edge_mode.py
@@ -15,7 +15,7 @@
 import its.image
 import its.device
 import its.objects
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene0/test_burst_capture.py b/apps/CameraITS/tests/scene0/test_burst_capture.py
new file mode 100644
index 0000000..e6ee100
--- /dev/null
+++ b/apps/CameraITS/tests/scene0/test_burst_capture.py
@@ -0,0 +1,40 @@
+# 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 its.image
+import its.device
+import its.objects
+import os.path
+
+def main():
+    """Test capture a burst of full size images is fast enough to not timeout.
+       This test verify that entire capture pipeline can keep up the speed
+       of fullsize capture + CPU read for at least some time.
+    """
+    NAME = os.path.basename(__file__).split(".")[0]
+    NUM_TEST_FRAMES = 20
+
+    with its.device.ItsSession() as cam:
+        props = cam.get_camera_properties()
+        req = its.objects.auto_capture_request()
+        caps = cam.do_capture([req]*NUM_TEST_FRAMES)
+
+        cap = caps[0]
+        img = its.image.convert_capture_to_rgb_image(cap, props=props)
+        img_name = "%s.jpg" % (NAME)
+        its.image.write_image(img, img_name)
+
+if __name__ == '__main__':
+    main()
+
diff --git a/apps/CameraITS/tests/scene0/test_gyro_bias.py b/apps/CameraITS/tests/scene0/test_gyro_bias.py
index 7ea90c3..86445fe 100644
--- a/apps/CameraITS/tests/scene0/test_gyro_bias.py
+++ b/apps/CameraITS/tests/scene0/test_gyro_bias.py
@@ -18,7 +18,7 @@
 import its.objects
 import its.target
 import time
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene0/test_jitter.py b/apps/CameraITS/tests/scene0/test_jitter.py
index c519792..6a156dd 100644
--- a/apps/CameraITS/tests/scene0/test_jitter.py
+++ b/apps/CameraITS/tests/scene0/test_jitter.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene0/test_metadata.py b/apps/CameraITS/tests/scene0/test_metadata.py
index e5fbba5..69ed19d 100644
--- a/apps/CameraITS/tests/scene0/test_metadata.py
+++ b/apps/CameraITS/tests/scene0/test_metadata.py
@@ -49,7 +49,6 @@
     check('props.has_key("android.info.supportedHardwareLevel")')
     check('props["android.info.supportedHardwareLevel"] is not None')
     check('props["android.info.supportedHardwareLevel"] in [0,1,2,3]')
-    full = getval('props["android.info.supportedHardwareLevel"]') == 1
     manual_sensor = its.caps.manual_sensor(props)
 
     # Test: rollingShutterSkew, and frameDuration tags must all be present,
@@ -75,7 +74,12 @@
     check('props["android.scaler.croppingType"] is not None')
     check('props["android.scaler.croppingType"] in [0,1]')
 
-    assert(not failed)
+    # Test: android.sensor.blackLevelPattern exists for RAW and is not None
+    if its.caps.raw(props):
+        check('props.has_key("android.sensor.blackLevelPattern")')
+        check('props["android.sensor.blackLevelPattern"] is not None')
+
+    assert not failed
 
     if not its.caps.legacy(props):
         # Test: pixel_pitch, FOV, and hyperfocal distance are reasonable
diff --git a/apps/CameraITS/tests/scene1/test_black_white.py b/apps/CameraITS/tests/scene1/test_black_white.py
index 68d7de6..d4895dc 100644
--- a/apps/CameraITS/tests/scene1/test_black_white.py
+++ b/apps/CameraITS/tests/scene1/test_black_white.py
@@ -16,7 +16,7 @@
 import its.caps
 import its.device
 import its.objects
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_dng_noise_model.py b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
index b7ba0e8..02bce79 100644
--- a/apps/CameraITS/tests/scene1/test_dng_noise_model.py
+++ b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
@@ -17,7 +17,7 @@
 import its.objects
 import its.image
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene1/test_ev_compensation_advanced.py b/apps/CameraITS/tests/scene1/test_ev_compensation_advanced.py
index c14f5a9..9892d64 100644
--- a/apps/CameraITS/tests/scene1/test_ev_compensation_advanced.py
+++ b/apps/CameraITS/tests/scene1/test_ev_compensation_advanced.py
@@ -17,7 +17,7 @@
 import its.caps
 import its.objects
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 import numpy
diff --git a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
index cb69607..815ef20 100644
--- a/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1/test_ev_compensation_basic.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 import numpy as np
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index e53af21..38e5738 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import its.target
-import pylab
+from matplotlib import pylab
 import numpy
 import os.path
 import matplotlib
diff --git a/apps/CameraITS/tests/scene1/test_latching.py b/apps/CameraITS/tests/scene1/test_latching.py
index 6e42c23..79f0f1a 100644
--- a/apps/CameraITS/tests/scene1/test_latching.py
+++ b/apps/CameraITS/tests/scene1/test_latching.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import its.target
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_linearity.py b/apps/CameraITS/tests/scene1/test_linearity.py
index 2176f5e..0557998 100644
--- a/apps/CameraITS/tests/scene1/test_linearity.py
+++ b/apps/CameraITS/tests/scene1/test_linearity.py
@@ -19,7 +19,7 @@
 import its.target
 import numpy
 import math
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_locked_burst.py b/apps/CameraITS/tests/scene1/test_locked_burst.py
index daefb6b..96c5e1a 100644
--- a/apps/CameraITS/tests/scene1/test_locked_burst.py
+++ b/apps/CameraITS/tests/scene1/test_locked_burst.py
@@ -18,7 +18,7 @@
 import its.caps
 import os.path
 import numpy
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene1/test_param_color_correction.py b/apps/CameraITS/tests/scene1/test_param_color_correction.py
index 8623426..db7d569 100644
--- a/apps/CameraITS/tests/scene1/test_param_color_correction.py
+++ b/apps/CameraITS/tests/scene1/test_param_color_correction.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import its.target
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_param_exposure_time.py b/apps/CameraITS/tests/scene1/test_param_exposure_time.py
index 576516c..b2f2a11 100644
--- a/apps/CameraITS/tests/scene1/test_param_exposure_time.py
+++ b/apps/CameraITS/tests/scene1/test_param_exposure_time.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import its.target
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index 1072684..80fbaa8 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -21,7 +21,7 @@
 import matplotlib.pyplot
 import numpy
 import os.path
-import pylab
+from matplotlib import pylab
 
 def main():
     """Test that the android.noiseReduction.mode param is applied when set.
diff --git a/apps/CameraITS/tests/scene1/test_param_sensitivity.py b/apps/CameraITS/tests/scene1/test_param_sensitivity.py
index d6b44a2..9279ada 100644
--- a/apps/CameraITS/tests/scene1/test_param_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_param_sensitivity.py
@@ -17,7 +17,7 @@
 import its.device
 import its.objects
 import its.target
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tests/scene1/test_param_shading_mode.py b/apps/CameraITS/tests/scene1/test_param_shading_mode.py
index c945791..f4c2b99 100644
--- a/apps/CameraITS/tests/scene1/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1/test_param_shading_mode.py
@@ -20,7 +20,7 @@
 import numpy
 import os
 import os.path
-import pylab
+from matplotlib import pylab
 
 def main():
     """Test that the android.shading.mode param is applied.
diff --git a/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py b/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
index 61b431c..70b1927 100644
--- a/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
+++ b/apps/CameraITS/tests/scene1/test_post_raw_sensitivity_boost.py
@@ -18,7 +18,7 @@
 import its.objects
 import its.target
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
index 1d2a6b1..7fff4ae 100644
--- a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
@@ -17,7 +17,7 @@
 import its.objects
 import its.image
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
index e49ee34..c443aba 100644
--- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
@@ -17,7 +17,7 @@
 import its.objects
 import its.image
 import os.path
-import pylab
+from matplotlib import pylab
 import matplotlib
 import matplotlib.pyplot
 
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index f0a6fbe..cb0ad9f 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -22,7 +22,7 @@
 import matplotlib.pyplot
 import numpy
 import os.path
-import pylab
+from matplotlib import pylab
 
 def main():
     """Test that the android.noiseReduction.mode param is applied when set for
diff --git a/apps/CameraITS/tests/scene2/test_faces.py b/apps/CameraITS/tests/scene2/test_faces.py
index ba4f317..8a3a403 100644
--- a/apps/CameraITS/tests/scene2/test_faces.py
+++ b/apps/CameraITS/tests/scene2/test_faces.py
@@ -25,6 +25,7 @@
     FD_MODE_OFF = 0
     FD_MODE_SIMPLE = 1
     FD_MODE_FULL = 2
+    W, H = 640, 480
 
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
@@ -42,14 +43,12 @@
             assert(FD_MODE_OFF <= fd_mode <= FD_MODE_FULL)
             req = its.objects.auto_capture_request()
             req['android.statistics.faceDetectMode'] = fd_mode
-            caps = cam.do_capture([req]*NUM_TEST_FRAMES)
+            fmt = {"format":"yuv", "width":W, "height":H}
+            caps = cam.do_capture([req]*NUM_TEST_FRAMES, fmt)
             for i,cap in enumerate(caps):
                 md = cap['metadata']
                 assert(md['android.statistics.faceDetectMode'] == fd_mode)
                 faces = md['android.statistics.faces']
-                img = its.image.convert_capture_to_rgb_image(cap, props=props)
-                img_name = "%s_fd_mode_%s.jpg" % (NAME, fd_mode)
-                its.image.write_image(img, img_name)
 
                 # 0 faces should be returned for OFF mode
                 if fd_mode == FD_MODE_OFF:
@@ -58,6 +57,10 @@
                 # Face detection could take several frames to warm up,
                 # but it should detect at least one face in last frame
                 if i == NUM_TEST_FRAMES - 1:
+                    img = its.image.convert_capture_to_rgb_image(cap, props=props)
+                    img = its.image.flip_mirror_img_per_argv(img)
+                    img_name = "%s_fd_mode_%s.jpg" % (NAME, fd_mode)
+                    its.image.write_image(img, img_name)
                     if len(faces) == 0:
                         print "Error: no face detected in mode", fd_mode
                         assert(0)
diff --git a/apps/CameraITS/tests/scene3/test_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
index a2dfdbe..37e1d63 100644
--- a/apps/CameraITS/tests/scene3/test_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
@@ -22,7 +22,7 @@
 import matplotlib.pyplot
 import numpy
 import os.path
-import pylab
+from matplotlib import pylab
 
 
 def test_edge_mode(cam, edge_mode, sensitivity, exp, fd, out_surface):
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..cd563be
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
@@ -0,0 +1,185 @@
+# 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 its.caps
+import its.cv2image
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+NUM_IMGS = 12
+FRAME_TIME_TOL = 10  # ms
+SHARPNESS_TOL = 0.10  # percentage
+POSITION_TOL = 0.10  # percentage
+VGA_WIDTH = 640
+VGA_HEIGHT = 480
+NAME = os.path.basename(__file__).split('.')[0]
+CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+                          'test_images', 'ISO12233.png')
+CHART_HEIGHT = 13.5  # cm
+CHART_DISTANCE = 30.0  # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
+
+
+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'
+    """
+
+    # initialize chart class
+    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+                               CHART_SCALE_START, CHART_SCALE_STOP,
+                               CHART_SCALE_STEP)
+
+    # find chart location
+    xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
+                                              exp, af_fd)
+
+    # initialize variables and take data sets
+    data_set = {}
+    white_level = int(props['android.sensor.info.whiteLevel'])
+    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
+    caps = cam.do_capture(reqs, fmt)
+    for i, cap in enumerate(caps):
+        data = {'fd': fds[i]}
+        data['loc'] = cap['metadata']['android.lens.focusDistance']
+        data['lens_moving'] = (cap['metadata']['android.lens.state']
+                               == 1)
+        timestamp = cap['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, props)
+        y = its.image.flip_mirror_img_per_argv(y)
+        chart = its.image.normalize_img(its.image.get_image_patch(y,
+                                                                  xnorm, ynorm,
+                                                                  wnorm, hnorm))
+        its.image.write_image(chart, '%s_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        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)
+        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/tests/scene3/test_lens_position.py b/apps/CameraITS/tests/scene3/test_lens_position.py
new file mode 100644
index 0000000..f850e3d
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/test_lens_position.py
@@ -0,0 +1,200 @@
+# 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 its.caps
+import its.cv2image
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+NUM_TRYS = 2
+NUM_STEPS = 6
+SHARPNESS_TOL = 10  # percentage
+POSITION_TOL = 10  # percentage
+FRAME_TIME_TOL = 10  # ms
+VGA_WIDTH = 640
+VGA_HEIGHT = 480
+NAME = os.path.basename(__file__).split('.')[0]
+CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+                          'test_images', 'ISO12233.png')
+CHART_HEIGHT = 13.5  # cm
+CHART_DISTANCE = 30.0  # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
+
+
+def test_lens_position(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:
+        Dictionary of results for different focal distance captures
+        with static lens positions and moving lens positions
+        d_static, d_moving
+    """
+
+    # initialize chart class
+    chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+                                CHART_SCALE_START, CHART_SCALE_STOP,
+                                CHART_SCALE_STEP)
+
+    # find chart location
+    xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
+                                              exp, af_fd)
+
+    # initialize variables and take data sets
+    data_static = {}
+    data_moving = {}
+    white_level = int(props['android.sensor.info.whiteLevel'])
+    min_fd = props['android.lens.info.minimumFocusDistance']
+    hyperfocal = props['android.lens.info.hyperfocalDistance']
+    fds_f = np.arange(hyperfocal, min_fd, (min_fd-hyperfocal)/(NUM_STEPS-1))
+    fds_f = np.append(fds_f, min_fd)
+    fds_f = fds_f.tolist()
+    fds_b = list(reversed(fds_f))
+    fds_fb = list(fds_f)
+    fds_fb.extend(fds_b)  # forward and back
+    # take static data set
+    for i, fd in enumerate(fds_fb):
+        req = its.objects.manual_capture_request(sensitivity, exp)
+        req['android.lens.focusDistance'] = fd
+        cap = its.image.stationary_lens_cap(cam, req, fmt)
+        data = {'fd': fds_fb[i]}
+        data['loc'] = cap['metadata']['android.lens.focusDistance']
+        print ' focus distance (diopters): %.3f' % data['fd']
+        print ' current lens location (diopters): %.3f' % data['loc']
+        y, _, _ = its.image.convert_capture_to_planes(cap, props)
+        chart = its.image.normalize_img(its.image.get_image_patch(y,
+                                                                  xnorm, ynorm,
+                                                                  wnorm, hnorm))
+        its.image.write_image(chart, '%s_stat_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        print 'Chart sharpness: %.1f\n' % data['sharpness']
+        data_static[i] = data
+    # take moving data set
+    reqs = []
+    for i, fd in enumerate(fds_f):
+        reqs.append(its.objects.manual_capture_request(sensitivity, exp))
+        reqs[i]['android.lens.focusDistance'] = fd
+    caps = cam.do_capture(reqs, fmt)
+    for i, cap in enumerate(caps):
+        data = {'fd': fds_f[i]}
+        data['loc'] = cap['metadata']['android.lens.focusDistance']
+        data['lens_moving'] = (cap['metadata']['android.lens.state']
+                               == 1)
+        timestamp = cap['metadata']['android.sensor.timestamp'] * 1E-6
+        if i == 0:
+            timestamp_init = timestamp
+        timestamp -= timestamp_init
+        data['timestamp'] = timestamp
+        print ' focus distance (diopters): %.3f' % data['fd']
+        print ' current lens location (diopters): %.3f' % data['loc']
+        y, _, _ = its.image.convert_capture_to_planes(cap, props)
+        y = its.image.flip_mirror_img_per_argv(y)
+        chart = its.image.normalize_img(its.image.get_image_patch(y,
+                                                                  xnorm, ynorm,
+                                                                  wnorm, hnorm))
+        its.image.write_image(chart, '%s_move_i=%d_chart.jpg' % (NAME, i))
+        data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+        print 'Chart sharpness: %.1f\n' % data['sharpness']
+        data_moving[i] = data
+    return data_static, data_moving
+
+
+def main():
+    """Test if focus position is properly reported for moving lenses."""
+
+    print '\nStarting test_lens_position.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_calibrated(props))
+        fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
+
+        # Get proper sensitivity, exposure time, and focus distance with 3A.
+        s, e, _, _, fd = cam.do_3a(get_results=True)
+
+        # Get sharpness for each focal distance
+        d_stat, d_move = test_lens_position(cam, props, fmt, s, e, fd)
+        print 'Lens stationary'
+        for k in sorted(d_stat):
+            print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
+                   'sharpness: %.1f' % (k, d_stat[k]['fd'],
+                                        d_stat[k]['loc'],
+                                        d_stat[k]['sharpness']))
+        print 'Lens moving'
+        for k in sorted(d_move):
+            print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
+                   'sharpness: %.1f  \tlens_moving: %r \t'
+                   'timestamp: %.1fms' % (k, d_move[k]['fd'],
+                                          d_move[k]['loc'],
+                                          d_move[k]['sharpness'],
+                                          d_move[k]['lens_moving'],
+                                          d_move[k]['timestamp']))
+
+        # assert static reported location/sharpness is close
+        print 'Asserting static lens locations/sharpness are similar'
+        for i in range(len(d_stat)/2):
+            j = 2 * NUM_STEPS - 1 - i
+            print (' lens position: %.3f'
+                   % d_stat[i]['fd'])
+            assert np.isclose(d_stat[i]['loc'], d_stat[i]['fd'],
+                              rtol=POSITION_TOL/100.0)
+            assert np.isclose(d_stat[i]['loc'], d_stat[j]['loc'],
+                              rtol=POSITION_TOL/100.0)
+            assert np.isclose(d_stat[i]['sharpness'], d_stat[j]['sharpness'],
+                              rtol=SHARPNESS_TOL/100.0)
+        # assert moving frames approximately consecutive with even distribution
+        print 'Asserting moving frames are consecutive'
+        times = [v['timestamp'] for v in d_move.itervalues()]
+        diffs = np.gradient(times)
+        assert np.isclose(np.amin(diffs), np.amax(diffs), atol=FRAME_TIME_TOL)
+        # assert reported location/sharpness is correct in moving frames
+        print 'Asserting moving lens locations/sharpness are similar'
+        for i in range(len(d_move)):
+            print ' lens position: %.3f' % d_stat[i]['fd']
+            assert np.isclose(d_stat[i]['loc'], d_move[i]['loc'],
+                              rtol=POSITION_TOL)
+            if d_move[i]['lens_moving'] and i > 0:
+                if d_stat[i]['sharpness'] > d_stat[i-1]['sharpness']:
+                    assert (d_stat[i]['sharpness']*(1.0+SHARPNESS_TOL) >
+                            d_move[i]['sharpness'] >
+                            d_stat[i-1]['sharpness']*(1.0-SHARPNESS_TOL))
+                else:
+                    assert (d_stat[i-1]['sharpness']*(1.0+SHARPNESS_TOL) >
+                            d_move[i]['sharpness'] >
+                            d_stat[i]['sharpness']*(1.0-SHARPNESS_TOL))
+            elif not d_move[i]['lens_moving']:
+                assert np.isclose(d_stat[i]['sharpness'],
+                                  d_move[i]['sharpness'], rtol=SHARPNESS_TOL)
+            else:
+                raise its.error.Error('Lens is moving at frame 0!')
+
+if __name__ == '__main__':
+    main()
+
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index 3bd4b34..95fc636 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -22,7 +22,7 @@
 import matplotlib.pyplot
 import numpy
 import os.path
-import pylab
+from matplotlib import pylab
 
 
 def test_edge_mode(cam, edge_mode, sensitivity, exp, fd, out_surface,
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 288d6e4..b6e9673 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -18,12 +18,12 @@
 import its.caps
 import time
 import math
-import pylab
+from matplotlib import pylab
 import os.path
 import matplotlib
 import matplotlib.pyplot
 import json
-import Image
+from PIL import Image
 import numpy
 import cv2
 import bisect
diff --git a/apps/CameraITS/tests/tutorial.py b/apps/CameraITS/tests/tutorial.py
index c266d14..1fca5f1 100644
--- a/apps/CameraITS/tests/tutorial.py
+++ b/apps/CameraITS/tests/tutorial.py
@@ -34,7 +34,7 @@
 
 # Modules from the numpy, scipy, and matplotlib libraries. These are used for
 # the image processing code, and images are represented as numpy arrays.
-import pylab
+from matplotlib import pylab
 import numpy
 import matplotlib
 import matplotlib.pyplot
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index c6ff548..03bf268 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -70,7 +70,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",
@@ -287,6 +287,12 @@
                                       'turn_off_screen.py'), screen_id_arg]
         retcode = subprocess.call(cmd)
         assert retcode == 0
+        print 'Shutting down DUT screen: ', device_id
+        screen_id_arg = ('screen=%s' % device_id)
+        cmd = ['python', os.path.join(os.environ['CAMERA_ITS_TOP'], 'tools',
+                                      'turn_off_screen.py'), screen_id_arg]
+        retcode = subprocess.call(cmd)
+        assert retcode == 0
 
     print "ITS tests finished. Please go back to CtsVerifier and proceed"
 
diff --git a/apps/CameraITS/tools/turn_off_screen.py b/apps/CameraITS/tools/turn_off_screen.py
index 4163ab4..207042b 100644
--- a/apps/CameraITS/tools/turn_off_screen.py
+++ b/apps/CameraITS/tools/turn_off_screen.py
@@ -33,10 +33,10 @@
     process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
     cmd_ret = process.stdout.read()
     screen_state = re.split(r'[s|=]', cmd_ret)[-1]
-    if screen_state == 'OFF\n':
-        print 'Screen OFF. Turning ON.'
+    if 'OFF' in screen_state:
+        print 'Screen already OFF.'
     else:
-        wakeup = ('adb -s %s shell input keyevent POWER' % screen_id)
-        subprocess.Popen(wakeup.split())
+        pwrdn = ('adb -s %s shell input keyevent POWER' % screen_id)
+        subprocess.Popen(pwrdn.split())
 if __name__ == '__main__':
     main()
diff --git a/apps/CameraITS/tools/wake_up_screen.py b/apps/CameraITS/tools/wake_up_screen.py
index 68a974a..a43126a 100644
--- a/apps/CameraITS/tools/wake_up_screen.py
+++ b/apps/CameraITS/tools/wake_up_screen.py
@@ -18,8 +18,8 @@
 import time
 
 DISPLAY_LEVEL = 96  # [0:255] Depends on tablet model. Adjust for best result.
-DISPLAY_WAIT = 0.5  # seconds. Screen commands take time to have effect
-
+DISPLAY_CMD_WAIT = 0.5  # seconds. Screen commands take time to have effect
+DISPLAY_TIMEOUT = 1800000  # ms
 
 def main():
     """Power up and unlock screen as needed."""
@@ -42,19 +42,24 @@
         print 'Screen OFF. Turning ON.'
         wakeup = ('adb -s %s shell input keyevent POWER' % screen_id)
         subprocess.Popen(wakeup.split())
-        time.sleep(DISPLAY_WAIT)
+        time.sleep(DISPLAY_CMD_WAIT)
     unlock = ('adb -s %s wait-for-device shell wm dismiss-keyguard'
               % screen_id)
     subprocess.Popen(unlock.split())
-    time.sleep(DISPLAY_WAIT)
+    time.sleep(DISPLAY_CMD_WAIT)
 
     # set brightness
     print 'Tablet display brightness set to %d' % DISPLAY_LEVEL
     bright = ('adb -s %s shell settings put system screen_brightness %d'
               % (screen_id, DISPLAY_LEVEL))
     subprocess.Popen(bright.split())
-    time.sleep(DISPLAY_WAIT)
+    time.sleep(DISPLAY_CMD_WAIT)
 
+    # set screen to dim at max time (30min)
+    stay_bright = ('adb -s %s shell settings put system screen_off_timeout %d' %
+                   (screen_id, DISPLAY_TIMEOUT))
+    subprocess.Popen(stay_bright.split())
+    time.sleep(DISPLAY_CMD_WAIT)
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 364d336..0d56341 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -26,6 +26,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 \
+                               android-support-v4 \
                                compatibility-common-util-devicesidelib \
                                cts-sensors-tests \
                                cts-location-tests \
@@ -35,7 +36,7 @@
                                ctsverifier-opencv \
                                core-tests-support \
                                android-support-v4  \
-                               mockito-target \
+                               mockito-target-minus-junit4 \
                                mockwebserver \
                                compatibility-device-util \
 
@@ -90,6 +91,7 @@
 
 notification-bot := $(call intermediates-dir-for,APPS,NotificationBot)/package.apk
 permission-app := $(call intermediates-dir-for,APPS,CtsPermissionApp)/package.apk
+usb-companion := $(call intermediates-dir-for,APPS,CtsVerifierUSBCompanion)/package.apk
 
 # Builds and launches CTS Verifier on a device.
 .PHONY: cts-verifier
@@ -128,20 +130,15 @@
 #	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
 
 cts : $(verifier-zip)
-ifeq ($(HOST_OS),linux)
-$(verifier-zip) : $(HOST_OUT)/bin/cts-usb-accessory
-endif
 $(verifier-zip) : $(HOST_OUT)/CameraITS
 $(verifier-zip) : $(notification-bot)
 $(verifier-zip) : $(permission-app)
+$(verifier-zip) : $(usb-companion)
 $(verifier-zip) : $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk | $(ACP)
 		$(hide) mkdir -p $(verifier-dir)
 		$(hide) $(ACP) -fp $< $(verifier-dir)/CtsVerifier.apk
 		$(ACP) -fp $(notification-bot) $(verifier-dir)/NotificationBot.apk
 		$(ACP) -fp $(permission-app) $(verifier-dir)/CtsPermissionApp.apk
-ifeq ($(HOST_OS),linux)
-		$(hide) $(ACP) -fp $(HOST_OUT)/bin/cts-usb-accessory $(verifier-dir)/cts-usb-accessory
-endif
 		$(hide) $(ACP) -fpr $(HOST_OUT)/CameraITS $(verifier-dir)
 		$(hide) cd $(cts-dir) && zip -rq $(verifier-dir-name) $(verifier-dir-name)
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 3d7584b..3fa7fe6 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -918,7 +918,6 @@
                 android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
         </activity>
 
-
         <activity android:name=".security.FingerprintBoundKeysTest"
                 android:label="@string/sec_fingerprint_bound_key_test"
                 android:configChanges="keyboardHidden|orientation|screenSize" >
@@ -1693,26 +1692,43 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.camera.flash" />
         </activity>
 
-        <activity android:name=".usb.UsbAccessoryTestActivity"
+        <activity android:name=".usb.accessory.UsbAccessoryTestActivity"
                 android:label="@string/usb_accessory_test"
-                android:configChanges="keyboardHidden|orientation|screenSize"
-                android:launchMode="singleTop">
+                android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
-            </intent-filter>
-            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
-                    android:resource="@xml/accessory_filter" />
             <meta-data android:name="test_category" android:value="@string/test_category_hardware" />
             <meta-data android:name="test_required_features" android:value="android.hardware.usb.accessory" />
             <meta-data android:name="test_excluded_features"
                     android:value="android.hardware.type.watch" />
         </activity>
 
-        <activity android:name=".usb.MtpHostTestActivity" android:label="@string/mtp_host_test">
+        <activity android:name=".usb.accessory.AccessoryAttachmentHandler">
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+            </intent-filter>
+
+            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                android:resource="@xml/accessory_filter" />
+        </activity>
+
+        <activity android:name=".usb.device.UsbDeviceTestActivity"
+                android:label="@string/usb_device_test"
+                android:configChanges="keyboardHidden|orientation|screenSize">
+            <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_hardware" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+        </activity>
+
+        <activity android:name=".usb.mtp.MtpHostTestActivity" android:label="@string/mtp_host_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -1756,6 +1772,15 @@
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
         </activity>
 
+        <activity android:name=".notifications.NotificationAssistantVerifierActivity"
+                  android:label="@string/nas_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_notifications" />
+        </activity>
+
         <activity android:name=".notifications.ConditionProviderVerifierActivity"
                   android:label="@string/cp_test">
             <intent-filter>
@@ -1798,6 +1823,15 @@
             </intent-filter>
         </service>
 
+        <service android:name=".notifications.MockAssistant"
+                 android:exported="true"
+                 android:label="@string/nas_service_name"
+                 android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationAssistantService" />
+            </intent-filter>
+        </service>
+
         <activity android:name=".notifications.ShortcutThrottlingResetActivity"
             android:label="@string/shortcut_reset_test"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
@@ -2108,7 +2142,7 @@
                  android:process=":projectionservice" />
 
         <activity android:name=".managedprovisioning.DeviceOwnerNegativeTestActivity"
-                android:label="@string/provisioning_device_owner">
+                android:label="@string/negative_device_owner">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -2119,6 +2153,14 @@
 
         <activity android:name=".managedprovisioning.DeviceOwnerNegativeTestActivity$TrampolineActivity" />
 
+        <activity android:name=".managedprovisioning.EnterprisePrivacyInfoOnlyTestActivity"
+                android:label="@string/enterprise_privacy_test">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_ENTERPRISE_PRIVACY_INFO_ONLY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".managedprovisioning.DeviceOwnerPositiveTestActivity"
                 android:label="@string/positive_device_owner">
             <intent-filter>
@@ -2214,6 +2256,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".managedprovisioning.EnterprisePrivacyTestListActivity"
+                android:label="@string/enterprise_privacy_test">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_ENTERPRISE_PRIVACY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".managedprovisioning.CommandReceiverActivity"
                 android:theme="@android:style/Theme.NoDisplay"
                 android:noHistory="true">
@@ -2742,6 +2792,21 @@
             </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>
+
         <activity android:name=".voicemail.VoicemailBroadcastActivity"
           android:label="@string/voicemail_broadcast_test">
             <intent-filter>
@@ -2763,7 +2828,6 @@
                 <action android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
             </intent-filter>
         </receiver>
-
     </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 187e8d2..9f7ffcd 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -33,7 +33,7 @@
 -dontwarn android.hardware.Sensor
 -dontwarn android.test.AndroidTestRunner
 -dontwarn java.util.concurrent.ConcurrentLinkedDeque
--dontwarn android.cts.util.**
+-dontwarn com.android.compatibility.common.util.**
 -dontwarn junit.**
 
 # Jack seems less rigorous than proguard when it comes to warning about
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/ic_usb_48.xml b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
new file mode 100644
index 0000000..eebb4fb
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48.0"
+    android:viewportHeight="48.0">
+    <path
+        android:pathData="M30,14v8h2v4h-6V10h4l-6,-8 -6,8h4v16h-6v-4.14c1.41,-0.73 2.4,-2.16 2.4,-3.86 0,-2.43 -1.97,-4.4 -4.4,-4.4 -2.43,0 -4.4,1.97 -4.4,4.4 0,1.7 0.99,3.13 2.4,3.86V26c0,2.21 1.79,4 4,4h6v6.1c-1.42,0.73 -2.4,2.19 -2.4,3.9 0,2.43 1.97,4.4 4.4,4.4 2.43,0 4.4,-1.97 4.4,-4.4 0,-1.71 -0.98,-3.17 -2.4,-3.9V30h6c2.21,0 4,-1.79 4,-4v-4h2v-8h-8z"
+        android:fillColor="#757575"/>
+</vector>
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-land/usb_main.xml b/apps/CtsVerifier/res/layout-land/usb_main.xml
deleted file mode 100644
index 139b54b..0000000
--- a/apps/CtsVerifier/res/layout-land/usb_main.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<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:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            >
-        <LinearLayout android:orientation="vertical"
-                android:layout_width="1px"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                >
-            <TextView android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/usb_sent_messages"
-                    style="?android:attr/listSeparatorTextViewStyle"
-                    />
-            <FrameLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    >
-                <ListView android:id="@+id/usb_sent_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        />
-                <TextView android:id="@+id/usb_empty_sent_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:gravity="center"
-                        android:text="@string/usb_no_messages"
-                        android:visibility="gone"
-                        />
-            </FrameLayout>
-        </LinearLayout>
-        <include layout="@layout/vertical_divider" />
-        <LinearLayout android:orientation="vertical"
-                android:layout_width="1px"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                >
-            <TextView android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/usb_received_messages"
-                    style="?android:attr/listSeparatorTextViewStyle"
-                    />
-            <FrameLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    >
-                <ListView android:id="@+id/usb_received_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        />
-                <TextView android:id="@+id/usb_empty_received_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:gravity="center"
-                        android:text="@string/usb_no_messages"
-                        android:visibility="gone"
-                        />
-            </FrameLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-    <include layout="@layout/pass_fail_buttons" />
-
-</LinearLayout>
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-round/provisioning_byod.xml b/apps/CtsVerifier/res/layout-round/provisioning_byod.xml
deleted file mode 100644
index d2b6e0e..0000000
--- a/apps/CtsVerifier/res/layout-round/provisioning_byod.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/main_layout"
-    style="@style/RootLayoutPadding"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-        <TextView
-            android:id="@+id/test_instructions"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:padding="10dip"/>
-        <Button
-            android:id="@+id/prepare_test_button"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-        <ListView
-            android:id="@+id/android:list"
-            android:layout_width="match_parent"
-            android:layout_height="0dip"
-            android:layout_weight="3"/>
-        <include layout="@layout/pass_fail_buttons"/>
-    </LinearLayout>
-</android.support.v4.widget.NestedScrollView>
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/enterprise_privacy_negative_test.xml b/apps/CtsVerifier/res/layout/enterprise_privacy_negative_test.xml
new file mode 100644
index 0000000..a5c531b
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/enterprise_privacy_negative_test.xml
@@ -0,0 +1,43 @@
+<?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="vertical"
+    style="@style/RootLayoutPadding">
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fillViewport="true">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+
+            <TextView android:id="@+id/info"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textSize="18sp"
+                android:padding="5dp" />
+
+            <include layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+    </ScrollView>
+</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/positive_device_owner.xml b/apps/CtsVerifier/res/layout/positive_device_owner.xml
index fa437de..12425bd 100644
--- a/apps/CtsVerifier/res/layout/positive_device_owner.xml
+++ b/apps/CtsVerifier/res/layout/positive_device_owner.xml
@@ -20,7 +20,8 @@
 
     <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:fillViewport="true">
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -42,7 +43,8 @@
             <ListView
                 android:id="@+id/android:list"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="0dp"
+                android:layout_weight="1" />
 
             <include layout="@layout/pass_fail_buttons" />
         </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/provisioning_byod.xml b/apps/CtsVerifier/res/layout/provisioning_byod.xml
index 227d8d8..fb4093a 100644
--- a/apps/CtsVerifier/res/layout/provisioning_byod.xml
+++ b/apps/CtsVerifier/res/layout/provisioning_byod.xml
@@ -1,37 +1,42 @@
 <?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2011 The Android Open Source Project
+
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
+
           http://www.apache.org/licenses/LICENSE-2.0
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/RootLayoutPadding"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-    <ScrollView
+    android:layout_height="match_parent">
+
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="2">
+        android:layout_height="match_parent"
+        android:orientation="vertical">
         <TextView
             android:id="@+id/test_instructions"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:padding="10dip"
-            android:textSize="18dip"/>
-    </ScrollView>
-    <Button
-        android:id="@+id/prepare_test_button"
-        android:layout_width="204dip"
-        android:layout_height="wrap_content"/>
-    <ListView
-        android:id="@+id/android:list"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="3"/>
-    <include layout="@layout/pass_fail_buttons"/>
-</LinearLayout>
+            android:textSize="18dip" />
+        <Button
+            android:id="@+id/prepare_test_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <ListView
+            android:id="@+id/android:list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <include layout="@layout/pass_fail_buttons" />
+    </LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/usb_main.xml b/apps/CtsVerifier/res/layout/usb_main.xml
index 5c16612..d693ae5 100644
--- a/apps/CtsVerifier/res/layout/usb_main.xml
+++ b/apps/CtsVerifier/res/layout/usb_main.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- 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.
@@ -14,55 +14,40 @@
      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"
-        >
-    <TextView android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/usb_sent_messages"
-            style="?android:attr/listSeparatorTextViewStyle"
-            />
-    <FrameLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            >
-        <ListView android:id="@+id/usb_sent_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                />
-        <TextView android:id="@+id/usb_empty_sent_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:text="@string/usb_no_messages"
-                android:visibility="gone"
-                />
-    </FrameLayout>
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
-    <TextView android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/usb_received_messages"
-            style="?android:attr/listSeparatorTextViewStyle"
-            />
-    <FrameLayout android:orientation="vertical"
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:padding="16dp">
+
+        <ImageView android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:src="@drawable/ic_usb_48"
+            android:tint="@color/primary"
+            android:scaleType="fitCenter"
+            android:layout_marginBottom="16dp" />
+
+        <ProgressBar android:id="@+id/progress_bar"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            >
-        <ListView android:id="@+id/usb_received_messages"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:visibility="gone" />
+
+        <ScrollView android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1">
+
+            <TextView android:id="@+id/status"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                />
-        <TextView android:id="@+id/usb_empty_received_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:text="@string/usb_no_messages"
-                android:visibility="gone"
-                />
-    </FrameLayout>
+                android:layout_height="wrap_content" />
+
+        </ScrollView>
+
+    </LinearLayout>
 
     <include layout="@layout/pass_fail_buttons" />
 
diff --git a/apps/CtsVerifier/res/layout/usb_message_row.xml b/apps/CtsVerifier/res/layout/usb_message_row.xml
deleted file mode 100644
index 3bb228a..0000000
--- a/apps/CtsVerifier/res/layout/usb_message_row.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/MessageRow"
-        />
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 a2da24d..b4f1c9b 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1070,35 +1070,62 @@
 
     <!-- Strings for USB accessory test activity -->
     <string name="usb_accessory_test">USB Accessory Test</string>
-    <string name="sensor_power_test">Sensor Power Test</string>
     <string name="usb_accessory_test_info">
-        1. Connect your Android device to a computer and ensure that the connection is set
-        to charging only from the Android device.
-        \n\n2.Run the \'cts-usb-accessory\' program included with the CTS Verifier bundle.
-        \n\n3. If you have not started the CTS Verifier, press \'OK\' when asked to open the CTS
-        Verifier when the accessory is connected. \n\nIf you are already in this test,
-        then you can press \'Cancel\' but press \'OK\' in the next dialog asking whether to allow
-        CTS Verifier to access the accessory.
-        \n\n4. You should see the accessory and the CTS Verifier display a series of messages
-        which indicates that the accessory support is working properly, and then you will
-        be presented with more instructions.
+        1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n\n2. Start the accessory test companion in the Cts Verifier USB Companion.
+        \n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+        \n\n4. Confirm access to the USB device on the helper device.
+        \n\n5. Confirm access to the USB accessory on this device
+        \n\n6. Confirm access to the USB device on the helper again.
+        \n\n7. Test will run and complete automatically in a less than 30 seconds.
+        \n\n8. Cancel all further dialogs on this device
     </string>
-    <string name="usb_not_available_title">USB accessory feature is not available?</string>
-    <string name="usb_not_available_message">If your device is supposed to support USB accessories, your API implementation is not behaving correctly!</string>
-    <string name="usb_received_messages">Received Messages</string>
-    <string name="usb_reconnect_title">Disconnect and Reconnect</string>
-    <string name="usb_disconnect_message">Please disconnect the Android device and the computer.</string>
-    <string name="usb_connect_message">Please connect the Android device and the computer. Do not interact with the device until prompted.</string>
-    <string name="usb_reconnect_timeout">Test failed because reconnect timed out. You can interact with the device again.</string>
-    <string name="usb_reconnect_abort">Abort Test</string>
-    <string name="usb_wait_for_done">Could not find USB accessory. Try waiting longer.</string>
-    <string name="usb_sent_messages">Sent Messages</string>
-    <string name="usb_no_messages">No messages</string>
-    <string name="usb_message_thread_started">Starting message processing...</string>
-    <string name="usb_message_thread_exception">Exception occurred while processing a message...</string>
-    <string name="usb_message_thread_ended">Stopping message processing...</string>
-    <string name="usb_test_passed">Test passed, pass button enabled! You can interact with the device again.</string>
-    <string name="usb_file_descriptor_error">Could not open file descriptor for USB accessory... try reconnecting and restarting the accessory?</string>
+    <string name="usb_accessory_test_step1">
+        In this specific order:
+        \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n2. Start the accessory test companion in the Cts Verifier USB Companion.
+        \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+        \n4. Confirm access to the USB device on the helper device. Only confirm once.
+        \n5. Confirm access to the USB accessory on this device.
+        \n6. Confirm access to the USB device on the helper device again.
+        \n\nResult: A progress indicator should appear or test will finish.
+    </string>
+    <string name="usb_accessory_test_step2">
+        Test is running and will complete automatically in less than 30 seconds.
+    </string>
+
+    <!-- String for the USB device test activity -->
+    <string name="usb_device_test">USB Device Test</string>
+    <string name="usb_device_test_info">
+        1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n\n2. Start the device test companion in the Cts Verifier USB Companion.
+        \n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
+        \n\n4. Confirm access to the USB device on this device.
+        \n\n5. Confirm access to the USB accessory on the helper device.
+        \n\n6. Confirm access to the USB device on this device again.
+        \n\n7. Test will run and complete automatically in less than 30 seconds.
+        \n\n8. Cancel all further dialogs on the helper device.
+    </string>
+    <string name="usb_device_test_step1">
+        In this specific order:
+        \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n2. Start the device test companion in the Cts Verifier USB Companion.
+        \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
+        \n\nResult: A dialog should show up on this device asking for access to a USB device.
+    </string>
+    <string name="usb_device_test_step2">
+        Confirm access to the USB device on this device.
+        \n\nResult: Dialogs should show up on this device and on the helper device asking for access to a USB device/accessory.
+    </string>
+    <string name="usb_device_test_step3">
+        1. Confirm access to the USB accessory on the helper device.
+        \n2. Confirm access to the USB device on this device again.
+        \n\nResult: A progress indicator should appear or test will finish.
+    </string>
+    <string name="usb_device_test_step4">
+        Test is running and will complete automatically in a less than 30 seconds.
+    </string>
+    <string name="usb_device_unexpected">Usb companion device is not as expected %1$s. Please retry test.</string>
 
     <!-- Strings for MTP host test activity -->
     <string name="mtp_host_test">MTP Host Test</string>
@@ -1208,15 +1235,15 @@
     <string name="p2p_go_neg_requester_info">
         Go to the Wi-Fi settings and forget all remembered networks.  Then
         start the \"GO Negotiation Responder Test\" on the other device.
-        Then run each test individually by clicking on it\'s name.</string>
+        Then run each test individually by clicking on its name.</string>
     <string name="p2p_join_go_info">
         Go to the Wi-Fi settings and forget all remembered networks.  Then
         start the \"Group Owner Test\" on the other device.
-        Then run each test individually by clicking on it\'s name.</string>
+        Then run each test individually by clicking on its name.</string>
     <string name="p2p_service_discovery_requester_info">
         Go to the Wi-Fi settings and forget all remembered networks.  Then
         start the \"Service Discovery Responder Test\" on the other device.
-        Then run each test individually by clicking on it\'s name.</string>
+        Then run each test individually by clicking on its name.</string>
 
     <string name="p2p_not_enabled">Wi-Fi is not enabled</string>
     <string name="p2p_not_enabled_message">These tests require Wi-Fi to be enabled.
@@ -1380,11 +1407,17 @@
     <string name="attention_some_are_filtered">Check that \"Priority\" mode doesn\'t filter priority notifications.</string>
     <string name="attention_all_are_filtered">Check that \"None\" mode filters all notifications.</string>
     <string name="nls_test">Notification Listener Test</string>
+    <string name="nas_test">Notification Assistant Test</string>
     <string name="nls_service_name">Notification Listener for CTS Verifier</string>
     <string name="nls_info">This test checks that a NotificationListenerService can be enabled
         and disabled, and that once enabled the service is able to receive notifications and
         dismiss them.
     </string>
+    <string name="nas_service_name">Notification Assistant for CTS Verifier</string>
+    <string name="nas_info">This test checks that a NotificationAssistantService can be enabled
+        and disabled, and that once enabled the service is able to receive notifications and
+        dismiss them.
+    </string>
     <string name="vr_tests">VR Tests</string>
     <string name="test_category_vr">VR</string>
     <string name="vr_test_title">VR Listener Test</string>
@@ -1402,18 +1435,35 @@
         under Apps > Gear Icon > Special Access > VR Helper Services and return here.</string>
         <string name="vr_disable_service">Please disable \"VR Listener for CTS Verifier\"
         under Apps > Gear Icon > Special Access > VR Helper Services and return here.</string>
+    <string name="nas_enable_service">Please enable \"Notification Assistant for CTS Verifier\"
+        under Apps > Gear Icon > Default > Notification Assistant and return here.</string>
+    <string name="nas_disable_service">Please disable \"Notification Assistant for CTS Verifier\"
+        under Apps > Gear Icon > Default > Notification Assistant and return here.</string>
     <string name="nls_enable_service">Please enable \"Notification Listener for CTS Verifier\"
         under Apps > Gear Icon > Special Access > Notification Access and return here.</string>
     <string name="nls_disable_service">Please disable \"Notification Listener for CTS Verifier\"
         under Apps > Gear Icon > Special Access > Notification Access and return here.</string>
     <string name="nls_start_settings">Launch Settings</string>
     <string name="nls_service_started">Service should start once enabled.</string>
+    <string name="nas_note_enqueued_received">Check that notification was enqueued.</string>
     <string name="nls_note_received">Check that notification was received.</string>
     <string name="nls_payload_intact">Check that notification payload was intact.</string>
+    <string name="nas_adjustment_payload_intact">Check that the Assistant can adjust notifications.</string>
+    <string name="nas_create_channel">Check that the Assistant can create a Notification Channel for another app.</string>
+    <string name="nas_update_channel">Check that the Assistant can update a Notification Channel for another app.</string>
+    <string name="nas_delete_channel">Check that the Assistant can delete a Notification Channel for another app.</string>
     <string name="nls_clear_one">Check that service can clear a notification.</string>
+    <string name="nls_clear_one_reason">Check that service can clear a notification and receive the correct reason for dismissal.</string>
     <string name="nls_clear_all">Check that service can clear all notifications.</string>
     <string name="nls_service_stopped">Service should stop once disabled.</string>
     <string name="nls_note_missed">Check that notification was not received.</string>
+    <string name="nls_snooze">Check the service can be snoozed.</string>
+    <string name="nls_unsnooze">Check the service can be unsnoozed.</string>
+    <string name="nls_hints">Check that the listener can set hints.</string>
+    <string name="nls_snooze_one">Check that service can snooze a notification.</string>
+    <string name="nls_snooze_one_time">Check that service can snooze a notification for a given time.</string>
+    <string name="nls_unsnooze_one">Check that service can unsnooze a notification.</string>
+    <string name="nas_note_missed_enqueued">Check that notification was not enqueued.</string>
     <string name="cp_test">Condition Provider test</string>
     <string name="cp_service_name">Condition Provider for CTS Verifier</string>
     <string name="cp_info">This test checks that a ConditionProviderService can be enabled
@@ -1424,6 +1474,7 @@
     <string name="cp_disable_service">Please disable \"CTS Verifier\" under Do Not Disturb access and return here.</string>
     <string name="cp_start_settings">Launch Settings</string>
     <string name="cp_create_rule">Creating Automatic Zen Rule</string>
+    <string name="cp_update_rule">Updating Automatic Zen Rule</string>
     <string name="cp_subscribe_rule">Subscribing to Automatic Zen Rule</string>
     <string name="cp_service_started">Service should start once enabled.</string>
     <string name="cp_service_stopped">Service should stop once disabled.</string>
@@ -1580,7 +1631,7 @@
     <string name="provisioning_byod_capture_media_error">Error while capturing media from managed profile.</string>
     <string name="provisioning_byod_capture_image_error">Error while capturing image from managed profile.</string>
 
-    <string name="provisioning_byod_auth_bound_key">Autentication-boud keys</string>
+    <string name="provisioning_byod_auth_bound_key">Authentication-bound keys</string>
     <string name="provisioning_byod_auth_bound_key_info">
         This test verifies keystore cryptographic keys can be bound to device credentials.
         These keys should only be available if there was a recent enough authentication.
@@ -1597,7 +1648,7 @@
     <string name="provisioning_byod_auth_bound_key_set_up">Set up</string>
     <string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
     <string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
-    <string name="provisioning_byod_vpn">Vpn test</string>
+    <string name="provisioning_byod_vpn">VPN test</string>
     <string name="provisioning_byod_select_work_challenge">Select work lock test</string>
     <string name="provisioning_byod_select_work_challenge_description">
         This test verifies that a work lock can be chosen.\n
@@ -1712,7 +1763,7 @@
     <string name="test_category_projection">Projection Tests</string>
     <string name="projection_service_name">Projection Service</string>
     <string name="pca_info">This tests whether or not OpenGL projection works.\n
-        You should see two "tumbling cubes." Tapping the screen should case the cubes to explode.</string>
+        You should see two "tumbling cubes." Tapping the screen should cause the cubes to explode.</string>
     <string name="pca_test">Projection Cube Test</string>
     <string name="pwa_info">This tests whether or displaying widets and keyfocus navigation works.\n
         You should see four buttons on the bottom of the screen.\n
@@ -2123,9 +2174,9 @@
     </string>
 
     <string name="provisioning_byod_turn_off_work">Turn off work mode</string>
-    <string name="provisioning_byod_turn_off_work_info">This test verifes device behaviours when turning off work mode.</string>
+    <string name="provisioning_byod_turn_off_work_info">This test verifies device behaviors when turning off work mode.</string>
     <string name="provisioning_byod_turn_off_work_instructions">
-        This test verifies the device behaviour when work profile is turned off.\n
+        This test verifies the device behavior when work profile is turned off.\n
         Please exercise the following tests in sequence.\n
         The button below can be used to open the Settings page where you can toggle work mode.
     </string>
@@ -2196,14 +2247,32 @@
         2. Lock and unlock the screen to verify that the personal side password was set correctly.\n
     </string>
 
-    <!-- Strings for DeviceOwnerProvisioningTest -->
-    <string name="provisioning_device_owner">Device Owner Provisioning</string>
-    <string name="device_owner_provisioning_tests">Device Owner provisioning tests</string>
-    <string name="device_owner_provisioning_tests_info">The device owner provisioning tests verify that setting up a corporate owned device can only be done on a factory reset device.</string>
-    <string name="device_owner_provisioning_category">Device Owner Provisioning</string>
-    <string name="device_owner_negative_test">Device owner negative test</string>
-    <string name="device_owner_negative_test_info">Please click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
+    <!-- Strings for DeviceOwnerNegativeTestActivity -->
+    <string name="negative_device_owner">No Device Owner Tests</string>
+    <string name="device_owner_negative_category">No Device Owner Tests</string>
+    <string name="device_owner_provisioning_negative">Device owner provisioning</string>
+    <string name="device_owner_provisioning_negative_info">The device owner provisioning test verifies that setting up a corporate owned device can only be done on a factory reset device.\n\nPlease click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
     <string name="start_device_owner_provisioning_button">Start provisioning</string>
+    <string name="enterprise_privacy_quick_settings_negative">Quick settings disclosure</string>
+    <string name="enterprise_privacy_quick_settings_negative_info">
+        Please do the following:\n
+        1) Open and fully expand Quick Settings.\n
+        2) Verify that at the bottom of Quick Settings, you are not told the device is managed.\n
+        3) Close Quick Settings.
+    </string>
+    <string name="enterprise_privacy_keyguard_negative">Keyguard disclosure</string>
+    <string name="enterprise_privacy_keyguard_negative_info">
+        Please do the following:\n
+        1) Press the Go button to open Settings.\n
+        2) Navigate to \"Security\" &gt; \"Screen lock\" and select the first screen lock type that is not \"None\".\n
+        3) Use the Back button to return to this page.\n
+        4) Lock the device.\n
+        5) Verify that on the lock screen, you are not told the device is managed.\n
+        6) Unlock the device.\n
+        7) Repeat steps (1) through (6) for each screen lock type other than \"None\".
+    </string>
+
+    <!-- Strings for DeviceOwnerPositiveTestActivity -->
     <string name="positive_device_owner">Device Owner Tests</string>
     <string name="device_owner_positive_tests">Device Owner positive tests</string>
     <string name="device_owner_positive_tests_instructions">
@@ -2305,8 +2374,8 @@
     <string name="device_profile_owner_permission_lockdown_test">Permissions lockdown</string>
     <string name="device_profile_owner_permission_lockdown_test_instructions">
             Select each of the three grant states for the permission shown below in turn.\n
-            Now open application settings, select Permissions, and verify if the following behaviour is observed.\n
-            <b>Allow:</b> Permission is granted to the app and cannot be changed through the settings UI. Trying to change it triggers a support message.\n
+            Now open application settings, select Permissions, and verify if the following behavior is observed.\n
+            <b>Grant:</b> Permission is granted to the app and cannot be changed through the settings UI. Trying to change it triggers a support message.\n
             <b>Let user decide:</b> Permission state can be changed through the settings UI.\n
             <b>Deny:</b> Permission is denied to the app and cannot be changed through the settings UI. Trying to change it triggers a support message.\n
             Please mark the test accordingly.
@@ -2408,7 +2477,7 @@
     <string name="device_owner_settings_go">Go</string>
 
     <string name="device_owner_vpn_connection">
-        Vpn connection has been established.\n
+        VPN connection has been established.\n
         This is not as expected.\n
         Mark this test as failed.\n
     </string>
@@ -2423,19 +2492,19 @@
         Mark this test as passed.\n
     </string>
     <string name="device_owner_vpn_test">Check VPN</string>
-    <string name="device_owner_vpn_info_default">Vpn test message</string>
+    <string name="device_owner_vpn_info_default">VPN test message</string>
 
     <string name="device_owner_disallow_config_vpn">Disallow configuring VPN</string>
     <string name="device_owner_disallow_config_vpn_info">
         Please press the Set VPN restriction button to set the VPN restriction.
         Perform tests in order. Mark test as passed if both test cases pass\n\n
-        1. Press Go to open the Vpn settings page.\n
+        1. Press Go to open the VPN settings page.\n
         Confirm that:\n
         - You cannot add a new VPN network.\n
         - You cannot edit, add or remove any existing VPNs.\n
         - Trying to perform any of the above actions will trigger a support message.\n\n
-        2. Press Check VPN to check programmatic Vpn test.\n
-        - Check Vpn setup is not allowed\n
+        2. Press Check VPN to check programmatic VPN test.\n
+        - Check VPN setup is not allowed\n
         - If prompted to allow a VPN connection, press OK.\n\n
         Use the Back button to return to this page.
     </string>
@@ -2650,18 +2719,102 @@
         Check that \'Dummy Input method\' is not enabled in Settings and disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
     </string>
     <string name="set_permitted_input_methods_action">
-        Enabling \'Dummy Input Method\' in the list of accessibility services
+        Enabling \'Dummy Input method\' in the list of accessibility services
     </string>
     <string name="set_permitted_input_methods_widget_label">
         Allow only system input methods:
     </string>
 
+    <!-- Strings used for enterprise privacy tests -->
+    <string name="enterprise_privacy_test">Privacy info test</string>
+    <string name="enterprise_privacy_page">Privacy info page</string>
+    <string name="enterprise_privacy_page_info">
+        Please press the Go button to open Settings. Verify that:\n
+        1) There is an entry for device privacy.\n
+        2) Tapping that entry opens a screen in which you are told your organization can:\n
+        3) Change settings on this device.\n
+        4) See data associated with your work account.\n
+        5) See the list of all apps on your device.\n
+        6) See usage of each app on your device.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="enterprise_privacy_open_settings">Open Settings</string>
+    <string name="enterprise_privacy_network_logging">Retrieve traffic logs</string>
+    <string name="enterprise_privacy_network_logging_info">
+        Please do the following:\n
+        1) Press the Retrieve Traffic Logs button and record the time at which you did this.\n
+        2) Wait one minute.\n
+        3) Press the Open Settings button.\n
+        4) In the screen that opens, verify that you are told traffic logs were last retrieved at the time you pressed the Retrieve Traffic Logs button in step (1).\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="enterprise_privacy_retrieve_network_logs">Retrieve Traffic Logs</string>
+    <string name="enterprise_privacy_bug_report">Request bug report</string>
+    <string name="enterprise_privacy_bug_report_info">
+        Please do the following:\n
+        1) Press the Request Bug Report button and record the time at which you did this.\n
+        2) Wait one minute.\n
+        3) Press the Open Settings button.\n
+        4) In the screen that opens, verify that you are told a bug report was last requested at the time you pressed the Request Bug Report button in step (1).\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="enterprise_privacy_request_bug_report">Request Bug Report</string>
+    <string name="enterprise_privacy_security_logging">Retrieve security logs</string>
+    <string name="enterprise_privacy_security_logging_info">
+        Please do the following:\n
+        1) Press the Retrieve Security Logs button and record the time at which you did this.\n
+        2) Wait one minute.\n
+        3) Press the Open Settings button.\n
+        4) In the screen that opens, verify that you are told security logs were last retrieved at the time you pressed the Retrieve Security Logs button in step (1).\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="enterprise_privacy_retrieve_security_logs">Retrieve Security Logs</string>
+    <string name="enterprise_privacy_clear_organization">Clear Org</string>
+    <string name="enterprise_privacy_set_organization">Set Org</string>
+    <string name="enterprise_privacy_quick_settings">Quick settings disclosure</string>
+    <string name="enterprise_privacy_quick_settings_info">
+        Please do the following:\n
+        1) Press the Clear Org button.\n
+        2) Open and fully expand Quick Settings.\n
+        3) Verify that at the bottom of Quick Settings, you are told the device is managed.\n
+        4) Close Quick Settings.\n
+        5) Press the Set Org button.\n
+        6) Open and fully expand Quick Settings.\n
+        7) Verify that at the bottom of Quick Settings, you are told the device is managed by \"Foo, Inc.\".\n
+        8) Tap on the information.\n
+        9) Verify that a dialog informing you about device monitoring opens.\n
+        10) Tap the \"Learn more\" link.\n
+        11) Verify that a screen informing you what your managing organization can do is shown.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="enterprise_privacy_keyguard">Keyguard disclosure</string>
+    <string name="enterprise_privacy_keyguard_info">
+        Please do the following:\n
+        1) Press the Open Settings button to open Settings.\n
+        2) Navigate to \"Security\" &gt; \"Screen lock\" and select the first screen lock type that is not \"None\".\n
+        3) Use the Back button to return to this page.\n
+        4) Press the Clear Org button.\n
+        5) Lock the device.\n
+        6) Verify that on the lock screen, you are told the device is managed.\n
+        7) Unlock the device.\n
+        8) Press the Set Org button.\n
+        9) Lock the device.\n
+        10) Verify that on the lock screen, you are told the device is managed by \"Foo, Inc.\".\n
+        11) Unlock the device.\n
+        12) Repeat steps (1) through (11) for each screen lock type other than \"None\".
+    </string>
+
     <!-- Strings for JobScheduler Tests -->
     <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
 
     <string name="js_idle_test">Idle Mode Constraints</string>
     <string name="js_start_test_text">Start test</string>
-    <string name="js_idle_instructions">Verify the behaviour of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
+    <string name="js_idle_instructions">Verify the behavior of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
     <string name="js_idle_description_1">Turn the screen off and then back on in order to begin.</string>
     <string name="js_idle_continue_instruction">
         Switch off screen and wait for it to turn on to continue.
@@ -2670,16 +2823,16 @@
     <string name="js_idle_item_idle_on">Idle job does execute when device is forced into idle.</string>
 
     <string name="js_charging_test">Charging Constraints</string>
-    <string name="js_charging_instructions">Verify the behaviour of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
+    <string name="js_charging_instructions">Verify the behavior of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
     <string name="js_charging_description_1">Plug in the charger if it isn\'t already plugged in.</string>
     <string name="js_charging_off_test">Device not charging will not execute a job with a charging constraint.</string>
     <string name="js_charging_on_test">Device when charging will execute a job with a charging constraint.</string>
     <string name="js_charging_description_2">After the above test has passed, remove the charger to continue. If the above failed, you can simply fail this test.</string>
-    <string name="js_charging_description_3">Device is plugged in. Please wait while it get\s into stable charging state.</string>
+    <string name="js_charging_description_3">Device is plugged in. Please wait while it gets into stable charging state.</string>
     <string name="js_charging_description_4">There seems to be a problem with your charger. Pleasy try again.</string>
 
     <string name="js_connectivity_test">Connectivity Constraints</string>
-    <string name="js_connectivity_instructions">Verify the behaviour of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
+    <string name="js_connectivity_instructions">Verify the behavior of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
     <string name="js_connectivity_description_1">Disable WiFi and Cellular data to begin.</string>
     <string name="js_unmetered_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
     <string name="js_any_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
@@ -3037,6 +3190,140 @@
 
     <string name="unprocessed_test_global_result">Global 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 color 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 its 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 color 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
+        its 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>
+
     <!-- Strings for voicemail broadcast test -->
     <string name="voicemail_broadcast_test">Voicemail Broadcast Test</string>
     <string name="voicemail_broadcast_instructions">This test verifies that the default dialer can intercept the voicemail notification. The test must be conducted on a SIM with visual voicemail disabled</string>
diff --git a/apps/CtsVerifier/res/xml/accessory_filter.xml b/apps/CtsVerifier/res/xml/accessory_filter.xml
index 21caaa4..4a1d779 100644
--- a/apps/CtsVerifier/res/xml/accessory_filter.xml
+++ b/apps/CtsVerifier/res/xml/accessory_filter.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <resources>
-    <usb-accessory manufacturer="Android CTS" model="CTS USB Accessory" version="1.0" />
+    <usb-accessory />
 </resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index 6933ef4..167fd84 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -21,12 +21,10 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -51,7 +49,6 @@
     private final int mInstructionsStringId;
 
     protected Button mPrepareTestButton;
-    protected ListView mTestFeaturesList;
 
     protected int mCurrentTestPosition;
 
@@ -88,31 +85,15 @@
 
         mCurrentTestPosition = 0;
 
-        TextView instructionTextView = (TextView) findViewById(R.id.test_instructions);
+        TextView instructionTextView = (TextView)findViewById(R.id.test_instructions);
         instructionTextView.setText(mInstructionsStringId);
-        mPrepareTestButton = (Button) findViewById(R.id.prepare_test_button);
-        mTestFeaturesList = (ListView) findViewById(android.R.id.list);
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            mTestFeaturesList.setOnTouchListener((View v, MotionEvent e) -> {
-                switch (e.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        v.getParent().requestDisallowInterceptTouchEvent(true);
-                        break;
-                    case MotionEvent.ACTION_UP:
-                        v.getParent().requestDisallowInterceptTouchEvent(false);
-                        break;
-                    default:
-                }
-                return false;
-            });
-        }
+        mPrepareTestButton = (Button)findViewById(R.id.prepare_test_button);
     }
 
     /**
      * Subclasses must add their tests items to the provided adapter(usually instances of
      * {@link DialogTestListItem} or {@link DialogTestListItemWithIcon} but any class deriving from
      * {@link TestListAdapter.TestListItem} will do).
-     *
      * @param adapter The adapter to add test items to.
      */
     protected abstract void setupTests(ArrayTestListAdapter adapter);
@@ -184,7 +165,7 @@
                 .getItem(position);
         if (test instanceof DialogTestListItem) {
             mCurrentTestPosition = position;
-            ((DialogTestListItem) test).performTest(this);
+            ((DialogTestListItem)test).performTest(this);
         } else {
             try {
                 super.handleItemClick(l, v, position, id);
@@ -199,7 +180,6 @@
 
     /**
      * Start a test's manual intent
-     *
      * @param test The test the manual intent of which is to be started.
      * @return true if activity could be started successfully, false otherwise.
      */
@@ -238,7 +218,6 @@
 
         public interface TestCallback {
             void onPass();
-
             void onFail();
         }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
index 33c9b62..062d2aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
@@ -21,11 +21,21 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Environment;
+import android.os.SystemClock;
+
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.InvocationResult;
+import com.android.compatibility.common.util.ResultHandler;
+
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
@@ -38,6 +48,21 @@
  * Background task to generate a report and save it to external storage.
  */
 class ReportExporter extends AsyncTask<Void, Void, String> {
+
+    private static final String COMMAND_LINE_ARGS = "CtsVerifier";
+    private static final String LOG_URL = null;
+    private static final String REFERENCE_URL = null;
+    private static final String SUITE_NAME = "ctsverifier";
+    private static final String SUITE_PLAN = "CTSVERIFIER";
+    private static final String SUITE_BUILD = "0";
+
+    private static final long START_MS = SystemClock.uptimeMillis();
+    private static final long END_MS = START_MS;
+
+    private static final int BUFFER_SIZE = 16 * 1024;
+    private static final String REPORT_DIRECTORY = "ctsVerifierReports";
+    private static final String ZIP_EXTENSION = ".zip";
+
     protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
 
     private final Context mContext;
@@ -54,50 +79,69 @@
             LOG.log(Level.WARNING, "External storage is not writable.");
             return mContext.getString(R.string.no_storage);
         }
-        byte[] contents;
+        IInvocationResult result;
         try {
             TestResultsReport report = new TestResultsReport(mContext, mAdapter);
-            contents = report.getContents().getBytes();
+            result = report.generateResult();
         } catch (Exception e) {
             LOG.log(Level.WARNING, "Couldn't create test results report", e);
             return mContext.getString(R.string.test_results_error);
         }
-        File reportPath = new File(Environment.getExternalStorageDirectory(), "ctsVerifierReports");
-        reportPath.mkdirs();
+        // create a directory for CTS Verifier reports
+        File externalStorageDirectory = Environment.getExternalStorageDirectory();
+        File verifierReportsDir = new File(externalStorageDirectory, REPORT_DIRECTORY);
+        verifierReportsDir.mkdirs();
+        // create a temporary directory for this particular report
+        File tempDir = new File(verifierReportsDir, getReportName());
+        tempDir.mkdirs();
 
-        String baseName = getReportBaseName();
-        File reportFile = new File(reportPath, baseName + ".zip");
-        ZipOutputStream out = null;
+        // create a File object for a report ZIP file
+        File reportZipFile = new File(verifierReportsDir, getReportName() + ZIP_EXTENSION);
+        // create a File object for the result XML file generated by ResultHandler
+        File tempXmlFile = new File(tempDir, ResultHandler.TEST_RESULT_FILE_NAME);
+
         try {
-            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(reportFile)));
-            ZipEntry entry = new ZipEntry(baseName + ".xml");
-            out.putNextEntry(entry);
-            out.write(contents);
-        } catch (IOException e) {
+            // Serialize the report
+            String versionName = Version.getVersionName(mContext);
+            ResultHandler.writeResults(SUITE_NAME, versionName, SUITE_PLAN, SUITE_BUILD,
+                    result, tempDir, START_MS, END_MS, REFERENCE_URL, LOG_URL,
+                    COMMAND_LINE_ARGS);
+
+            // create a compressed ZIP file
+            FileOutputStream reportFileStream = new FileOutputStream(reportZipFile);
+            ZipOutputStream reportZipStream =
+                    new ZipOutputStream(new BufferedOutputStream(reportFileStream));
+            ZipEntry entry = new ZipEntry(ResultHandler.TEST_RESULT_FILE_NAME);
+            reportZipStream.putNextEntry(entry);
+
+            // TODO: compress all results via tradefed ZipUtil or equivalent;
+            // the current implementation only saves the generated result XML
+
+            // write the report to the ZIP file and close the ZIP file
+            FileInputStream tempXmlStream = new FileInputStream(tempXmlFile);
+            int size = -1;
+            byte[] ioBuffer = new byte[BUFFER_SIZE];
+            while ((size = tempXmlStream.read(ioBuffer)) != -1) {
+                reportZipStream.write(ioBuffer, 0, size);
+            }
+            reportZipStream.close();
+
+        } catch (IOException | XmlPullParserException 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);
-            }
+            // delete the temporary results file and directory made for the reports
+            tempXmlFile.delete();
+            tempDir.delete();
         }
-
-        return mContext.getString(R.string.report_saved, reportFile.getPath());
+        return mContext.getString(R.string.report_saved, reportZipFile.getPath());
     }
 
-    private String getReportBaseName() {
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss", Locale.ENGLISH);
+    private String getReportName() {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss", Locale.ENGLISH);
         String date = dateFormat.format(new Date());
-        return "ctsVerifierReport"
-                + "-" + date
-                + "-" + Build.MANUFACTURER
-                + "-" + Build.PRODUCT
-                + "-" + Build.DEVICE
-                + "-" + Build.ID;
+        String[] nameDetails = {date, Build.MANUFACTURER, Build.PRODUCT, Build.DEVICE, Build.ID};
+        return String.join("-", nameDetails);
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index 1e3f312..4dd7777 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -34,8 +34,6 @@
 import android.view.Window;
 import android.widget.Toast;
 
-import java.io.IOException;
-
 /** Top-level {@link ListActivity} for launching tests and managing results. */
 public class TestListActivity extends AbstractTestListActivity implements View.OnClickListener {
     private static final int CTS_VERIFIER_PERMISSION_REQUEST = 1;
@@ -146,15 +144,10 @@
     }
 
     private void handleViewItemSelected() {
-        try {
-            TestResultsReport report = new TestResultsReport(this, mAdapter);
-            Intent intent = new Intent(this, ReportViewerActivity.class);
-            intent.putExtra(ReportViewerActivity.EXTRA_REPORT_CONTENTS, report.getContents());
-            startActivity(intent);
-        } catch (IOException e) {
-            Toast.makeText(this, R.string.test_results_error, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Couldn't copy test results report", e);
-        }
+        TestResultsReport report = new TestResultsReport(this, mAdapter);
+        Intent intent = new Intent(this, ReportViewerActivity.class);
+        intent.putExtra(ReportViewerActivity.EXTRA_REPORT_CONTENTS, report.getContents());
+        startActivity(intent);
     }
 
     private void handleExportItemSelected() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index 36be7f9..9d9739d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -21,8 +21,15 @@
 import android.text.TextUtils;
 import android.util.Xml;
 
+import com.android.compatibility.common.util.DevicePropertyInfo;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.InvocationResult;
+import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.MetricsXmlSerializer;
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestStatus;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
 import org.xmlpull.v1.XmlSerializer;
@@ -33,26 +40,10 @@
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
+import java.util.Map.Entry;
 
 /**
- * XML text report of the current test results.
- * <p>
- * Sample:
- * <pre>
- * <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- * <test-results-report report-version="1" creation-time="Tue Jun 28 11:04:10 PDT 2011">
- *   <verifier-info version-name="2.3_r4" version-code="2" />
- *   <device-info>
- *     <build-info fingerprint="google/soju/crespo:2.3.4/GRJ22/121341:user/release-keys" />
- *   </device-info>
- *   <test-results>
- *     <test title="Audio Quality Verifier" class-name="com.android.cts.verifier.audioquality.AudioQualityVerifierActivity" result="not-executed" />
- *     <test title="Hardware/Software Feature Summary" class-name="com.android.cts.verifier.features.FeatureSummaryActivity" result="fail" />
- *     <test title="Bluetooth Test" class-name="com.android.cts.verifier.bluetooth.BluetoothTestActivity" result="fail" />
- *     <test title="Accelerometer Test" class-name="com.android.cts.verifier.sensors.AccelerometerTestActivity" result="pass" />
- *   </test-results>
- * </test-results-report>
- * </pre>
+ * Helper class for creating an {@code InvocationResult} for CTS result generation.
  */
 class TestResultsReport {
 
@@ -63,6 +54,7 @@
     private static DateFormat DATE_FORMAT =
             new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
 
+    private static final String PREFIX_TAG = "build_";
     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";
@@ -71,6 +63,9 @@
     private static final String TEST_TAG = "test";
     private static final String TEST_DETAILS_TAG = "details";
 
+    private static final String MODULE_ID = "noabi CtsVerifier";
+    private static final String TEST_CASE_NAME = "manualTests";
+
     private final Context mContext;
 
     private final TestListAdapter mAdapter;
@@ -80,83 +75,83 @@
         this.mAdapter = adapter;
     }
 
-    String getContents() throws IllegalArgumentException, IllegalStateException, IOException {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+    IInvocationResult generateResult() {
+        String abis = null;
+        String abis32 = null;
+        String abis64 = null;
+        String versionBaseOs = null;
+        String versionSecurityPatch = null;
+        IInvocationResult result = new InvocationResult();
+        IModuleResult moduleResult = result.getOrCreateModule(MODULE_ID);
 
-        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);
+        // Collect build fields available in API level 21
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            abis = TextUtils.join(",", Build.SUPPORTED_ABIS);
+            abis32 = TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS);
+            abis64 = TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS);
+        }
 
-        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()));
+        // Collect build fields available in API level 23
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            versionBaseOs = Build.VERSION.BASE_OS;
+            versionSecurityPatch = Build.VERSION.SECURITY_PATCH;
+        }
 
-        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);
+        // at the time of writing, the build class has no REFERENCE_FINGERPRINT property
+        String referenceFingerprint = null;
 
-        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);
+        DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(Build.CPU_ABI,
+                Build.CPU_ABI2, abis, abis32, abis64, Build.BOARD, Build.BRAND, Build.DEVICE,
+                Build.FINGERPRINT, Build.ID, Build.MANUFACTURER, Build.MODEL, Build.PRODUCT,
+                referenceFingerprint, Build.SERIAL, Build.TAGS, Build.TYPE, versionBaseOs,
+                Build.VERSION.RELEASE, Integer.toString(Build.VERSION.SDK_INT),
+                versionSecurityPatch);
 
-        xml.startTag(null, TEST_RESULTS_TAG);
+        // add device properties to the result with a prefix tag for each key
+        for (Entry<String, String> entry :
+                devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) {
+            String entryValue = entry.getValue();
+            if (entryValue != null) {
+                result.addInvocationInfo(entry.getKey(), entry.getValue());
+            }
+        }
+
+        ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME);
         int count = mAdapter.getCount();
         for (int i = 0; i < count; i++) {
             TestListItem item = mAdapter.getItem(i);
             if (item.isTest()) {
-                xml.startTag(null, TEST_TAG);
-                xml.attribute(null, "title", item.title);
-                xml.attribute(null, "class-name", item.testName);
-                xml.attribute(null, "result", getTestResultString(mAdapter.getTestResult(i)));
+                ITestResult currentTestResult = caseResult.getOrCreateResult(item.testName);
+                currentTestResult.setResultStatus(getTestResultStatus(mAdapter.getTestResult(i)));
+                // TODO: report test details with Extended Device Info (EDI) or CTS metrics
+                // String details = mAdapter.getTestDetails(i);
 
-                String details = mAdapter.getTestDetails(i);
-                if (!TextUtils.isEmpty(details)) {
-                    xml.startTag(null, TEST_DETAILS_TAG);
-                    xml.text(details);
-                    xml.endTag(null, TEST_DETAILS_TAG);
-                }
-
-                // TODO(stuartscott): For v2: ReportLog.serialize(xml, mAdapter.getReportLog(i));
                 ReportLog reportLog = mAdapter.getReportLog(i);
                 if (reportLog != null) {
-                    MetricsXmlSerializer metricsXmlSerializer = new MetricsXmlSerializer(xml);
-                    metricsXmlSerializer.serialize(reportLog);
+                    currentTestResult.setReportLog(reportLog);
                 }
-
-                xml.endTag(null, TEST_TAG);
             }
         }
-        xml.endTag(null, TEST_RESULTS_TAG);
+        moduleResult.setDone(true);
 
-        xml.endTag(null, TEST_RESULTS_REPORT_TAG);
-        xml.endDocument();
-
-        return outputStream.toString("utf-8");
+        return result;
     }
 
-    private String getTestResultString(int testResult) {
+    String getContents() {
+        // TODO: remove getContents and everything that depends on it
+        return "Report viewing is deprecated. See contents on the SD Card.";
+    }
+
+    private TestStatus getTestResultStatus(int testResult) {
         switch (testResult) {
             case TestResult.TEST_RESULT_PASSED:
-                return "pass";
+                return TestStatus.PASS;
 
             case TestResult.TEST_RESULT_FAILED:
-                return "fail";
+                return TestStatus.FAIL;
 
             case TestResult.TEST_RESULT_NOT_EXECUTED:
-                return "not-executed";
+                return null;
 
             default:
                 throw new IllegalArgumentException("Unknown test result: " + testResult);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index b0eaf35..363c9e1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -187,13 +187,16 @@
             ByteBuffer buffer = planes[0].getBuffer();
             if (quota != null) {
                 try {
+                    Logt.i(TAG, "Start waiting for quota Semaphore");
                     quota.acquire(buffer.capacity());
+                    Logt.i(TAG, "Acquired quota Semaphore. Start reading image");
                 } catch (java.lang.InterruptedException e) {
                     Logt.e(TAG, "getDataFromImage error acquiring memory quota. Interrupted", e);
                 }
             }
             data = new byte[buffer.capacity()];
             buffer.get(data);
+            Logt.i(TAG, "Done reading jpeg image, format %d");
             return data;
         } else if (format == ImageFormat.YUV_420_888 || format == ImageFormat.RAW_SENSOR
                 || format == ImageFormat.RAW10 || format == ImageFormat.RAW12) {
@@ -201,7 +204,9 @@
             int dataSize = width * height * ImageFormat.getBitsPerPixel(format) / 8;
             if (quota != null) {
                 try {
+                    Logt.i(TAG, "Start waiting for quota Semaphore");
                     quota.acquire(dataSize);
+                    Logt.i(TAG, "Acquired quota Semaphore. Start reading image");
                 } catch (java.lang.InterruptedException e) {
                     Logt.e(TAG, "getDataFromImage error acquiring memory quota. Interrupted", e);
                 }
@@ -220,8 +225,9 @@
                 int pixelStride = planes[i].getPixelStride();
                 int bytesPerPixel = ImageFormat.getBitsPerPixel(format) / 8;
                 Logt.i(TAG, String.format(
-                        "Reading image: fmt %d, plane %d, w %d, h %d, rowStride %d, pixStride %d",
-                        format, i, width, height, rowStride, pixelStride));
+                        "Reading image: fmt %d, plane %d, w %d, h %d," +
+                        "rowStride %d, pixStride %d, bytesPerPixel %d",
+                        format, i, width, height, rowStride, pixelStride, bytesPerPixel));
                 // For multi-planar yuv images, assuming yuv420 with 2x2 chroma subsampling.
                 int w = (i == 0) ? width : width / 2;
                 int h = (i == 0) ? height : height / 2;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index cf8ec89..a9445ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -29,6 +29,7 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.managedprovisioning.Utils;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 
@@ -60,6 +61,9 @@
     public static final String COMMAND_REMOVE_DEVICE_OWNER = "remove-device-owner";
     public static final String COMMAND_REQUEST_BUGREPORT = "request-bugreport";
     public static final String COMMAND_SET_USER_ICON = "set-user-icon";
+    public static final String COMMAND_RETRIEVE_NETWORK_LOGS = "retrieve-network-logs";
+    public static final String COMMAND_RETRIEVE_SECURITY_LOGS = "retrieve-security-logs";
+    public static final String COMMAND_SET_ORGANIZATION_NAME = "set-organization-name";
 
     public static final String EXTRA_USER_RESTRICTION =
             "com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION";
@@ -71,6 +75,9 @@
             "com.android.cts.verifier.managedprovisioning.extra.ENFORCED";
     public static final String EXTRA_VALUE =
             "com.android.cts.verifier.managedprovisioning.extra.VALUE";
+    public static final String EXTRA_ORGANIZATION_NAME =
+            "com.android.cts.verifier.managedprovisioning.extra.ORGANIZATION_NAME";
+
 
     private ComponentName mAdmin;
     private DevicePolicyManager mDpm;
@@ -180,6 +187,35 @@
                     mDpm.setUserIcon(mAdmin, BitmapFactory.decodeResource(getResources(),
                             com.android.cts.verifier.R.drawable.icon));
                 } break;
+                case COMMAND_RETRIEVE_NETWORK_LOGS: {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                        return;
+                    }
+                    // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove
+                    // reflection when the un-hiding happens.
+                    final Method setNetworkLoggingEnabledMethod =
+                            DevicePolicyManager.class.getDeclaredMethod(
+                                    "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+                    final Method retrieveNetworkLogsMethod =
+                            DevicePolicyManager.class.getDeclaredMethod(
+                                    "retrieveNetworkLogs", ComponentName.class, long.class);
+                    setNetworkLoggingEnabledMethod.invoke(mDpm, mAdmin, true);
+                    retrieveNetworkLogsMethod.invoke(mDpm, mAdmin, 0 /* batchToken */);
+                    setNetworkLoggingEnabledMethod.invoke(mDpm, mAdmin, false);
+                } break;
+                case COMMAND_RETRIEVE_SECURITY_LOGS: {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                        return;
+                    }
+                    mDpm.retrieveSecurityLogs(mAdmin);
+                } break;
+                case COMMAND_SET_ORGANIZATION_NAME: {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                        return;
+                    }
+                    mDpm.setOrganizationName(mAdmin,
+                            intent.getStringExtra(EXTRA_ORGANIZATION_NAME));
+                } break;
             }
         } catch (Exception e) {
             Log.e(TAG, "Failed to execute command: " + intent, e);
@@ -188,7 +224,7 @@
         }
     }
 
-    private void clearAllPolicies() {
+    private void clearAllPolicies() throws Exception {
         clearProfileOwnerRelatedPolicies();
 
         mDpm.clearUserRestriction(mAdmin, UserManager.DISALLOW_ADD_USER);
@@ -212,6 +248,12 @@
         mDpm.setKeyguardDisabled(mAdmin, false);
         mDpm.setAutoTimeRequired(mAdmin, false);
         mDpm.setStatusBarDisabled(mAdmin, false);
+        // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+        // un-hiding happens.
+        final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+        setNetworkLoggingEnabledMethod.invoke(mDpm, mAdmin, false);
+        mDpm.setOrganizationName(mAdmin, null);
     }
 
     private void clearProfileOwnerRelatedPolicies() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
index 5b43f6a..cee7307 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.provider.Settings;
 
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.IntentDrivenTestActivity;
@@ -31,43 +32,30 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
 /**
  * Activity that lists all device owner negative tests.
  */
 public class DeviceOwnerNegativeTestActivity extends PassFailButtons.TestListActivity {
 
-    private static final String DEVICE_OWNER_NEGATIVE_TEST = "DEVICE_OWNER_PROVISIONING_NEGATIVE";
+    private static final String DEVICE_OWNER_PROVISIONING_NEGATIVE
+            = "DEVICE_OWNER_PROVISIONING_NEGATIVE";
+    private static final String ENTERPRISE_PRIVACY_QUICK_SETTINGS_NEGATIVE
+            = "ENTERPRISE_PRIVACY_QUICK_SETTINGS_NEGATIVE";
+    private static final String ENTERPRISE_PRIVACY_KEYGUARD_NEGATIVE
+            = "ENTERPRISE_PRIVACY_KEYGUARD_NEGATIVE";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.pass_fail_list);
-        setInfoResources(R.string.device_owner_provisioning_tests,
-                R.string.device_owner_provisioning_tests_info, 0);
         setPassFailButtonClickListeners();
 
-        TestInfo deviceOwnerNegativeTestInfo = new TestInfo(
-                DEVICE_OWNER_NEGATIVE_TEST,
-                R.string.device_owner_negative_test,
-                R.string.device_owner_negative_test_info,
-                new ButtonInfo(
-                        R.string.start_device_owner_provisioning_button,
-                        new Intent(this, TrampolineActivity.class)));
-
         final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
-        adapter.add(TestListItem.newCategory(this, R.string.device_owner_provisioning_category));
+        adapter.add(TestListItem.newCategory(this, R.string.device_owner_negative_category));
 
-        Intent startTestIntent = new Intent(this, IntentDrivenTestActivity.class)
-                    .putExtra(IntentDrivenTestActivity.EXTRA_ID,
-                            deviceOwnerNegativeTestInfo.getTestId())
-                    .putExtra(IntentDrivenTestActivity.EXTRA_TITLE,
-                            deviceOwnerNegativeTestInfo.getTitle())
-                    .putExtra(IntentDrivenTestActivity.EXTRA_INFO,
-                            deviceOwnerNegativeTestInfo.getInfoText())
-                    .putExtra(IntentDrivenTestActivity.EXTRA_BUTTONS,
-                            deviceOwnerNegativeTestInfo.getButtons());
-
-        adapter.add(TestListItem.newTest(this, deviceOwnerNegativeTestInfo.getTitle(),
-                deviceOwnerNegativeTestInfo.getTestId(), startTestIntent, null));
+        addTestsToAdapter(adapter);
 
         adapter.registerDataSetObserver(new DataSetObserver() {
             @Override
@@ -79,6 +67,41 @@
         setTestListAdapter(adapter);
     }
 
+    private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+        final TestInfo provisioningNegativeTestInfo = new TestInfo(
+                DEVICE_OWNER_PROVISIONING_NEGATIVE,
+                R.string.device_owner_provisioning_negative,
+                R.string.device_owner_provisioning_negative_info,
+                new ButtonInfo(
+                        R.string.start_device_owner_provisioning_button,
+                        new Intent(this, TrampolineActivity.class)));
+        final Intent startTestIntent = new Intent(this, IntentDrivenTestActivity.class)
+                    .putExtra(IntentDrivenTestActivity.EXTRA_ID,
+                            provisioningNegativeTestInfo.getTestId())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_TITLE,
+                            provisioningNegativeTestInfo.getTitle())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_INFO,
+                            provisioningNegativeTestInfo.getInfoText())
+                    .putExtra(IntentDrivenTestActivity.EXTRA_BUTTONS,
+                            provisioningNegativeTestInfo.getButtons());
+        adapter.add(TestListItem.newTest(this, provisioningNegativeTestInfo.getTitle(),
+                provisioningNegativeTestInfo.getTestId(), startTestIntent, null));
+        adapter.add(TestListItem.newTest(this, R.string.enterprise_privacy_quick_settings_negative,
+                ENTERPRISE_PRIVACY_QUICK_SETTINGS_NEGATIVE,
+                new Intent(this, EnterprisePrivacyInfoOnlyTestActivity.class)
+                        .putExtra(EnterprisePrivacyInfoOnlyTestActivity.EXTRA_ID,
+                                ENTERPRISE_PRIVACY_QUICK_SETTINGS_NEGATIVE)
+                        .putExtra(EnterprisePrivacyInfoOnlyTestActivity.EXTRA_TITLE,
+                                R.string.enterprise_privacy_quick_settings_negative)
+                        .putExtra(EnterprisePrivacyInfoOnlyTestActivity.EXTRA_INFO,
+                                R.string.enterprise_privacy_quick_settings_negative_info),
+                        null));
+        adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_KEYGUARD_NEGATIVE,
+                R.string.enterprise_privacy_keyguard_negative,
+                R.string.enterprise_privacy_keyguard_negative_info,
+                new ButtonInfo(R.string.go_button_text, new Intent(Settings.ACTION_SETTINGS))));
+    }
+
     /**
      * This is needed because IntentDrivenTestActivity fires the intent by startActivity when
      * a button is clicked, but ACTION_PROVISION_MANAGED_DEVICE requires to be fired by
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 024854c..b5ed29d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -70,6 +70,7 @@
     private static final String DISALLOW_DATA_ROAMING_ID = "DISALLOW_DATA_ROAMING";
     private static final String DISALLOW_FACTORY_RESET_ID = "DISALLOW_FACTORY_RESET";
     private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY";
+    private static final String ENTERPRISE_PRIVACY_TEST_ID = "ENTERPRISE_PRIVACY";
     private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
 
     @Override
@@ -297,6 +298,15 @@
                 R.string.device_profile_owner_policy_transparency_test,
                 policyTransparencyTestIntent));
 
+        // Enterprise Privacy
+        final Intent enterprisePolicyTestIntent = new Intent(this,
+                EnterprisePrivacyTestListActivity.class);
+        enterprisePolicyTestIntent.putExtra(
+                EnterprisePrivacyTestListActivity.EXTRA_TEST_ID, ENTERPRISE_PRIVACY_TEST_ID);
+        adapter.add(createTestItem(this, ENTERPRISE_PRIVACY_TEST_ID,
+                R.string.enterprise_privacy_test,
+                enterprisePolicyTestIntent));
+
         // removeDeviceOwner
         adapter.add(createInteractiveTestItem(this, REMOVE_DEVICE_OWNER_TEST_ID,
                 R.string.device_owner_remove_device_owner_test,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyInfoOnlyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyInfoOnlyTestActivity.java
new file mode 100644
index 0000000..99961dc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyInfoOnlyTestActivity.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 com.android.cts.verifier.managedprovisioning;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TextView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+/**
+ * A test Activity that has an info text and pass/fail buttons, nothing else.
+ */
+public class EnterprisePrivacyInfoOnlyTestActivity extends PassFailButtons.Activity {
+    public static final String EXTRA_ID = "id";
+    public static final String EXTRA_TITLE = "title";
+    public static final String EXTRA_INFO = "info";
+
+    private String mTestId;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.enterprise_privacy_negative_test);
+        setPassFailButtonClickListeners();
+
+        final Intent intent = getIntent();
+        if (!intent.hasExtra(EXTRA_ID)
+                || !intent.hasExtra(EXTRA_TITLE)
+                || !intent.hasExtra(EXTRA_INFO)) {
+            throw new IllegalArgumentException(
+                    "Intent must have EXTRA_ID, EXTRA_TITLE & EXTRA_INFO");
+        }
+
+        mTestId = intent.getStringExtra(EXTRA_ID);
+        setTitle(intent.getIntExtra(EXTRA_TITLE, -1));
+
+        final TextView info = (TextView) findViewById(R.id.info);
+        info.setText(intent.getIntExtra(EXTRA_INFO, -1));
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setResult(RESULT_CANCELED);
+    }
+
+    @Override
+    public String getTestId() {
+        return mTestId;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
new file mode 100644
index 0000000..81a3404
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -0,0 +1,140 @@
+/*
+ * 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.managedprovisioning;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.provider.Settings;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
+
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
+/**
+ * Test class to verify privacy information is shown for devices managed by a Device Owner.
+ */
+public class EnterprisePrivacyTestListActivity extends PassFailButtons.TestListActivity {
+
+    private static final String ENTERPRISE_PRIVACY_PAGE = "ENTERPRISE_PRIVACY_PAGE";
+    private static final String ENTERPRISE_PRIVACY_NETWORK_LOGGING
+            = "ENTERPRISE_PRIVACY_NETWORK_LOGGING";
+    private static final String ENTERPRISE_PRIVACY_BUG_REPORT = "ENTERPRISE_PRIVACY_BUG_REPORT";
+    private static final String ENTERPRISE_PRIVACY_SECURITY_LOGGING
+            = "ENTERPRISE_PRIVACY_SECURITY_LOGGING";
+    private static final String ENTERPRISE_PRIVACY_QUICK_SETTINGS
+            = "ENTERPRISE_PRIVACY_QUICK_SETTINGS";
+    private static final String ENTERPRISE_PRIVACY_KEYGUARD = "ENTERPRISE_PRIVACY_KEYGUARD";
+
+    public static final String EXTRA_TEST_ID =
+            "com.android.cts.verifier.managedprovisioning.extra.TEST_ID";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_list);
+        setPassFailButtonClickListeners();
+        final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+        addTestsToAdapter(adapter);
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+        setTestListAdapter(adapter);
+    }
+
+    private Intent buildCommandIntent(String command) {
+        return new Intent(CommandReceiverActivity.ACTION_EXECUTE_COMMAND)
+                .putExtra(CommandReceiverActivity.EXTRA_COMMAND, command);
+    }
+
+    private TestListItem buildCommandTest(String id, int titleRes, int infoRes,
+            int commandButtonRes, String command) {
+        return createInteractiveTestItem(this, id, titleRes, infoRes,
+                new ButtonInfo[] {
+                        new ButtonInfo(commandButtonRes, buildCommandIntent(command)),
+                        new ButtonInfo(R.string.enterprise_privacy_open_settings,
+                               new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS))});
+    }
+
+    private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+        adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_PAGE,
+                R.string.enterprise_privacy_page,
+                R.string.enterprise_privacy_page_info,
+                new ButtonInfo(R.string.go_button_text, new Intent(Settings.ACTION_SETTINGS))));
+        adapter.add(buildCommandTest(ENTERPRISE_PRIVACY_NETWORK_LOGGING,
+                R.string.enterprise_privacy_network_logging,
+                R.string.enterprise_privacy_network_logging_info,
+                R.string.enterprise_privacy_retrieve_network_logs,
+                CommandReceiverActivity.COMMAND_RETRIEVE_NETWORK_LOGS));
+        adapter.add(buildCommandTest(ENTERPRISE_PRIVACY_BUG_REPORT,
+                R.string.enterprise_privacy_bug_report,
+                R.string.enterprise_privacy_bug_report_info,
+                R.string.enterprise_privacy_request_bug_report,
+                CommandReceiverActivity.COMMAND_REQUEST_BUGREPORT));
+        adapter.add(buildCommandTest(ENTERPRISE_PRIVACY_SECURITY_LOGGING,
+                R.string.enterprise_privacy_security_logging,
+                R.string.enterprise_privacy_security_logging_info,
+                R.string.enterprise_privacy_retrieve_security_logs,
+                CommandReceiverActivity.COMMAND_RETRIEVE_SECURITY_LOGS));
+        adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_QUICK_SETTINGS,
+                R.string.enterprise_privacy_quick_settings,
+                R.string.enterprise_privacy_quick_settings_info,
+                new ButtonInfo[] {
+                        new ButtonInfo(R.string.enterprise_privacy_clear_organization,
+                                buildCommandIntent(
+                                        CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)),
+                        new ButtonInfo(R.string.enterprise_privacy_set_organization,
+                                buildCommandIntent(
+                                        CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)
+                                        .putExtra(CommandReceiverActivity.EXTRA_ORGANIZATION_NAME,
+                                                "Foo, Inc."))}));
+        adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_KEYGUARD,
+                R.string.enterprise_privacy_keyguard,
+                R.string.enterprise_privacy_keyguard_info,
+                new ButtonInfo[] {
+                        new ButtonInfo(R.string.enterprise_privacy_open_settings,
+                                new Intent(Settings.ACTION_SETTINGS)),
+                        new ButtonInfo(R.string.enterprise_privacy_clear_organization,
+                                buildCommandIntent(
+                                        CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)),
+                        new ButtonInfo(R.string.enterprise_privacy_set_organization,
+                                buildCommandIntent(
+                                        CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)
+                                        .putExtra(CommandReceiverActivity.EXTRA_ORGANIZATION_NAME,
+                                                "Foo, Inc."))}));
+    }
+
+    @Override
+    public String getTestId() {
+        return getIntent().getStringExtra(EXTRA_TEST_ID);
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+        startActivity(buildCommandIntent(
+                CommandReceiverActivity.COMMAND_DEVICE_OWNER_CLEAR_POLICIES));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
index 0b0be81..24d88b7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -27,7 +27,6 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -60,6 +59,7 @@
         tests.add(new IsEnabledTest());
         tests.add(new ServiceStartedTest());
         tests.add(new CreateAutomaticZenRuleTest());
+        tests.add(new UpdateAutomaticZenRuleTest());
         tests.add(new GetAutomaticZenRuleTest());
         tests.add(new GetAutomaticZenRulesTest());
         tests.add(new SubscribeAutomaticZenRuleTest());
@@ -171,6 +171,54 @@
         }
     }
 
+    private class UpdateAutomaticZenRuleTest extends InteractiveTestCase {
+        private String id = null;
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.cp_update_rule);
+        }
+
+        @Override
+        void setUp() {
+            id = mNm.addAutomaticZenRule(createRule("BeforeUpdate", "beforeValue",
+                    NotificationManager.INTERRUPTION_FILTER_ALARMS));
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            AutomaticZenRule updated = mNm.getAutomaticZenRule(id);
+            updated.setName("AfterUpdate");
+            updated.setConditionId(MockConditionProvider.toConditionId("afterValue"));
+            updated.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
+
+            try {
+                boolean success = mNm.updateAutomaticZenRule(id, updated);
+                if (success && updated.equals(mNm.getAutomaticZenRule(id))) {
+                    status = PASS;
+                } else {
+                    logFail();
+                    status = FAIL;
+                }
+            } catch (Exception e) {
+                logFail("update failed", e);
+                status = FAIL;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            if (id != null) {
+                mNm.removeAutomaticZenRule(id);
+            }
+            MockConditionProvider.resetData(mContext);
+            delay();
+        }
+    }
+
     private class SubscribeAutomaticZenRuleTest extends InteractiveTestCase {
         private String id = null;
         private AutomaticZenRule ruleToCreate;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index 27ad8b3..8f56cd8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Parcelable;
 import android.provider.Settings.Secure;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -38,8 +39,10 @@
 import com.android.cts.verifier.R;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.LinkedBlockingQueue;
 
 public abstract class InteractiveVerifierActivity extends PassFailButtons.Activity
@@ -123,6 +126,11 @@
             logWithStack("failed " + this.getClass().getSimpleName() +
                     ((message == null) ? "" : ": " + message));
         }
+
+        protected void logFail(String message, Exception e) {
+            Log.e(TAG, "failed " + this.getClass().getSimpleName() +
+                    ((message == null) ? "" : ": " + message), e);
+        }
     }
 
     abstract int getTitleResource();
@@ -302,6 +310,14 @@
         delay(3000);
     }
 
+    protected void sleep(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
     /**
      * Wait for some time.
      */
@@ -341,6 +357,38 @@
         return pi;
     }
 
+    protected boolean checkEquals(long[] expected, long[] actual, String message) {
+        if (Arrays.equals(expected, actual)) {
+            return true;
+        }
+        logWithStack(String.format(message, expected, actual));
+        return false;
+    }
+
+    protected boolean checkEquals(Object[] expected, Object[] actual, String message) {
+        if (Arrays.equals(expected, actual)) {
+            return true;
+        }
+        logWithStack(String.format(message, expected, actual));
+        return false;
+    }
+
+    protected boolean checkEquals(Parcelable expected, Parcelable actual, String message) {
+        if (Objects.equals(expected, actual)) {
+            return true;
+        }
+        logWithStack(String.format(message, expected, actual));
+        return false;
+    }
+
+    protected boolean checkEquals(boolean expected, boolean actual, String message) {
+        if (expected == actual) {
+            return true;
+        }
+        logWithStack(String.format(message, expected, actual));
+        return false;
+    }
+
     protected boolean checkEquals(long expected, long actual, String message) {
         if (expected == actual) {
             return true;
@@ -349,7 +397,7 @@
         return false;
     }
 
-    protected boolean checkEquals(String expected, String actual, String message) {
+    protected boolean checkEquals(CharSequence expected, CharSequence actual, String message) {
         if (expected.equals(actual)) {
             return true;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java
new file mode 100644
index 0000000..1b9c914
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java
@@ -0,0 +1,499 @@
+/*
+ * 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.notifications;
+
+import android.app.Activity;
+import android.app.NotificationChannel;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.service.notification.Adjustment;
+import android.service.notification.NotificationAssistantService;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class MockAssistant extends NotificationAssistantService {
+    static final String TAG = "MockListener";
+
+    static final String SERVICE_BASE = "android.service.notification.cts.";
+    static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
+    static final String SERVICE_ENQUEUED = SERVICE_BASE + "SERVICE_ENQUEUED";
+    static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
+    static final String SERVICE_PAYLOADS = SERVICE_BASE + "SERVICE_PAYLOADS";
+    static final String SERVICE_REMOVED = SERVICE_BASE + "SERVICE_REMOVED";
+    static final String SERVICE_REMOVED_REASON = SERVICE_BASE + "SERVICE_REMOVED_REASON";
+    static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
+    static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
+    static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
+    public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
+    public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+    public static final String SERVICE_ADJUSTMENT = SERVICE_BASE + "SERVICE_ADJUSTMENT";
+    public static final String SERVICE_CREATE_CHANNEL = SERVICE_BASE + "CREATE_CHANNEL";
+    public static final String SERVICE_UPDATE_CHANNEL = SERVICE_BASE + "UPDATE_CHANNEL";
+    public static final String SERVICE_DELETE_CHANNEL = SERVICE_BASE + "DELETE_CHANNEL";
+    public static final String SERVICE_CHECK_CHANNELS = SERVICE_BASE + "CHECK_CHANNELS";
+
+    static final String EXTRA_PAYLOAD = "PAYLOAD";
+    static final String EXTRA_INT = "INT";
+    static final String EXTRA_TAG = "TAG";
+    static final String EXTRA_CODE = "CODE";
+    static final String EXTRA_BUNDLE = "BUNDLE";
+    static final String EXTRA_PKG = "PKG";
+    static final String EXTRA_CHANNEL = "CHANNEL";
+
+    static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
+
+    public static final String KEY_FLAGS = "flag";
+    public static final String KEY_ICON = "icon";
+    public static final String KEY_ID = "id";
+    public static final String KEY_PACKAGE = "pkg";
+    public static final String KEY_WHEN = "when";
+    public static final String KEY_TAG = "tag";
+    public static final String KEY_RANK = "rank";
+    public static final String KEY_AMBIENT = "ambient";
+    public static final String KEY_MATCHES_ZEN_FILTER = "matches_zen_filter";
+    public static final String KEY_REASON = "reason";
+    public static final String KEY_PEOPLE = "people";
+    public static final String KEY_CHANNEL = "channel";
+    public static final String KEY_SNOOZE_CRITERIA = "snooze";
+
+    private ArrayList<String> mEnqueued = new ArrayList<>();
+    private ArrayList<String> mPosted = new ArrayList<>();
+    private ArrayMap<String, Bundle> mNotifications = new ArrayMap<>();
+    private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
+    private ArrayList<String> mRemoved = new ArrayList<String>();
+    private ArrayMap<String, Bundle> mRemovedReason = new ArrayMap<>();
+    private ArrayList<String> mOrder = new ArrayList<>();
+    private Set<String> mTestPackages = new HashSet<>();
+    private BroadcastReceiver mReceiver;
+    private int mDND = -1;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "created");
+
+        mTestPackages.add("com.android.cts.verifier");
+        mTestPackages.add("com.android.cts.robot");
+
+        mEnqueued = new ArrayList<String>();
+        mPosted = new ArrayList<String>();
+        mRemoved = new ArrayList<String>();
+        mRemovedReason = new ArrayMap<>();
+
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (SERVICE_CHECK.equals(action)) {
+                    Log.d(TAG, "SERVICE_CHECK");
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_ENQUEUED.equals(action)) {
+                    Log.d(TAG, "SERVICE_ENQUEUED");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mEnqueued);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_POSTED.equals(action)) {
+                    Log.d(TAG, "SERVICE_POSTED");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_DND.equals(action)) {
+                    Log.d(TAG, "SERVICE_DND");
+                    Bundle bundle = new Bundle();
+                    bundle.putInt(EXTRA_INT, mDND);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_ORDER.equals(action)) {
+                    Log.d(TAG, "SERVICE_ORDER");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_PAYLOADS.equals(action)) {
+                    Log.d(TAG, "SERVICE_PAYLOADS");
+                    Bundle bundle = new Bundle();
+                    ArrayList<Bundle> payloadData = new ArrayList<>(mNotifications.size());
+                    for (Bundle notiStats : mNotifications.values()) {
+                        payloadData.add(notiStats);
+                    }
+                    bundle.putParcelableArrayList(EXTRA_PAYLOAD, payloadData);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_REMOVED.equals(action)) {
+                    Log.d(TAG, "SERVICE_REMOVED");
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_REMOVED_REASON.equals(action)) {
+                    Log.d(TAG, "SERVICE_REMOVED_REASON");
+                    Bundle bundle = new Bundle();
+                    ArrayList<Bundle> payloadData = new ArrayList<>(mRemovedReason.size());
+                    for (Bundle notiStats : mRemovedReason.values()) {
+                        payloadData.add(notiStats);
+                    }
+                    bundle.putParcelableArrayList(EXTRA_PAYLOAD, payloadData);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_CLEAR_ONE.equals(action)) {
+                    Log.d(TAG, "SERVICE_CLEAR_ONE");
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    if (key != null) {
+                        MockAssistant.this.cancelNotification(key);
+                    } else {
+                        Log.w(TAG, "Notification does not exist: " + tag);
+                    }
+                } else if (SERVICE_CLEAR_ALL.equals(action)) {
+                    Log.d(TAG, "SERVICE_CLEAR_ALL");
+                    MockAssistant.this.cancelAllNotifications();
+                } else if (SERVICE_RESET.equals(action)) {
+                    Log.d(TAG, "SERVICE_RESET");
+                    resetData();
+                } else if (SERVICE_ADJUSTMENT.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    Bundle signals = intent.getBundleExtra(EXTRA_BUNDLE);
+                    Adjustment adjustment = new Adjustment(context.getPackageName(),
+                            key, signals, "", 0);
+                    MockAssistant.this.adjustNotification(adjustment);
+                } else if (SERVICE_CHECK_CHANNELS.equals(action)) {
+                    String pkg = intent.getStringExtra(EXTRA_PKG);
+                    Bundle bundle = new Bundle();
+                    List<NotificationChannel> channels =
+                            MockAssistant.this.getNotificationChannels(pkg);
+                    bundle.putParcelableArrayList(EXTRA_PAYLOAD,
+                            new ArrayList<NotificationChannel>(channels));
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_CREATE_CHANNEL.equals(action)) {
+                    String pkg = intent.getStringExtra(EXTRA_PKG);
+                    NotificationChannel channel = intent.getParcelableExtra(EXTRA_CHANNEL);
+                    try {
+                        MockAssistant.this.createNotificationChannel(pkg, channel);
+                    } catch (Exception e) {
+                        Log.e(TAG, "creation failed", e);
+                    }
+                } else if (SERVICE_UPDATE_CHANNEL.equals(action)) {
+                    String pkg = intent.getStringExtra(EXTRA_PKG);
+                    NotificationChannel channel = intent.getParcelableExtra(EXTRA_CHANNEL);
+                    MockAssistant.this.updateNotificationChannel(pkg, channel);
+                } else if (SERVICE_DELETE_CHANNEL.equals(action)) {
+                    String pkg = intent.getStringExtra(EXTRA_PKG);
+                    String id = intent.getStringExtra(EXTRA_TAG);
+                    MockAssistant.this.deleteNotificationChannel(pkg, id);
+                } else {
+                    Log.w(TAG, "unknown action");
+                    setResultCode(Activity.RESULT_CANCELED);
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(SERVICE_CHECK);
+        filter.addAction(SERVICE_DND);
+        filter.addAction(SERVICE_ENQUEUED);
+        filter.addAction(SERVICE_POSTED);
+        filter.addAction(SERVICE_ORDER);
+        filter.addAction(SERVICE_PAYLOADS);
+        filter.addAction(SERVICE_REMOVED);
+        filter.addAction(SERVICE_REMOVED_REASON);
+        filter.addAction(SERVICE_CLEAR_ONE);
+        filter.addAction(SERVICE_CLEAR_ALL);
+        filter.addAction(SERVICE_RESET);
+        filter.addAction(SERVICE_ADJUSTMENT);
+        filter.addAction(SERVICE_CHECK_CHANNELS);
+        filter.addAction(SERVICE_CREATE_CHANNEL);
+        filter.addAction(SERVICE_DELETE_CHANNEL);
+        filter.addAction(SERVICE_UPDATE_CHANNEL);
+        registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+        mReceiver = null;
+        Log.d(TAG, "destroyed");
+    }
+
+    @Override
+    public void onListenerConnected() {
+        super.onListenerConnected();
+        mDND = getCurrentInterruptionFilter();
+        Log.d(TAG, "initial value of CurrentInterruptionFilter is " + mDND);
+    }
+
+    @Override
+    public void onInterruptionFilterChanged(int interruptionFilter) {
+        super.onInterruptionFilterChanged(interruptionFilter);
+        mDND = interruptionFilter;
+        Log.d(TAG, "value of CurrentInterruptionFilter changed to " + mDND);
+    }
+
+    public void resetData() {
+        mEnqueued.clear();
+        mPosted.clear();
+        mNotifications.clear();
+        mRemoved.clear();
+        mRemovedReason.clear();
+        mOrder.clear();
+    }
+
+    @Override
+    public void onNotificationRankingUpdate(RankingMap rankingMap) {
+        String[] orderedKeys = rankingMap.getOrderedKeys();
+        mOrder.clear();
+        Ranking rank = new Ranking();
+        for( int i = 0; i < orderedKeys.length; i++) {
+            String key = orderedKeys[i];
+            mOrder.add(key);
+            rankingMap.getRanking(key, rank);
+            Bundle note = mNotifications.get(key);
+            if (note != null) {
+                note.putInt(KEY_RANK, rank.getRank());
+                note.putBoolean(KEY_AMBIENT, rank.isAmbient());
+                note.putBoolean(KEY_MATCHES_ZEN_FILTER, rank.matchesInterruptionFilter());
+                note.putParcelable(KEY_CHANNEL, rank.getChannel());
+                note.putStringArray(KEY_PEOPLE, rank.getAdditionalPeople() == null ? null
+                        : rank.getAdditionalPeople().toArray(new String[]{}));
+                note.putParcelableArray(KEY_SNOOZE_CRITERIA, rank.getSnoozeCriteria() == null
+                        ? null
+                        : rank.getSnoozeCriteria().toArray(new SnoozeCriterion[] {}));
+            }
+        }
+    }
+
+    @Override
+    public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
+            boolean user) {
+        if (!mTestPackages.contains(sbn.getPackageName())) { return null; }
+        Log.d(TAG, "posted: " + sbn.getTag());
+        mEnqueued.add(sbn.getTag());
+        mNotifications.put(sbn.getKey(), packNotification(sbn));
+        mNotificationKeys.put(sbn.getTag(), sbn.getKey());
+
+        return null;
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+        if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        Log.d(TAG, "posted: " + sbn.getTag());
+        mPosted.add(sbn.getTag());
+        mNotifications.put(sbn.getKey(), packNotification(sbn));
+        mNotificationKeys.put(sbn.getTag(), sbn.getKey());
+        onNotificationRankingUpdate(rankingMap);
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+        Log.d(TAG, "removed: " + sbn.getTag());
+        mRemoved.add(sbn.getTag());
+        mNotifications.remove(sbn.getKey());
+        mNotificationKeys.remove(sbn.getTag());
+        onNotificationRankingUpdate(rankingMap);
+    }
+
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+            int reason) {
+        if (!mTestPackages.contains(sbn.getPackageName())) { return; }
+        Log.d(TAG, "removed: " + sbn.getTag());
+        mRemoved.add(sbn.getTag());
+        Bundle removed = new Bundle();
+        removed.putString(KEY_TAG, sbn.getTag());
+        removed.putInt(KEY_REASON, reason);
+
+        mNotifications.remove(sbn.getKey());
+        mNotificationKeys.remove(sbn.getTag());
+        mRemovedReason.put(sbn.getTag(), removed);
+        onNotificationRankingUpdate(rankingMap);
+    }
+
+    private Bundle packNotification(StatusBarNotification sbn) {
+        Bundle notification = new Bundle();
+        notification.putString(KEY_TAG, sbn.getTag());
+        notification.putInt(KEY_ID, sbn.getId());
+        notification.putString(KEY_PACKAGE, sbn.getPackageName());
+        notification.putLong(KEY_WHEN, sbn.getNotification().when);
+        notification.putInt(KEY_ICON, sbn.getNotification().icon);
+        notification.putInt(KEY_FLAGS, sbn.getNotification().flags);
+        return notification;
+    }
+
+    public static void resetListenerData(Context context) {
+        sendCommand(context, SERVICE_RESET, null, 0);
+    }
+
+    public static void probeListenerStatus(Context context, StatusCatcher catcher) {
+        requestStatus(context, SERVICE_CHECK, catcher);
+    }
+
+    public static void probeFilter(Context context, IntegerResultCatcher catcher) {
+        requestIntegerResult(context, SERVICE_DND, catcher);
+    }
+
+    public static void probeListenerEnqueued(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_ENQUEUED, catcher);
+    }
+
+    public static void probeListenerPosted(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_POSTED, catcher);
+    }
+
+    public static void probeListenerOrder(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_ORDER, catcher);
+    }
+
+    public static void probeListenerPayloads(Context context, BundleListResultCatcher catcher) {
+        requestBundleListResult(context, SERVICE_PAYLOADS, catcher);
+    }
+
+    public static void probeListenerRemoved(Context context, StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_REMOVED, catcher);
+    }
+
+    public static void probeListenerRemovedWithReason(Context context,
+            BundleListResultCatcher catcher) {
+        requestBundleListResult(context, SERVICE_REMOVED_REASON, catcher);
+    }
+
+    public static void probeChannels(Context context, String pkg, BundleListResultCatcher catcher) {
+        Intent broadcast = new Intent(SERVICE_CHECK_CHANNELS);
+        broadcast.putExtra(EXTRA_PKG, pkg);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public static void clearOne(Context context, String tag, int code) {
+        sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
+    }
+
+    public static void clearAll(Context context) {
+        sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
+    }
+
+    public static void createChannel(Context context, String pkg, NotificationChannel channel) {
+        Intent broadcast = new Intent(SERVICE_CREATE_CHANNEL);
+        broadcast.putExtra(EXTRA_PKG, pkg);
+        broadcast.putExtra(EXTRA_CHANNEL, channel);
+        context.sendBroadcast(broadcast);
+    }
+
+    public static void updateChannel(Context context, String pkg, NotificationChannel channel) {
+        Intent broadcast = new Intent(SERVICE_UPDATE_CHANNEL);
+        broadcast.putExtra(EXTRA_PKG, pkg);
+        broadcast.putExtra(EXTRA_CHANNEL, channel);
+        context.sendBroadcast(broadcast);
+    }
+
+    public static void deleteChannel(Context context, String pkg, String id) {
+        Intent broadcast = new Intent(SERVICE_DELETE_CHANNEL);
+        broadcast.putExtra(EXTRA_PKG, pkg);
+        broadcast.putExtra(EXTRA_TAG, id);
+        context.sendBroadcast(broadcast);
+    }
+
+    public static void applyAdjustment(Context context, String tag, Bundle signals) {
+        Intent broadcast = new Intent(SERVICE_ADJUSTMENT);
+        broadcast.putExtra(EXTRA_TAG, tag);
+        broadcast.putExtra(EXTRA_BUNDLE, signals);
+        context.sendBroadcast(broadcast);
+    }
+
+    private static void sendCommand(Context context, String action, String tag, int code) {
+        Intent broadcast = new Intent(action);
+        if (tag != null) {
+            broadcast.putExtra(EXTRA_TAG, tag);
+            broadcast.putExtra(EXTRA_CODE, code);
+        }
+        context.sendBroadcast(broadcast);
+    }
+
+    public abstract static class StatusCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(Integer.valueOf(getResultCode()));
+        }
+
+        abstract public void accept(int result);
+    }
+
+    private static void requestStatus(Context context, String action,
+            StatusCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public abstract static class IntegerResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getInt(EXTRA_INT, -1));
+        }
+
+        abstract public void accept(int result);
+    }
+
+    private static void requestIntegerResult(Context context, String action,
+            IntegerResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+    public abstract static class StringListResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getStringArrayList(EXTRA_PAYLOAD));
+        }
+
+        abstract public void accept(List<String> result);
+    }
+
+    private static void requestStringListResult(Context context, String action,
+            StringListResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+
+
+    public abstract static class BundleListResultCatcher extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            accept(getResultExtras(true).getParcelableArrayList(EXTRA_PAYLOAD));
+        }
+
+        abstract public void accept(ArrayList<Parcelable> result);
+    }
+
+    private static void requestBundleListResult(Context context, String action,
+            BundleListResultCatcher catcher) {
+        Intent broadcast = new Intent(action);
+        context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index c80f371..6c294e5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -17,6 +17,7 @@
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -38,23 +39,33 @@
 public class MockListener extends NotificationListenerService {
     static final String TAG = "MockListener";
 
+    public static final ComponentName COMPONENT_NAME =
+            new ComponentName("com.android.cts.verifier", MockListener.class.getName());
+
     static final String SERVICE_BASE = "android.service.notification.cts.";
     static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
     static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
     static final String SERVICE_PAYLOADS = SERVICE_BASE + "SERVICE_PAYLOADS";
     static final String SERVICE_REMOVED = SERVICE_BASE + "SERVICE_REMOVED";
+    static final String SERVICE_REMOVED_REASON = SERVICE_BASE + "SERVICE_REMOVED";
     static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
     static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
     static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
-    public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
-    public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+    static final String SERVICE_SNOOZE = SERVICE_BASE + "SERVICE_SNOOZE";
+    static final String SERVICE_HINTS = SERVICE_BASE + "SERVICE_HINTS";
+    static final String SERVICE_PROBE_HINTS = SERVICE_BASE + "SERVICE_PROBE_HINTS";
+    static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
+    static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+    static final String SERVICE_SNOOZE_ONE = SERVICE_BASE + "SERVICE_SNOOZE_ONE";
+    static final String SERVICE_UNSNOOZE_ONE = SERVICE_BASE + "SERVICE_UNSNOOZE_ONE";
+    static final String SERVICE_SNOOZE_UNTIL = SERVICE_BASE + "SERVICE_SNOOZE_UNTIL";
 
     static final String EXTRA_PAYLOAD = "PAYLOAD";
     static final String EXTRA_INT = "INT";
     static final String EXTRA_TAG = "TAG";
     static final String EXTRA_CODE = "CODE";
+    static final String EXTRA_LONG = "LONG";
 
-    static final int RESULT_TIMEOUT = Activity.RESULT_FIRST_USER;
     static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
 
     public static final String JSON_FLAGS = "flag";
@@ -66,11 +77,14 @@
     public static final String JSON_RANK = "rank";
     public static final String JSON_AMBIENT = "ambient";
     public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter";
+    public static final String JSON_REASON = "reason";
+    public static final String JSON_HINTS = "hints";
 
     private ArrayList<String> mPosted = new ArrayList<String>();
     private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
     private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
     private ArrayList<String> mRemoved = new ArrayList<String>();
+    private ArrayMap<String, JSONObject> mRemovedReason = new ArrayMap<>();
     private ArrayList<String> mOrder = new ArrayList<>();
     private Set<String> mTestPackages = new HashSet<>();
     private BroadcastReceiver mReceiver;
@@ -90,31 +104,24 @@
         mReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
+                final String action = intent.getAction();
+                final Bundle bundle = new Bundle();
+                Log.d(TAG, action);
                 if (SERVICE_CHECK.equals(action)) {
-                    Log.d(TAG, "SERVICE_CHECK");
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_POSTED.equals(action)) {
-                    Log.d(TAG, "SERVICE_POSTED");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_DND.equals(action)) {
-                    Log.d(TAG, "SERVICE_DND");
-                    Bundle bundle = new Bundle();
                     bundle.putInt(EXTRA_INT, mDND);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_ORDER.equals(action)) {
-                    Log.d(TAG, "SERVICE_ORDER");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_PAYLOADS.equals(action)) {
-                    Log.d(TAG, "SERVICE_PAYLOADS");
-                    Bundle bundle = new Bundle();
                     ArrayList<String> payloadData = new ArrayList<>(mNotifications.size());
                     for (JSONObject payload: mNotifications.values()) {
                         payloadData.add(payload.toString());
@@ -123,13 +130,18 @@
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_REMOVED.equals(action)) {
-                    Log.d(TAG, "SERVICE_REMOVED");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_REMOVED_REASON.equals(action)) {
+                    ArrayList<String> payloadData = new ArrayList<>(mRemovedReason.size());
+                    for (JSONObject payload: mRemovedReason.values()) {
+                        payloadData.add(payload.toString());
+                    }
+                    bundle.putStringArrayList(EXTRA_PAYLOAD, payloadData);
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_CLEAR_ONE.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ONE");
                     String tag = intent.getStringExtra(EXTRA_TAG);
                     String key = mNotificationKeys.get(tag);
                     if (key != null) {
@@ -138,11 +150,30 @@
                         Log.w(TAG, "Notification does not exist: " + tag);
                     }
                 } else if (SERVICE_CLEAR_ALL.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ALL");
                     MockListener.this.cancelAllNotifications();
                 } else if (SERVICE_RESET.equals(action)) {
-                    Log.d(TAG, "SERVICE_RESET");
                     resetData();
+                } else if (SERVICE_SNOOZE.equals(action)) {
+                    MockListener.this.requestUnbind();
+                } else if (SERVICE_HINTS.equals(action)) {
+                    MockListener.this.requestListenerHints(intent.getIntExtra(EXTRA_CODE, 0));
+                } else if (SERVICE_PROBE_HINTS.equals(action)) {
+                    bundle.putInt(EXTRA_INT, MockListener.this.getCurrentListenerHints());
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_SNOOZE_ONE.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.snoozeNotification(key);
+                } else if (SERVICE_UNSNOOZE_ONE.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.unsnoozeNotification(key);
+                } else if (SERVICE_SNOOZE_UNTIL.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.snoozeNotification(key,
+                            intent.getLongExtra(EXTRA_LONG, (long) 0));
                 } else {
                     Log.w(TAG, "unknown action");
                     setResultCode(Activity.RESULT_CANCELED);
@@ -156,9 +187,16 @@
         filter.addAction(SERVICE_ORDER);
         filter.addAction(SERVICE_PAYLOADS);
         filter.addAction(SERVICE_REMOVED);
+        filter.addAction(SERVICE_REMOVED_REASON);
         filter.addAction(SERVICE_CLEAR_ONE);
         filter.addAction(SERVICE_CLEAR_ALL);
         filter.addAction(SERVICE_RESET);
+        filter.addAction(SERVICE_SNOOZE);
+        filter.addAction(SERVICE_HINTS);
+        filter.addAction(SERVICE_PROBE_HINTS);
+        filter.addAction(SERVICE_SNOOZE_ONE);
+        filter.addAction(SERVICE_UNSNOOZE_ONE);
+        filter.addAction(SERVICE_SNOOZE_UNTIL);
         registerReceiver(mReceiver, filter);
     }
 
@@ -189,6 +227,7 @@
         mNotifications.clear();
         mRemoved.clear();
         mOrder.clear();
+        mRemovedReason.clear();
     }
 
     @Override
@@ -243,6 +282,24 @@
         onNotificationRankingUpdate(rankingMap);
     }
 
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
+            int reason) {
+        Log.d(TAG, "removed: " + sbn.getTag());
+        mRemoved.add(sbn.getTag());
+        JSONObject removed = new JSONObject();
+        try {
+            removed.put(JSON_TAG, sbn.getTag());
+            removed.put(JSON_REASON, reason);
+        } catch (JSONException e) {
+            Log.e(TAG, "failed to pack up notification payload", e);
+        }
+        mNotifications.remove(sbn.getKey());
+        mNotificationKeys.remove(sbn.getTag());
+        mRemovedReason.put(sbn.getTag(), removed);
+        onNotificationRankingUpdate(rankingMap);
+    }
+
     public static void resetListenerData(Context context) {
         sendCommand(context, SERVICE_RESET, null, 0);
     }
@@ -271,10 +328,46 @@
         requestStringListResult(context, SERVICE_REMOVED, catcher);
     }
 
+    public static void probeListenerRemovedWithReason(Context context,
+            StringListResultCatcher catcher) {
+        requestStringListResult(context, SERVICE_REMOVED_REASON, catcher);
+    }
+
+    public static void probeListenerHints(Context context, IntegerResultCatcher catcher) {
+        requestIntegerResult(context, SERVICE_PROBE_HINTS, catcher);
+    }
+
+    public static void setHints(Context context, int hints) {
+        Intent broadcast = new Intent(SERVICE_HINTS);
+        broadcast.putExtra(EXTRA_CODE, hints);
+        context.sendBroadcast(broadcast);
+    }
+
+    public static void snooze(Context context) {
+        sendCommand(context, SERVICE_SNOOZE, null, 0);
+    }
+
     public static void clearOne(Context context, String tag, int code) {
         sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
     }
 
+    public static void snoozeOne(Context context, String tag) {
+        sendCommand(context, SERVICE_SNOOZE_ONE, tag, 0);
+    }
+
+    public static void unsnoozeOne(Context context, String tag) {
+        sendCommand(context, SERVICE_UNSNOOZE_ONE, tag, 0);
+    }
+
+    public static void snoozeOneUntil(Context context, String tag, long until) {
+        Intent broadcast = new Intent(SERVICE_SNOOZE_UNTIL);
+        if (tag != null) {
+            broadcast.putExtra(EXTRA_TAG, tag);
+            broadcast.putExtra(EXTRA_LONG, until);
+        }
+        context.sendBroadcast(broadcast);
+    }
+
     public static void clearAll(Context context) {
         sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java
new file mode 100644
index 0000000..02b4edf
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java
@@ -0,0 +1,1073 @@
+/*
+ * 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.notifications;
+
+import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
+
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_CHANNEL;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_FLAGS;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_ICON;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_ID;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_PACKAGE;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_PEOPLE;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_REASON;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_SNOOZE_CRITERIA;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_TAG;
+import static com.android.cts.verifier.notifications.MockAssistant.KEY_WHEN;
+import static com.android.cts.verifier.notifications.MockAssistant.StatusCatcher;
+import static com.android.cts.verifier.notifications.MockAssistant.StringListResultCatcher;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.service.notification.Adjustment;
+import android.service.notification.SnoozeCriterion;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+public class NotificationAssistantVerifierActivity extends InteractiveVerifierActivity
+        implements Runnable {
+    private static final String TAG = "NoAssistantVerifier";
+
+    protected static final String ASSISTANT_PATH = "com.android.cts.verifier/" +
+            "com.android.cts.verifier.notifications.MockAssistant";
+    private static final String ENABLED_NOTIFICATION_ASSISTANT_SETTING =
+            "enabled_notification_assistant";
+    private static final String OTHER_PKG = "android";
+
+    private String mTag1;
+    private String mTag2;
+    private String mTag3;
+    private int mIcon1;
+    private int mIcon2;
+    private int mIcon3;
+    private int mId1;
+    private int mId2;
+    private int mId3;
+    private long mWhen1;
+    private long mWhen2;
+    private long mWhen3;
+    private int mFlag1;
+    private int mFlag2;
+    private int mFlag3;
+
+    @Override
+    int getTitleResource() {
+        return R.string.nas_test;
+    }
+
+    @Override
+    int getInstructionsResource() {
+        return R.string.nas_info;
+    }
+
+    // Test Setup
+
+    @Override
+    protected List<InteractiveTestCase> createTestItems() {
+        List<InteractiveTestCase> tests = new ArrayList<>();
+        tests.add(new IsEnabledTest());
+        tests.add(new ServiceStartedTest());
+        tests.add(new NotificationEnqueuedTest());
+        tests.add(new NotificationReceivedTest());
+        tests.add(new DataIntactTest());
+        tests.add(new DismissOneTest());
+        tests.add(new DismissOneWithReasonTest());
+        tests.add(new DismissAllTest());
+        tests.add(new AdjustNotificationTest());
+        tests.add(new CreateChannelTest());
+        tests.add(new UpdateChannelTest());
+        tests.add(new DeleteChannelTest());
+        tests.add(new IsDisabledTest());
+        tests.add(new ServiceStoppedTest());
+        tests.add(new NotificationNotEnqueuedTest());
+        tests.add(new NotificationNotReceivedTest());
+        return tests;
+    }
+
+    @SuppressLint("NewApi")
+    private void sendNotifications() {
+        sendNotifications(null);
+    }
+
+    @SuppressLint("NewApi")
+    private void sendNotifications(NotificationChannel channel) {
+        mTag1 = UUID.randomUUID().toString();
+        mTag2 = UUID.randomUUID().toString();
+        mTag3 = UUID.randomUUID().toString();
+
+        mNm.cancelAll();
+
+        mWhen1 = System.currentTimeMillis() + 1;
+        mWhen2 = System.currentTimeMillis() + 2;
+        mWhen3 = System.currentTimeMillis() + 3;
+
+        mIcon1 = R.drawable.ic_stat_alice;
+        mIcon2 = R.drawable.ic_stat_bob;
+        mIcon3 = R.drawable.ic_stat_charlie;
+
+        mId1 = NOTIFICATION_ID + 1;
+        mId2 = NOTIFICATION_ID + 2;
+        mId3 = NOTIFICATION_ID + 3;
+
+        mPackageString = "com.android.cts.verifier";
+
+        Notification n1 = new Notification.Builder(mContext)
+                .setContentTitle("ClearTest 1")
+                .setContentText(mTag1.toString())
+                .setPriority(Notification.PRIORITY_LOW)
+                .setSmallIcon(mIcon1)
+                .setWhen(mWhen1)
+                .setDeleteIntent(makeIntent(1, mTag1))
+                .setOnlyAlertOnce(true)
+                .setChannel(channel == null ? NotificationChannel.DEFAULT_CHANNEL_ID
+                        : channel.getId())
+                .build();
+        mNm.notify(mTag1, mId1, n1);
+        mFlag1 = Notification.FLAG_ONLY_ALERT_ONCE;
+
+        Notification n2 = new Notification.Builder(mContext)
+                .setContentTitle("ClearTest 2")
+                .setContentText(mTag2.toString())
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setSmallIcon(mIcon2)
+                .setWhen(mWhen2)
+                .setDeleteIntent(makeIntent(2, mTag2))
+                .setAutoCancel(true)
+                .setChannel(channel == null ? NotificationChannel.DEFAULT_CHANNEL_ID
+                        : channel.getId())
+                .build();
+        mNm.notify(mTag2, mId2, n2);
+        mFlag2 = Notification.FLAG_AUTO_CANCEL;
+
+        Notification n3 = new Notification.Builder(mContext)
+                .setContentTitle("ClearTest 3")
+                .setContentText(mTag3.toString())
+                .setPriority(Notification.PRIORITY_LOW)
+                .setSmallIcon(mIcon3)
+                .setWhen(mWhen3)
+                .setDeleteIntent(makeIntent(3, mTag3))
+                .setAutoCancel(true)
+                .setOnlyAlertOnce(true)
+                .setChannel(channel == null ? NotificationChannel.DEFAULT_CHANNEL_ID
+                        : channel.getId())
+                .build();
+        mNm.notify(mTag3, mId3, n3);
+        mFlag3 = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL;
+    }
+
+    // Tests
+
+    protected class IsEnabledTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createSettingsItem(parent, R.string.nas_enable_service);
+        }
+
+        @Override
+        boolean autoStart() {
+            return true;
+        }
+
+        @Override
+        void test() {
+            mNm.cancelAll();
+            Intent settings = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
+            if (settings.resolveActivity(mPackageManager) == null) {
+                logFail("no settings activity");
+                status = FAIL;
+            } else {
+                String listeners = Secure.getString(getContentResolver(),
+                        ENABLED_NOTIFICATION_ASSISTANT_SETTING);
+                if (listeners != null && listeners.equals(ASSISTANT_PATH)) {
+                    status = PASS;
+                } else {
+                    status = WAIT_FOR_USER;
+                }
+                next();
+            }
+        }
+
+        void tearDown() {
+            // wait for the service to start
+            delay();
+        }
+    }
+
+    protected class ServiceStartedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_service_started);
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerStatus(mContext,
+                    new MockAssistant.StatusCatcher() {
+                        @Override
+                        public void accept(int result) {
+                            if (result == Activity.RESULT_OK) {
+                                status = PASS;
+                                next();
+                            } else {
+                                logFail();
+                                status = RETEST;
+                                delay();
+                            }
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class NotificationEnqueuedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_note_enqueued_received);
+
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            // wait for notifications to move through the system
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerEnqueued(mContext,
+                    new StringListResultCatcher() {
+                        @Override
+                        public void accept(List<String> result) {
+                            if (result != null && result.size() > 0 && result.contains(mTag1)) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = FAIL;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+    }
+
+    private class NotificationReceivedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_note_received);
+
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            // wait for notifications to move through the system
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerPosted(mContext,
+                    new StringListResultCatcher() {
+                        @Override
+                        public void accept(List<String> result) {
+                            if (result != null && result.size() > 0 && result.contains(mTag1)) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = FAIL;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+    }
+
+    private class DataIntactTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_payload_intact);
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerPayloads(mContext,
+                    new MockAssistant.BundleListResultCatcher() {
+                        @Override
+                        public void accept(ArrayList<Parcelable> result) {
+                            Set<String> found = new HashSet<String>();
+                            if (result == null || result.size() == 0) {
+                                status = FAIL;
+                                return;
+                            }
+                            boolean pass = true;
+                            for (Parcelable payloadData : result) {
+                                Bundle payload = (Bundle) payloadData;
+                                pass &= checkEquals(mPackageString,
+                                        payload.getString(KEY_PACKAGE),
+                                        "data integrity test: notification package (%s, %s)");
+                                String tag = payload.getString(KEY_TAG);
+                                if (mTag1.equals(tag)) {
+                                    found.add(mTag1);
+                                    pass &= checkEquals(mIcon1, payload.getInt(KEY_ICON),
+                                            "data integrity test: notification icon (%d, %d)");
+                                    pass &= checkFlagSet(mFlag1, payload.getInt(KEY_FLAGS),
+                                            "data integrity test: notification flags (%d, %d)");
+                                    pass &= checkEquals(mId1, payload.getInt(KEY_ID),
+                                            "data integrity test: notification ID (%d, %d)");
+                                    pass &= checkEquals(mWhen1, payload.getLong(KEY_WHEN),
+                                            "data integrity test: notification when (%d, %d)");
+                                } else if (mTag2.equals(tag)) {
+                                    found.add(mTag2);
+                                    pass &= checkEquals(mIcon2, payload.getInt(KEY_ICON),
+                                            "data integrity test: notification icon (%d, %d)");
+                                    pass &= checkFlagSet(mFlag2, payload.getInt(KEY_FLAGS),
+                                            "data integrity test: notification flags (%d, %d)");
+                                    pass &= checkEquals(mId2, payload.getInt(KEY_ID),
+                                            "data integrity test: notification ID (%d, %d)");
+                                    pass &= checkEquals(mWhen2, payload.getLong(KEY_WHEN),
+                                            "data integrity test: notification when (%d, %d)");
+                                } else if (mTag3.equals(tag)) {
+                                    found.add(mTag3);
+                                    pass &= checkEquals(mIcon3, payload.getInt(KEY_ICON),
+                                            "data integrity test: notification icon (%d, %d)");
+                                    pass &= checkFlagSet(mFlag3, payload.getInt(KEY_FLAGS),
+                                            "data integrity test: notification flags (%d, %d)");
+                                    pass &= checkEquals(mId3, payload.getInt(KEY_ID),
+                                            "data integrity test: notification ID (%d, %d)");
+                                    pass &= checkEquals(mWhen3, payload.getLong(KEY_WHEN),
+                                            "data integrity test: notification when (%d, %d)");
+                                } else {
+                                    pass = false;
+                                    logFail("unexpected notification tag: " + tag);
+                                }
+                            }
+
+                            pass &= found.size() == 3;
+                            status = pass ? PASS : FAIL;
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class DismissOneTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_clear_one);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.clearOne(mContext, mTag1, mId1);
+                status = RETEST;
+            } else {
+                MockAssistant.probeListenerRemoved(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)
+                                        && !result.contains(mTag2)
+                                        && !result.contains(mTag3)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class DismissOneWithReasonTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_clear_one_reason);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.clearOne(mContext, mTag2, mId2);
+                status = RETEST;
+            } else {
+                MockAssistant.probeListenerRemovedWithReason(mContext,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (Parcelable payloadData : result) {
+                                    Bundle payload = (Bundle) payloadData;
+                                    pass &= checkEquals(mTag2,
+                                            payload.getString(KEY_TAG),
+                                            "data dismissal test: notification tag (%s, %s)");
+                                    pass &= checkEquals(REASON_LISTENER_CANCEL,
+                                            payload.getInt(KEY_REASON),
+                                            "data dismissal test: reason (%d, %d)");
+                                }
+                                status = pass ? PASS : FAIL;
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class DismissAllTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_clear_all);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.clearAll(mContext);
+                status = RETEST;
+            } else {
+                MockAssistant.probeListenerRemoved(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)
+                                        && result.contains(mTag2)
+                                        && result.contains(mTag3)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class IsDisabledTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createSettingsItem(parent, R.string.nas_disable_service);
+        }
+
+        @Override
+        boolean autoStart() {
+            return true;
+        }
+
+        @Override
+        void test() {
+            String listeners = Secure.getString(getContentResolver(),
+                    ENABLED_NOTIFICATION_ASSISTANT_SETTING);
+            if (listeners == null || !listeners.equals(ASSISTANT_PATH)) {
+                status = PASS;
+            } else {
+                status = WAIT_FOR_USER;
+            }
+            next();
+        }
+
+        @Override
+        void tearDown() {
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class ServiceStoppedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_service_stopped);
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerStatus(mContext,
+                    new StatusCatcher() {
+                        @Override
+                        public void accept(int result) {
+                            if (result == Activity.RESULT_OK) {
+                                logFail();
+                                status = FAIL;
+                            } else {
+                                status = PASS;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            // wait for intent to move through the system
+            delay();
+        }
+    }
+
+    private class NotificationNotEnqueuedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_note_missed_enqueued);
+
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerEnqueued(mContext,
+                    new StringListResultCatcher() {
+                        @Override
+                        public void accept(List<String> result) {
+                            if (result == null || result.size() == 0) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = FAIL;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class NotificationNotReceivedTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_note_missed);
+
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeListenerPosted(mContext,
+                    new StringListResultCatcher() {
+                        @Override
+                        public void accept(List<String> result) {
+                            if (result == null || result.size() == 0) {
+                                status = PASS;
+                            } else {
+                                logFail();
+                                status = FAIL;
+                            }
+                            next();
+                        }
+                    });
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class AdjustNotificationTest extends InteractiveTestCase {
+        private Bundle bundle1 = new Bundle();
+        private Bundle bundle2 = new Bundle();
+        private Bundle bundle3 = new Bundle();
+        private SnoozeCriterion snooze1 = new SnoozeCriterion("id1", "1", "2");
+        private SnoozeCriterion snooze2 = new SnoozeCriterion("id2", "2", "3");
+        private String people1 = "people1";
+        private String people2 = "people2";
+        private ArrayList<String> people;
+        private ArrayList<SnoozeCriterion> snooze;
+        private NotificationChannel originalChannel = new NotificationChannel("new", "new",
+                NotificationManager.IMPORTANCE_LOW);
+        private NotificationChannel newChannel = new NotificationChannel("new", "new",
+                NotificationManager.IMPORTANCE_LOW);
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_adjustment_payload_intact);
+        }
+
+        @Override
+        void setUp() {
+            try {
+                mNm.createNotificationChannel(newChannel, (createdChannel) -> {}, null);
+                mNm.createNotificationChannel(originalChannel, (createdChannel) -> {}, null);
+            } catch (Exception e) {
+
+            }
+            sendNotifications(originalChannel);
+            status = READY;
+            bundle1.putString(Adjustment.KEY_CHANNEL_ID, newChannel.getId());
+            people = new ArrayList<>();
+            people.add(people1);
+            people.add(people2);
+            bundle2.putStringArrayList(Adjustment.KEY_PEOPLE, people);
+            snooze = new ArrayList<>();
+            snooze.add(snooze1);
+            snooze.add(snooze2);
+            bundle3.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, snooze);
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.applyAdjustment(mContext, mTag1, bundle1);
+                MockAssistant.applyAdjustment(mContext, mTag2, bundle2);
+                MockAssistant.applyAdjustment(mContext, mTag3, bundle3);
+                status = RETEST;
+            } else {
+                MockAssistant.probeListenerPayloads(mContext,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                Set<String> found = new HashSet<>();
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (Parcelable payloadData : result) {
+                                    Bundle payload = (Bundle) payloadData;
+                                    pass &= checkEquals(mPackageString,
+                                            payload.getString(KEY_PACKAGE),
+                                            "data integrity test: notification package (%s, %s)");
+
+                                    String tag = payload.getString(KEY_TAG);
+                                    if (mTag1.equals(tag)) {
+                                        found.add(mTag1);
+                                        pass &= checkEquals(newChannel,
+                                                payload.getParcelable(KEY_CHANNEL),
+                                                "data integrity test: notification channel ("
+                                                        + "%s, %s)");
+                                        pass &= checkEquals(null,
+                                                payload.getStringArray(KEY_PEOPLE),
+                                                "data integrity test, notification people ("
+                                                        + "%s, %s)");
+                                        pass &= checkEquals(null,
+                                                payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+                                                "data integrity test, notification snooze ("
+                                                        + "%s, %s)");
+                                    } else if (mTag2.equals(tag)) {
+                                        found.add(mTag2);
+                                        pass &= checkEquals(originalChannel,
+                                                payload.getParcelable(KEY_CHANNEL),
+                                                "data integrity test: notification channel ("
+                                                        + "%s, %s)");
+                                        pass &= checkEquals(people.toArray(new String[]{}),
+                                                payload.getStringArray(KEY_PEOPLE),
+                                                "data integrity test, notification people ("
+                                                        + "%s, %s)");
+                                        pass &= checkEquals(null,
+                                                payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+                                                "data integrity test, notification snooze ("
+                                                        + "%s, %s)");
+                                    } else if (mTag3.equals(tag)) {
+                                        found.add(mTag3);
+                                        pass &= checkEquals(originalChannel,
+                                                payload.getParcelable(KEY_CHANNEL),
+                                                "data integrity test: notification channel ("
+                                                        + "%s, %s)");
+                                        pass &= checkEquals(null,
+                                                payload.getStringArray(KEY_PEOPLE),
+                                                "data integrity test, notification people ("
+                                                        + "%s, %s)");;
+                                        pass &= checkEquals(snooze.toArray(new SnoozeCriterion[]{}),
+                                                payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+                                                "data integrity test, notification snooze ("
+                                                        + "%s, %s)");
+                                    } else {
+                                        pass = false;
+                                        logFail("unexpected notification tag: " + tag);
+                                    }
+                                }
+
+                                pass &= found.size() == 3;
+                                status = pass ? PASS : FAIL;
+                                next();
+                            }
+                        });
+            }
+            delay(6000);  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            mNm.deleteNotificationChannel(originalChannel.getId());
+            mNm.deleteNotificationChannel(newChannel.getId());
+            sleep(1000);
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class CreateChannelTest extends InteractiveTestCase {
+        private NotificationChannel channel = new NotificationChannel("channelForOtherPkg", "new",
+                NotificationManager.IMPORTANCE_LOW);
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_create_channel);
+        }
+
+        @Override
+        void setUp() {
+            MockAssistant.createChannel(mContext, OTHER_PKG, channel);
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            MockAssistant.probeChannels(mContext, OTHER_PKG,
+                    new MockAssistant.BundleListResultCatcher() {
+                        @Override
+                        public void accept(ArrayList<Parcelable> result) {
+                            if (result == null || result.size() == 0) {
+                                logFail(result == null ? "no results"
+                                        : String.format("%d results returned", result.size()));
+                                status = FAIL;
+                                return;
+                            }
+                            boolean pass = false;
+                            for (Parcelable payloadData : result) {
+                                NotificationChannel payload = (NotificationChannel) payloadData;
+                                pass |= compareChannels(payload, channel);
+                            }
+                            status = pass ? PASS : FAIL;
+                            next();
+                        }
+                    });
+
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockAssistant.deleteChannel(
+                    mContext, OTHER_PKG, channel.getId());
+            delay();
+        }
+    }
+
+    private class DeleteChannelTest extends InteractiveTestCase {
+        private NotificationChannel channel = new NotificationChannel("1channelForOtherPkg", "new",
+                NotificationManager.IMPORTANCE_LOW);
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_delete_channel);
+        }
+
+        @Override
+        void setUp() {
+            MockAssistant.createChannel(mContext, OTHER_PKG, channel);
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.probeChannels(mContext, OTHER_PKG,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = false;
+                                for (Parcelable payloadData : result) {
+                                    NotificationChannel payload = (NotificationChannel) payloadData;
+                                    pass |= compareChannels(channel, payload);
+                                }
+                                if (pass) {
+                                    MockAssistant.deleteChannel(
+                                            mContext, OTHER_PKG, channel.getId());
+                                    status = RETEST;
+                                }
+                            }
+                        });
+            } else if (status == RETEST) {
+                MockAssistant.probeChannels(mContext, OTHER_PKG,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                if (result == null || result.size() <= 1) {
+                                    status = PASS;
+                                } else {
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockAssistant.deleteChannel(
+                    mContext, OTHER_PKG, channel.getId());
+            delay();
+        }
+    }
+
+    private class UpdateChannelTest extends InteractiveTestCase {
+        private String id = "channelToUpdate";
+        private NotificationChannel channel = new NotificationChannel(id, "new",
+                NotificationManager.IMPORTANCE_LOW);
+        private NotificationChannel updatedChannel = new NotificationChannel(id, "new",
+                NotificationManager.IMPORTANCE_MIN);
+
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nas_update_channel);
+        }
+
+        @Override
+        void setUp() {
+            updatedChannel.setVibrationPattern(new long[] {467, 2478, 24738});
+            updatedChannel.setSound(new Uri.Builder().appendPath("sound").build());
+            updatedChannel.setLights(true);
+            updatedChannel.enableVibration(true);
+            updatedChannel.setBypassDnd(true);
+            updatedChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+            MockAssistant.createChannel(mContext, OTHER_PKG, channel);
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockAssistant.probeChannels(mContext, OTHER_PKG,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                }
+                                boolean pass = false;
+                                for (Parcelable payloadData : result) {
+                                    NotificationChannel payload = (NotificationChannel) payloadData;
+                                    pass |= compareChannels(channel, payload);
+                                }
+                                if (pass) {
+                                    MockAssistant.updateChannel(
+                                            mContext, OTHER_PKG, updatedChannel);
+                                    status = RETEST;
+                                } else {
+                                    status = FAIL;
+                                    next();
+                                }
+                            }
+                        });
+            } else if (status == RETEST) {
+                MockAssistant.probeChannels(mContext, OTHER_PKG,
+                        new MockAssistant.BundleListResultCatcher() {
+                            @Override
+                            public void accept(ArrayList<Parcelable> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                }
+                                boolean pass = false;
+                                for (Parcelable payloadData : result) {
+                                    NotificationChannel payload = (NotificationChannel) payloadData;
+                                    pass |= compareChannels(updatedChannel, payload);
+                                }
+                                status = pass ? PASS : FAIL;
+                                next();
+                            }
+                        });
+            }
+
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            MockAssistant.deleteChannel(
+                    mContext, OTHER_PKG, channel.getId());
+            delay();
+        }
+    }
+
+    private boolean compareChannels(NotificationChannel expected, NotificationChannel actual) {
+        boolean pass = true;
+        String msg = "Channel mismatch (%s, %s)";
+        if (actual == null || expected == null) {
+            logWithStack(String.format("Channel mismatch (%s, %s)", expected, actual));
+            return false;
+        }
+        pass &= checkEquals(expected.getId(), actual.getId(), msg);
+        pass &= checkEquals(expected.getName(), actual.getName(), msg);
+        pass &= checkEquals(expected.shouldVibrate(), actual.shouldVibrate(), msg);
+        pass &= checkEquals(expected.shouldShowLights(), actual.shouldShowLights(), msg);
+        pass &= checkEquals(expected.getImportance(), actual.getImportance(), msg);
+        pass &= checkEquals(
+                expected.getLockscreenVisibility(), actual.getLockscreenVisibility(), msg);
+        pass &= checkEquals(expected.getSound(), actual.getSound(), msg);
+        pass &= checkEquals(expected.canBypassDnd(), actual.canBypassDnd(), msg);
+        pass &= checkEquals(expected.getVibrationPattern(), actual.getVibrationPattern(), msg);
+        return pass;
+    }
+
+    protected View createSettingsItem(ViewGroup parent, int messageId) {
+        return createUserItem(parent, R.string.nls_start_settings, messageId);
+    }
+
+    @Override
+    public void launchSettings() {
+        startActivity(new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS));
+    }
+
+    @Override
+    public void actionPressed(View v) {
+        Object tag = v.getTag();
+        if (tag instanceof Integer) {
+            int id = ((Integer) tag).intValue();
+            if (id == R.string.nls_start_settings) {
+                launchSettings();
+            } else if (id == R.string.attention_ready) {
+                mCurrentTest.status = READY;
+                next();
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index ace194c..fe23fe0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -77,7 +77,15 @@
         tests.add(new NotificationRecievedTest());
         tests.add(new DataIntactTest());
         tests.add(new DismissOneTest());
+        tests.add(new DismissOneWithReasonTest());
         tests.add(new DismissAllTest());
+        tests.add(new SnoozeNotificationTest());
+        tests.add(new UnsnoozeNotificationTest());
+        tests.add(new SnoozeNotificationForTimeTest());
+        tests.add(new EnableHintsTest());
+        tests.add(new SnoozeTest());
+        tests.add(new UnsnoozeTest());
+        tests.add(new EnableHintsTest());
         tests.add(new IsDisabledTest());
         tests.add(new ServiceStoppedTest());
         tests.add(new NotificationNotReceivedTest());
@@ -308,6 +316,64 @@
         }
     }
 
+    private class DismissOneWithReasonTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_clear_one_reason);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.clearOne(mContext, mTag1, mId1);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerRemovedWithReason(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (String payloadData : result) {
+                                    JSONObject payload = null;
+                                    try {
+                                        payload = new JSONObject(payloadData);
+                                        pass &= checkEquals(mTag1,
+                                                payload.getString(JSON_TAG),
+                                                "data dismissal test: notification tag (%s, %s)");
+                                        pass &= checkEquals(REASON_LISTENER_CANCEL,
+                                                payload.getInt(JSON_TAG),
+                                                "data dismissal test: reason (%d, %d)");
+                                    } catch (JSONException e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                                status = pass ? PASS : FAIL;
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            MockAssistant.resetListenerData(mContext);
+            delay();
+        }
+    }
+
     private class DismissAllTest extends InteractiveTestCase {
         @Override
         View inflate(ViewGroup parent) {
@@ -367,6 +433,12 @@
         }
 
         @Override
+        void setUp(){
+            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+            delay();
+        }
+
+        @Override
         void test() {
             String listeners = Secure.getString(getContentResolver(),
                     ENABLED_NOTIFICATION_LISTENERS);
@@ -401,7 +473,11 @@
                                 logFail();
                                 status = FAIL;
                             } else {
-                                status = PASS;
+                                if (mNm.getEffectsSuppressor() == null) {
+                                    status = PASS;
+                                } else {
+                                    status = FAIL;
+                                }
                             }
                             next();
                         }
@@ -455,4 +531,362 @@
             delay();
         }
     }
+
+    private class SnoozeTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.snooze(mContext);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerStatus(mContext,
+                        new MockListener.StatusCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == Activity.RESULT_OK) {
+                                    logFail();
+                                    status = FAIL;
+                                } else {
+                                    if (mNm.getEffectsSuppressor() == null) {
+                                        status = PASS;
+                                    } else {
+                                        logFail();
+                                        status = RETEST;
+                                        delay();
+                                    }
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class UnsnoozeTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_unsnooze);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.requestRebind(MockListener.COMPONENT_NAME);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerStatus(mContext,
+                        new MockListener.StatusCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == Activity.RESULT_OK) {
+                                    status = PASS;
+                                    next();
+                                } else {
+                                    logFail();
+                                    status = RETEST;
+                                    delay();
+                                }
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class EnableHintsTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_hints);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerHints(mContext,
+                        new MockListener.IntegerResultCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == MockListener.HINT_HOST_DISABLE_CALL_EFFECTS) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class SnoozeNotificationTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze_one);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.snoozeOne(mContext, mTag1);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerRemoved(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)
+                                        && !result.contains(mTag2)
+                                        && !result.contains(mTag3)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancel(mTag1, mId1);
+            mNm.cancel(mTag2, mId2);
+            mNm.cancel(mTag2, mId3);
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class UnsnoozeNotificationTest extends InteractiveTestCase {
+        final static int READY_TO_SNOOZE = 0;
+        final static int SNOOZED = 1;
+        final static int READY_TO_UNSNOOZE = 2;
+        final static int UNSNOOZED = 3;
+        int state = -1;
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_unsnooze_one);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            status = RETEST;
+
+            if (state == READY_TO_SNOOZE) {
+                MockListener.snoozeOne(mContext, mTag1);
+                state = SNOOZED;
+            } else if (state == SNOOZED) {
+                MockListener.probeListenerRemovedWithReason(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (String payloadData : result) {
+                                    JSONObject payload = null;
+                                    try {
+                                        payload = new JSONObject(payloadData);
+                                        pass &= checkEquals(mTag1,
+                                                payload.getString(JSON_TAG),
+                                                "data dismissal test: notification tag (%s, %s)");
+                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
+                                                payload.getInt(JSON_TAG),
+                                                "data dismissal test: reason (%d, %d)");
+                                    } catch (JSONException e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                                if (!pass) {
+                                    logFail();
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                } else {
+                                    state = READY_TO_UNSNOOZE;
+                                }
+                            }
+                        });
+            } else if (state == READY_TO_UNSNOOZE) {
+                MockListener.unsnoozeOne(mContext, mTag1);
+                state = UNSNOOZED;
+            } else {
+                MockListener.probeListenerPosted(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class SnoozeNotificationForTimeTest extends InteractiveTestCase {
+        final static int READY_TO_SNOOZE = 0;
+        final static int SNOOZED = 1;
+        final static int READY_TO_CHECK_FOR_UNSNOOZE = 2;
+        int state = -1;
+        long snoozeTime = 3000;
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze_one_time);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            state = READY_TO_SNOOZE;
+            delay();
+        }
+
+        @Override
+        void test() {
+            status = RETEST;
+            if (state == READY_TO_SNOOZE) {
+                MockListener.snoozeOneUntil(mContext, mTag1,
+                        System.currentTimeMillis() + snoozeTime);
+                state = SNOOZED;
+            } else if (state == SNOOZED){
+                MockListener.probeListenerRemovedWithReason(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (String payloadData : result) {
+                                    JSONObject payload = null;
+                                    try {
+                                        payload = new JSONObject(payloadData);
+                                        pass &= checkEquals(mTag1,
+                                                payload.getString(JSON_TAG),
+                                                "data dismissal test: notification tag (%s, %s)");
+                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
+                                                payload.getInt(JSON_TAG),
+                                                "data dismissal test: reason (%d, %d)");
+                                    } catch (JSONException e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                                if (!pass) {
+                                    logFail();
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                } else {
+                                    state = READY_TO_CHECK_FOR_UNSNOOZE;
+                                }
+                            }
+                        });
+            } else {
+                MockListener.probeListenerPosted(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
index b7d9617..7ef63d7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
@@ -19,7 +19,6 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
 
-import android.content.pm.PackageManager;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.cts.helpers.TestSensorEnvironment;
@@ -83,9 +82,6 @@
 
     @SuppressWarnings("unused")
     public String testProximity_batching() throws Throwable {
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY)) {
-            return null;
-        }
         return runBatchTest(
                 Sensor.TYPE_PROXIMITY,
                 REPORT_LATENCY_10_SEC,
@@ -94,9 +90,6 @@
 
     @SuppressWarnings("unused")
     public String testProximity_flush() throws Throwable {
-        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_PROXIMITY)) {
-            return null;
-        }
         return runFlushTest(
                 Sensor.TYPE_PROXIMITY,
                 REPORT_LATENCY_10_SEC,
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/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java
new file mode 100644
index 0000000..dddbde7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/BuildConfig.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.sensors.sixdof;
+
+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/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java
new file mode 100644
index 0000000..4b188f1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/AccuracyListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.Interfaces;
+
+/**
+ * Interface that handles UI listeners that are only used in the Accuracy test.
+ */
+public interface AccuracyListener {
+    void onReset();
+
+    void lap1Complete();
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java
new file mode 100644
index 0000000..302bdd6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/BaseUiListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.Interfaces;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject;
+
+/**
+ * Interface that handles UI listeners that are used in every test.
+ */
+public interface BaseUiListener {
+    void onPoseProviderReady();
+
+    void onWaypointPlaced();
+
+    void onResult(ResultObject result);
+
+    void onDestroyUi();
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java
new file mode 100644
index 0000000..7f3bfe9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/ComplexMovementListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.Interfaces;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring;
+
+/**
+ * Interface that handles UI listeners that are only used in the Complex Movement test.
+ */
+public interface ComplexMovementListener {
+    void onRingEntered(Ring ring);
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java
new file mode 100644
index 0000000..7821322
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Interfaces/RobustnessListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.Interfaces;
+
+import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData;
+
+/**
+ * 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/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java
new file mode 100644
index 0000000..8de7bb6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointAreaCoveredException.java
@@ -0,0 +1,22 @@
+/*
+ * 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.Exceptions;
+
+/**
+ * Exception class for not enough area covered by waypoints.
+ */
+public class WaypointAreaCoveredException extends WaypointException {
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java
new file mode 100644
index 0000000..c09d12f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointDistanceException.java
@@ -0,0 +1,22 @@
+/*
+ * 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.Exceptions;
+
+/**
+ * Exception class for being too close to the marker waypoints.
+ */
+public class WaypointDistanceException extends WaypointException {
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java
new file mode 100644
index 0000000..d1fc1d9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointException.java
@@ -0,0 +1,22 @@
+/*
+ * 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.Exceptions;
+
+/**
+ * Generic abstract exception class used by the other exceptions.
+ */
+public abstract class WaypointException extends Exception {
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java
new file mode 100644
index 0000000..855bfce
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointRingNotEnteredException.java
@@ -0,0 +1,22 @@
+/*
+ * 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.Exceptions;
+
+/**
+ * Exception class for when a ring has not been entered.
+ */
+public class WaypointRingNotEnteredException extends WaypointException {
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java
new file mode 100644
index 0000000..d2664f9
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/sixdof/Utils/Exceptions/WaypointStartPointException.java
@@ -0,0 +1,22 @@
+/*
+ * 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.Exceptions;
+
+/**
+ * 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/apps/CtsVerifier/src/com/android/cts/verifier/usb/MtpHostTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/MtpHostTestActivity.java
deleted file mode 100644
index 2041be0..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/MtpHostTestActivity.java
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.usb;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbConstants;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
-import android.mtp.MtpConstants;
-import android.mtp.MtpDevice;
-import android.mtp.MtpDeviceInfo;
-import android.mtp.MtpEvent;
-import android.mtp.MtpObjectInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.util.MutableInt;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import junit.framework.AssertionFailedError;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class MtpHostTestActivity extends PassFailButtons.Activity implements Handler.Callback {
-    private static final int MESSAGE_PASS = 0;
-    private static final int MESSAGE_FAIL = 1;
-    private static final int MESSAGE_RUN = 2;
-
-    private static final int ITEM_STATE_PASS = 0;
-    private static final int ITEM_STATE_FAIL = 1;
-    private static final int ITEM_STATE_INDETERMINATE = 2;
-
-    /**
-     * Subclass for PTP.
-     */
-    private static final int SUBCLASS_STILL_IMAGE_CAPTURE = 1;
-
-    /**
-     * Subclass for Android style MTP.
-     */
-    private static final int SUBCLASS_MTP = 0xff;
-
-    /**
-     * Protocol for Picture Transfer Protocol (PIMA 15470).
-     */
-    private static final int PROTOCOL_PICTURE_TRANSFER = 1;
-
-    /**
-     * Protocol for Android style MTP.
-     */
-    private static final int PROTOCOL_MTP = 0;
-
-    private static final int RETRY_DELAY_MS = 1000;
-
-    private static final String ACTION_PERMISSION_GRANTED =
-            "com.android.cts.verifier.usb.ACTION_PERMISSION_GRANTED";
-
-    private static final String TEST_FILE_NAME = "CtsVerifierTest_testfile.txt";
-    private static final byte[] TEST_FILE_CONTENTS =
-            "This is a test file created by CTS verifier test.".getBytes(StandardCharsets.US_ASCII);
-
-    private final Handler mHandler = new Handler(this);
-    private int mStep;
-    private final ArrayList<TestItem> mItems = new ArrayList<>();
-
-    private UsbManager mUsbManager;
-    private BroadcastReceiver mReceiver;
-    private UsbDevice mUsbDevice;
-    private MtpDevice mMtpDevice;
-    private ExecutorService mExecutor;
-    private TextView mErrorText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.mtp_host_activity);
-        setInfoResources(R.string.mtp_host_test, R.string.mtp_host_test_info, -1);
-        setPassFailButtonClickListeners();
-
-        final LayoutInflater inflater = getLayoutInflater();
-        final LinearLayout itemsView = (LinearLayout) findViewById(R.id.mtp_host_list);
-
-        mErrorText = (TextView) findViewById(R.id.error_text);
-
-        // Don't allow a test pass until all steps are passed.
-        getPassButton().setEnabled(false);
-
-        // Build test items.
-        mItems.add(new TestItem(
-                inflater,
-                R.string.mtp_host_device_lookup_message,
-                new int[] { R.id.next_item_button }));
-        mItems.add(new TestItem(
-                inflater,
-                R.string.mtp_host_grant_permission_message,
-                null));
-        mItems.add(new TestItem(
-                inflater,
-                R.string.mtp_host_test_read_event_message,
-                null));
-        mItems.add(new TestItem(
-                inflater,
-                R.string.mtp_host_test_send_object_message,
-                null));
-        mItems.add(new TestItem(
-                inflater,
-                R.string.mtp_host_test_notification_message,
-                new int[] { R.id.pass_item_button, R.id.fail_item_button }));
-        for (final TestItem item : mItems) {
-            itemsView.addView(item.view);
-        }
-
-        mExecutor = Executors.newSingleThreadExecutor();
-        mUsbManager = getSystemService(UsbManager.class);
-
-        mStep = 0;
-        mHandler.sendEmptyMessage(MESSAGE_RUN);
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        if (mReceiver != null) {
-            unregisterReceiver(mReceiver);
-            mReceiver = null;
-        }
-    }
-
-    @Override
-    public boolean handleMessage(Message msg) {
-        final TestItem item = mStep < mItems.size() ? mItems.get(mStep) : null;
-
-        switch (msg.what) {
-            case MESSAGE_RUN:
-                if (item == null) {
-                    getPassButton().setEnabled(true);
-                    return true;
-                }
-                item.setEnabled(true);
-                mExecutor.execute(new Runnable() {
-                    private final int mCurrentStep = mStep;
-
-                    @Override
-                    public void run() {
-                        try {
-                            int i = mCurrentStep;
-                            if (i-- == 0) stepFindMtpDevice();
-                            if (i-- == 0) stepGrantPermission();
-                            if (i-- == 0) stepTestReadEvent();
-                            if (i-- == 0) stepTestSendObject();
-                            if (i-- == 0) stepTestNotification();
-                            mHandler.sendEmptyMessage(MESSAGE_PASS);
-                        } catch (Exception | AssertionFailedError exception) {
-                            mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_FAIL, exception));
-                        }
-                    }
-                });
-                break;
-
-            case MESSAGE_PASS:
-                item.setState(ITEM_STATE_PASS);
-                item.setEnabled(false);
-                mStep++;
-                mHandler.sendEmptyMessage(MESSAGE_RUN);
-                break;
-
-            case MESSAGE_FAIL:
-                item.setState(ITEM_STATE_FAIL);
-                item.setEnabled(false);
-                final StringWriter writer = new StringWriter();
-                final Throwable throwable = (Throwable) msg.obj;
-                throwable.printStackTrace(new PrintWriter(writer));
-                mErrorText.setText(writer.toString());
-                break;
-        }
-
-        return true;
-    }
-
-    private void stepFindMtpDevice() throws InterruptedException {
-        assertEquals(R.id.next_item_button, waitForButtonClick());
-
-        UsbDevice device = null;
-        for (final UsbDevice candidate : mUsbManager.getDeviceList().values()) {
-            if (isMtpDevice(candidate)) {
-                device = candidate;
-                break;
-            }
-        }
-        assertNotNull(device);
-        mUsbDevice = device;
-    }
-
-    private void stepGrantPermission() throws InterruptedException {
-        if (!mUsbManager.hasPermission(mUsbDevice)) {
-            final CountDownLatch latch = new CountDownLatch(1);
-            mReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    unregisterReceiver(this);
-                    mReceiver = null;
-                    latch.countDown();
-                }
-            };
-            registerReceiver(mReceiver, new IntentFilter(ACTION_PERMISSION_GRANTED));
-            mUsbManager.requestPermission(
-                    mUsbDevice,
-                    PendingIntent.getBroadcast(
-                            MtpHostTestActivity.this, 0, new Intent(ACTION_PERMISSION_GRANTED), 0));
-
-            latch.await();
-            assertTrue(mUsbManager.hasPermission(mUsbDevice));
-        }
-
-        final UsbDeviceConnection connection = mUsbManager.openDevice(mUsbDevice);
-        assertNotNull(connection);
-
-        // Try to rob device ownership from other applications.
-        for (int i = 0; i < mUsbDevice.getInterfaceCount(); i++) {
-            connection.claimInterface(mUsbDevice.getInterface(i), true);
-            connection.releaseInterface(mUsbDevice.getInterface(i));
-        }
-        mMtpDevice = new MtpDevice(mUsbDevice);
-        assertTrue(mMtpDevice.open(connection));
-        assertTrue(mMtpDevice.getStorageIds().length > 0);
-    }
-
-    private void stepTestReadEvent() {
-        assertNotNull(mMtpDevice.getDeviceInfo().getEventsSupported());
-        assertTrue(mMtpDevice.getDeviceInfo().isEventSupported(MtpEvent.EVENT_OBJECT_ADDED));
-
-        mMtpDevice.getObjectHandles(0xFFFFFFFF, 0x0, 0x0);
-        while (true) {
-            MtpEvent event;
-            try {
-                event = mMtpDevice.readEvent(null);
-            } catch (IOException e) {
-                fail();
-                return;
-            }
-            if (event.getEventCode() == MtpEvent.EVENT_OBJECT_ADDED) {
-                break;
-            }
-            SystemClock.sleep(RETRY_DELAY_MS);
-        }
-    }
-
-    private void stepTestSendObject() throws IOException {
-        final MtpDeviceInfo deviceInfo = mMtpDevice.getDeviceInfo();
-        assertNotNull(deviceInfo.getOperationsSupported());
-        assertTrue(deviceInfo.isOperationSupported(MtpConstants.OPERATION_SEND_OBJECT_INFO));
-        assertTrue(deviceInfo.isOperationSupported(MtpConstants.OPERATION_SEND_OBJECT));
-
-        // Delete an existing test file that may be created by the test previously.
-        final int storageId = mMtpDevice.getStorageIds()[0];
-        for (final int objectHandle : mMtpDevice.getObjectHandles(
-                storageId, /* all format */ 0, /* Just under the root */ -1)) {
-            final MtpObjectInfo info = mMtpDevice.getObjectInfo(objectHandle);
-            if (TEST_FILE_NAME.equals(info.getName())) {
-                assertTrue(mMtpDevice.deleteObject(objectHandle));
-            }
-        }
-
-        final MtpObjectInfo info = new MtpObjectInfo.Builder()
-                .setStorageId(storageId)
-                .setName(TEST_FILE_NAME)
-                .setCompressedSize(TEST_FILE_CONTENTS.length)
-                .setFormat(MtpConstants.FORMAT_TEXT)
-                .setParent(-1)
-                .build();
-        final MtpObjectInfo newInfo = mMtpDevice.sendObjectInfo(info);
-        assertNotNull(newInfo);
-        assertTrue(newInfo.getObjectHandle() != -1);
-
-        final ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
-        try {
-            try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                    new ParcelFileDescriptor.AutoCloseOutputStream(pipes[1])) {
-                stream.write(TEST_FILE_CONTENTS);
-            }
-            assertTrue(mMtpDevice.sendObject(
-                    newInfo.getObjectHandle(),
-                    newInfo.getCompressedSizeLong(),
-                    pipes[0]));
-        } finally {
-            pipes[0].close();
-        }
-    }
-
-    private void stepTestNotification() throws InterruptedException {
-        assertEquals(R.id.pass_item_button, waitForButtonClick());
-    }
-
-    private int waitForButtonClick() throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final MutableInt result = new MutableInt(-1);
-        mItems.get(mStep).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                result.value = v.getId();
-                latch.countDown();
-            }
-        });
-        latch.await();
-        return result.value;
-    }
-
-    private static boolean isMtpDevice(UsbDevice device) {
-        for (int i = 0; i < device.getInterfaceCount(); i++) {
-            final UsbInterface usbInterface = device.getInterface(i);
-            if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
-                    usbInterface.getInterfaceSubclass() == SUBCLASS_STILL_IMAGE_CAPTURE &&
-                    usbInterface.getInterfaceProtocol() == PROTOCOL_PICTURE_TRANSFER)) {
-                return true;
-            }
-            if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
-                    usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
-                    usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
-                    "MTP".equals(usbInterface.getName())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static class TestItem {
-        private final View view;
-        private final int[] buttons;
-
-        TestItem(LayoutInflater inflater,
-                 int messageText,
-                 int[] buttons) {
-            this.view = inflater.inflate(R.layout.mtp_host_item, null, false);
-
-            final TextView textView = (TextView) view.findViewById(R.id.instructions);
-            textView.setText(messageText);
-
-            this.buttons = buttons != null ? buttons : new int[0];
-            for (final int id : this.buttons) {
-                final Button button = (Button) view.findViewById(id);
-                button.setVisibility(View.VISIBLE);
-                button.setEnabled(false);
-            }
-        }
-
-        void setOnClickListener(OnClickListener listener) {
-            for (final int id : buttons) {
-                final Button button = (Button) view.findViewById(id);
-                button.setOnClickListener(listener);
-            }
-        }
-
-        void setEnabled(boolean value) {
-            for (final int id : buttons) {
-                final Button button = (Button) view.findViewById(id);
-                button.setEnabled(value);
-            }
-        }
-
-        Button getButton(int id) {
-            return (Button) view.findViewById(id);
-        }
-
-        void setState(int state) {
-            final ImageView imageView = (ImageView) view.findViewById(R.id.status);
-            switch (state) {
-                case ITEM_STATE_PASS:
-                    imageView.setImageResource(R.drawable.fs_good);
-                    break;
-                case ITEM_STATE_FAIL:
-                    imageView.setImageResource(R.drawable.fs_error);
-                    break;
-                case ITEM_STATE_INDETERMINATE:
-                    imageView.setImageResource(R.drawable.fs_indeterminate);
-                    break;
-            }
-        }
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java
deleted file mode 100644
index 5c31ea4..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java
+++ /dev/null
@@ -1,475 +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 com.android.cts.verifier.usb;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.TestResult;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.hardware.usb.UsbAccessory;
-import android.hardware.usb.UsbManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Test for USB accessories. The test activity interacts with a cts-usb-accessory program that
- * acts as an accessory by exchanging a series of messages.
- */
-public class UsbAccessoryTestActivity extends PassFailButtons.Activity {
-
-    private static final String TAG = "UsbAccessoryTest";
-
-    private static final int FILE_DESCRIPTOR_PROBLEM_DIALOG_ID = 1;
-    private static final int STATE_START = 0;
-    private static final int STATE_CONNECTED = 1;
-    private static final int STATE_WAITING_FOR_RECONNECT = 2;
-    private static final int STATE_RECONNECTED = 3;
-    private static final int STATE_PASSED = 4;
-
-    private static final String ACTION_USB_PERMISSION =
-            "com.android.cts.verifier.usb.USB_PERMISSION";
-
-    private ArrayAdapter<String> mReceivedMessagesAdapter;
-    private ArrayAdapter<String> mSentMessagesAdapter;
-    private MessageHandler mHandler;
-    private Handler mMainHandler;
-
-    private UsbManager mUsbManager;
-    private PendingIntent mPermissionIntent;
-    private boolean mPermissionRequestPending;
-    private UsbReceiver mUsbReceiver;
-    private int mState = STATE_START;
-    private AlertDialog mDisconnectDialog;
-    private AlertDialog mConnectDialog;
-
-    private UsbAccessory mAccessory;
-    private ParcelFileDescriptor mFileDescriptor;
-
-    private Runnable mTimeoutRunnable = new Runnable() {
-        @Override
-        public void run() {
-            Toast.makeText(UsbAccessoryTestActivity.this,
-                    R.string.usb_reconnect_timeout, Toast.LENGTH_SHORT).show();
-            TestResult.setFailedResult(UsbAccessoryTestActivity.this, getTestId(), getTestDetails());
-        }
-    };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Log.d(TAG, "onCreate");
-        // Test success only works properly if launched from TestListActivity
-        String action = getIntent().getAction();
-        if (ACTION_USB_PERMISSION.equals(action)
-                || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
-            finish();
-            return;
-        }
-
-        setContentView(R.layout.usb_main);
-        setInfoResources(R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
-        setPassFailButtonClickListeners();
-
-        // Don't allow a test pass until the accessory and the Android device exchange messages...
-        getPassButton().setEnabled(false);
-
-        if (!hasUsbAccessorySupport()) {
-            showNoUsbAccessoryDialog();
-        }
-
-        mReceivedMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
-        mSentMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
-        mHandler = new MessageHandler();
-
-        mUsbManager = (UsbManager) getSystemService(USB_SERVICE);
-        mPermissionIntent = PendingIntent.getBroadcast(this, 0,
-                new Intent(ACTION_USB_PERMISSION), 0);
-
-        mUsbReceiver = new UsbReceiver();
-        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
-        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
-        registerReceiver(mUsbReceiver, filter);
-
-        setupListViews();
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(this)
-            .setIcon(android.R.drawable.ic_dialog_alert)
-            .setTitle(R.string.usb_reconnect_title)
-            .setCancelable(false)
-            .setNegativeButton(R.string.usb_reconnect_abort,
-                    new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    setTestResultAndFinish(false);
-                }
-            });
-        mConnectDialog = builder
-            .setMessage(R.string.usb_connect_message)
-            .create();
-        mDisconnectDialog = builder
-            .setMessage(R.string.usb_disconnect_message)
-            .create();
-
-        mMainHandler = new Handler(Looper.getMainLooper());
-    }
-
-    private boolean hasUsbAccessorySupport() {
-        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
-    }
-
-    private void showNoUsbAccessoryDialog() {
-        new AlertDialog.Builder(this)
-            .setIcon(android.R.drawable.ic_dialog_alert)
-            .setTitle(R.string.usb_not_available_title)
-            .setMessage(R.string.usb_not_available_message)
-            .setCancelable(false)
-            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    finish();
-                }
-            })
-            .show();
-    }
-
-    private void setupListViews() {
-        ListView sentMessages = (ListView) findViewById(R.id.usb_sent_messages);
-        ListView receivedMessages = (ListView) findViewById(R.id.usb_received_messages);
-
-        View emptySentView = findViewById(R.id.usb_empty_sent_messages);
-        View emptyReceivedView = findViewById(R.id.usb_empty_received_messages);
-        sentMessages.setEmptyView(emptySentView);
-        receivedMessages.setEmptyView(emptyReceivedView);
-
-        receivedMessages.setAdapter(mReceivedMessagesAdapter);
-        sentMessages.setAdapter(mSentMessagesAdapter);
-    }
-
-    class UsbReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.d(TAG, "Received broadcast: intent=" + intent);
-            if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
-                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
-                    UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-                    openAccessory(accessory);
-                } else {
-                    Log.i(TAG, "Permission denied...");
-                }
-                mPermissionRequestPending = false;
-            } else if (mState == STATE_WAITING_FOR_RECONNECT &&
-                    UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(intent.getAction())) {
-                UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-                if (accessory.equals(mAccessory)) {
-                    closeAccessory();
-                    mDisconnectDialog.dismiss();
-                    mConnectDialog.show();
-                    mMainHandler.postDelayed(mTimeoutRunnable, 10000 /* 10 seconds */);
-                }
-            }
-        }
-    }
-
-    public void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        Log.d(TAG, "onNewIntent: state=" + mState + ", intent=" + intent);
-        if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
-            UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-            openAccessory(accessory);
-        }
-    }
-
-    private void openAccessory(UsbAccessory accessory) {
-        mAccessory = accessory;
-        mFileDescriptor = mUsbManager.openAccessory(accessory);
-        if (mState == STATE_START) {
-            setState(STATE_CONNECTED);
-        } else if (mState == STATE_WAITING_FOR_RECONNECT) {
-            setState(STATE_RECONNECTED);
-            mConnectDialog.dismiss();
-        }
-        if (mFileDescriptor != null) {
-            FileDescriptor fileDescriptor = mFileDescriptor.getFileDescriptor();
-            FileInputStream inputStream = new FileInputStream(fileDescriptor);
-            FileOutputStream outputStream = new FileOutputStream(fileDescriptor);
-            new MessageThread(inputStream, outputStream, mHandler).start();
-        } else {
-            showDialog(FILE_DESCRIPTOR_PROBLEM_DIALOG_ID);
-        }
-    }
-
-    private void closeAccessory() {
-        mAccessory = null;
-        if (mFileDescriptor != null) {
-            try {
-                mFileDescriptor.close();
-            } catch (IOException e) {
-                Log.e(TAG, "Exception while closing file descriptor", e);
-            } finally {
-                mFileDescriptor = null;
-            }
-        }
-    }
-
-    static class MessageThread extends Thread {
-
-        private final InputStream mInputStream;
-
-        private final OutputStream mOutputStream;
-
-        private final MessageHandler mHandler;
-
-        private int mNextMessageNumber = 0;
-
-        MessageThread(InputStream inputStream, OutputStream outputStream, MessageHandler handler) {
-            this.mInputStream = inputStream;
-            this.mOutputStream = outputStream;
-            this.mHandler = handler;
-        }
-
-        @Override
-        public void run() {
-            mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_STARTING);
-
-            try {
-                // Wait a bit or else the messages can appear to quick and be confusing...
-                Thread.sleep(2000);
-                sendMessage();
-
-                // Wait for response and send message acks...
-                int numRead = 0;
-                byte[] buffer = new byte[16384];
-                boolean done = false;
-                while (numRead >= 0 && !done) {
-                    numRead = mInputStream.read(buffer);
-                    if (numRead > 0) {
-                        done = handleReceivedMessage(buffer, numRead);
-                    }
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Exception while reading from input stream", e);
-                mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
-            } catch (InterruptedException e) {
-                Log.e(TAG, "Exception while reading from input stream", e);
-                mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
-            }
-            mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_ENDING);
-        }
-
-        private boolean handleReceivedMessage(byte[] buffer, int numRead) throws IOException {
-            // TODO: Check the contents of the message?
-            String text = new String(buffer, 0, numRead).trim();
-            mHandler.sendReceivedMessage(text);
-
-            // Send back a response..
-            if (mNextMessageNumber <= 10) {
-                sendMessage();
-                return false;
-            } else {
-                mHandler.sendEmptyMessage(MessageHandler.STAGE_PASSED);
-                return true;
-            }
-        }
-
-        private void sendMessage() throws IOException {
-            String text = "Message from Android device #" + mNextMessageNumber++;
-            mOutputStream.write(text.getBytes());
-            mHandler.sendSentMessage(text);
-        }
-    }
-
-    class MessageHandler extends Handler {
-
-        static final int RECEIVED_MESSAGE = 1;
-
-        static final int SENT_MESSAGE = 2;
-
-        static final int MESSAGE_THREAD_STARTING = 3;
-
-        static final int MESSAGE_THREAD_EXCEPTION = 4;
-
-        static final int MESSAGE_THREAD_ENDING = 5;
-
-        static final int STAGE_PASSED = 6;
-
-        @Override
-        public void handleMessage(Message msg) {
-            super.handleMessage(msg);
-            switch (msg.what) {
-                case RECEIVED_MESSAGE:
-                    mReceivedMessagesAdapter.add((String) msg.obj);
-                    break;
-
-                case SENT_MESSAGE:
-                    mSentMessagesAdapter.add((String) msg.obj);
-                    break;
-
-                case MESSAGE_THREAD_STARTING:
-                    showToast(R.string.usb_message_thread_started);
-                    break;
-
-                case MESSAGE_THREAD_EXCEPTION:
-                    showToast(R.string.usb_message_thread_exception);
-                    break;
-
-                case MESSAGE_THREAD_ENDING:
-                    showToast(R.string.usb_message_thread_ended);
-                    break;
-
-                case STAGE_PASSED:
-                    if (mState == STATE_RECONNECTED) {
-                        showToast(R.string.usb_test_passed);
-                        getPassButton().setEnabled(true);
-                        setState(STATE_PASSED);
-                        mMainHandler.removeCallbacks(mTimeoutRunnable);
-                    } else if (mState == STATE_CONNECTED) {
-                        mDisconnectDialog.show();
-                        setState(STATE_WAITING_FOR_RECONNECT);
-                    }
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Bad message type: " + msg.what);
-            }
-        }
-
-        private void showToast(int messageId) {
-            Toast.makeText(UsbAccessoryTestActivity.this, messageId, Toast.LENGTH_SHORT).show();
-        }
-
-        void sendReceivedMessage(String text) {
-            Message message = Message.obtain(this, RECEIVED_MESSAGE);
-            message.obj = text;
-            sendMessage(message);
-        }
-
-        void sendSentMessage(String text) {
-            Message message = Message.obtain(this, SENT_MESSAGE);
-            message.obj = text;
-            sendMessage(message);
-        }
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        Log.d(TAG, "onResume: state=" + stateToString(mState));
-        if (mState == STATE_START) {
-            UsbAccessory[] accessories = mUsbManager.getAccessoryList();
-            UsbAccessory accessory = accessories != null && accessories.length > 0
-                    ? accessories[0]
-                    : null;
-            if (accessory != null) {
-                if (mUsbManager.hasPermission(accessory)) {
-                    openAccessory(accessory);
-                } else {
-                    if (!mPermissionRequestPending) {
-                        mUsbManager.requestPermission(accessory, mPermissionIntent);
-                        mPermissionRequestPending = true;
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        Log.d(TAG, "onPause: state=" + stateToString(mState));
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        Log.d(TAG, "onStop: state=" + stateToString(mState));
-        closeAccessory();
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        setContentView(R.layout.usb_main);
-        setupListViews();
-    }
-
-    @Override
-    public Dialog onCreateDialog(int id, Bundle args) {
-        switch (id) {
-            case FILE_DESCRIPTOR_PROBLEM_DIALOG_ID:
-                return new AlertDialog.Builder(this)
-                    .setIcon(android.R.drawable.ic_dialog_alert)
-                    .setTitle(R.string.usb_accessory_test)
-                    .setMessage(R.string.usb_file_descriptor_error)
-                    .create();
-
-            default:
-                return super.onCreateDialog(id, args);
-        }
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        Log.d(TAG, "onDestroy");
-        if (mUsbReceiver != null) {
-            unregisterReceiver(mUsbReceiver);
-        }
-    }
-
-    private void setState(int newState) {
-        Log.d(TAG, "Transition: " + stateToString(mState) + " -> " + stateToString(newState));
-        mState = newState;
-    }
-
-
-    private static String stateToString(int state) {
-        switch (state) {
-            case STATE_START: return "START";
-            case STATE_CONNECTED: return "CONNECTED";
-            case STATE_WAITING_FOR_RECONNECT: return "WAITING_FOR_RECONNECT";
-            case STATE_RECONNECTED: return "RECONNECTED";
-            case STATE_PASSED: return "PASSED";
-            default: return "UNKNOWN";
-        }
-    }
-
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java
new file mode 100644
index 0000000..5be1792
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.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.usb;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * Utilities for the USB CTS verifier tests.
+ */
+public class Util {
+    private static final String LOG_TAG = Util.class.getSimpleName();
+
+    /**
+     * Run a {@link Invokable} and expect a {@link Throwable}.
+     *
+     * @param r             The {@link Invokable} to run
+     * @param expectedClass The expected {@link Throwable} type
+     */
+    public static void runAndAssertException(@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");
+    }
+
+
+    /**
+     * A {@link Runnable} that can throw an {@link Throwable}.
+     */
+    public interface Invokable {
+        /**
+         * Run the code that might cause an exception.
+         */
+        void run() throws Throwable;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java
new file mode 100644
index 0000000..f5e0fef
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.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.usb.accessory;
+
+import android.app.Activity;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Utility to receive callbacks when an USB accessory is attached.
+ */
+public class AccessoryAttachmentHandler extends Activity {
+    private static final ArrayList<AccessoryAttachmentObserver> sObservers = new ArrayList<>();
+
+    /**
+     * Register an observer to be called when an USB accessory connects.
+     *
+     * @param observer The observer that should be called when an USB accessory connects.
+     */
+    static void addObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.add(observer);
+        }
+    }
+
+    /**
+     * Remove an observer that was added in {@link #addObserver}.
+     *
+     * @param observer The observer to remove
+     */
+    static void removeObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.remove(observer);
+        }
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        UsbAccessory accessory = getIntent().getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+        synchronized (sObservers) {
+            ArrayList<AccessoryAttachmentObserver> observers =
+                    (ArrayList<AccessoryAttachmentObserver>) sObservers.clone();
+
+            for (AccessoryAttachmentObserver observer : observers) {
+                observer.onAttached(accessory);
+            }
+        }
+
+        finish();
+    }
+
+    /**
+     * Callback when an accessory is attached
+     */
+    interface AccessoryAttachmentObserver {
+        void onAttached(UsbAccessory accessory);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
new file mode 100644
index 0000000..8ac009b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.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 com.android.cts.verifier.usb.accessory;
+
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Guide the user to run test for the USB accessory interface.
+ */
+public class UsbAccessoryTestActivity extends PassFailButtons.Activity implements
+        AccessoryAttachmentHandler.AccessoryAttachmentObserver {
+    private static final String LOG_TAG = UsbAccessoryTestActivity.class.getSimpleName();
+    private static final int MAX_BUFFER_SIZE = 16384;
+
+    private TextView mStatus;
+    private ProgressBar mProgress;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.usb_main);
+        setInfoResources(
+                R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
+
+        mStatus = (TextView) findViewById(R.id.status);
+        mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+        mStatus.setText(R.string.usb_accessory_test_step1);
+        getPassButton().setEnabled(false);
+
+        AccessoryAttachmentHandler.addObserver(this);
+    }
+
+    @Override
+    public void onAttached(UsbAccessory accessory) {
+        mStatus.setText(R.string.usb_accessory_test_step2);
+        mProgress.setVisibility(View.VISIBLE);
+
+        AccessoryAttachmentHandler.removeObserver(this);
+
+        UsbManager usbManager = getSystemService(UsbManager.class);
+
+        try {
+            assertEquals("Android device running CTS verifier", accessory.getDescription());
+            assertEquals("Android", accessory.getManufacturer());
+            assertEquals("Android device", accessory.getModel());
+            assertEquals("0", accessory.getSerial());
+            assertEquals("https://source.android.com/compatibility/cts/verifier.html",
+                    accessory.getUri());
+            assertEquals("1", accessory.getVersion());
+
+            assertTrue(Arrays.asList(usbManager.getAccessoryList()).contains(accessory));
+
+            runAndAssertException(() -> usbManager.openAccessory(null), NullPointerException.class);
+
+            ParcelFileDescriptor accessoryFd = usbManager.openAccessory(accessory);
+            assertNotNull(accessoryFd);
+
+            try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(accessoryFd)) {
+                try (OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
+                        accessoryFd)) {
+                    byte[] origBuffer32 = new byte[32];
+                    (new Random()).nextBytes(origBuffer32);
+
+                    byte[] origBufferMax = new byte[MAX_BUFFER_SIZE];
+                    (new Random()).nextBytes(origBufferMax);
+
+                    byte[] bufferMax = new byte[MAX_BUFFER_SIZE];
+                    byte[] buffer32 = new byte[32];
+                    byte[] buffer16 = new byte[16];
+
+                    // Echo a transfer
+                    nextTest(is, os, "echo 32 bytes");
+
+                    os.write(origBuffer32);
+
+                    int numRead = is.read(buffer32);
+                    assertEquals(32, numRead);
+                    assertArrayEquals(origBuffer32, buffer32);
+
+                    // Receive less data than available
+                    nextTest(is, os, "echo 32 bytes");
+
+                    os.write(origBuffer32);
+
+                    numRead = is.read(buffer16);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOf(origBuffer32, 16), buffer16);
+
+                    // If a transfer was only partially read, the rest of the transfer is lost.
+                    // We cannot read the second part, hence proceed to the next test.
+
+                    // Send two transfers in a row
+                    nextTest(is, os, "echo two 16 byte transfers as one");
+
+                    os.write(Arrays.copyOf(origBuffer32, 16));
+                    os.write(Arrays.copyOfRange(origBuffer32, 16, 32));
+
+                    numRead = is.read(buffer32);
+                    assertEquals(32, numRead);
+                    assertArrayEquals(origBuffer32, buffer32);
+
+                    // Receive two transfers in a row into a buffer that is bigger than the transfer
+                    nextTest(is, os, "echo 32 bytes as two 16 byte transfers");
+
+                    os.write(origBuffer32);
+
+                    // Even though the buffer would hold 32 bytes the input stream will read the
+                    // transfers individually
+                    numRead = is.read(buffer32);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOf(origBuffer32, 16),
+                            Arrays.copyOf(buffer32, 16));
+
+                    numRead = is.read(buffer32);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOfRange(origBuffer32, 16, 32),
+                            Arrays.copyOf(buffer32, 16));
+
+                    // Echo a buffer with the maximum size
+                    nextTest(is, os, "echo max bytes");
+
+                    os.write(origBufferMax);
+
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    // Echo a buffer with twice the maximum size
+                    nextTest(is, os, "echo max*2 bytes");
+
+                    byte[] oversizeBuffer = new byte[MAX_BUFFER_SIZE * 2];
+                    System.arraycopy(origBufferMax, 0, oversizeBuffer, 0, MAX_BUFFER_SIZE);
+                    System.arraycopy(origBufferMax, 0, oversizeBuffer, MAX_BUFFER_SIZE,
+                            MAX_BUFFER_SIZE);
+                    os.write(oversizeBuffer);
+
+                    // The other side can not write more than the maximum size at once, hence we get
+                    // two transfers in return
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    nextTest(is, os, "done");
+                }
+            }
+
+            accessoryFd.close();
+
+            setTestResultAndFinish(true);
+        } catch (Throwable t) {
+            fail(null, t);
+        }
+    }
+
+    /**
+     * Signal to the companion device that we want to switch to the next test.
+     *
+     * @param is       The input stream from the companion device
+     * @param os       The output stream from the companion device
+     * @param testName The name of the new test
+     */
+    private boolean nextTest(@NonNull InputStream is, @NonNull OutputStream os,
+            @NonNull String testName) throws IOException {
+        Log.i(LOG_TAG, "Init new test " + testName);
+
+        ByteBuffer nameBuffer = Charset.forName("UTF-8").encode(CharBuffer.wrap(testName));
+        byte[] sizeBuffer = {(byte) nameBuffer.limit()};
+
+        os.write(sizeBuffer);
+        os.write(Arrays.copyOf(nameBuffer.array(), nameBuffer.limit()));
+
+        int ret = is.read();
+        if (ret <= 0) {
+            Log.i(LOG_TAG, "Last test failed " + ret);
+            return false;
+        }
+
+        os.write(0);
+
+        Log.i(LOG_TAG, "Running " + testName);
+
+        return true;
+    }
+
+    @Override
+    protected void onDestroy() {
+        AccessoryAttachmentHandler.removeObserver(this);
+
+        super.onDestroy();
+    }
+
+    /**
+     * Indicate that the test failed.
+     */
+    private void fail(@Nullable String s, @Nullable Throwable e) {
+        Log.e(LOG_TAG, s, e);
+        setTestResultAndFinish(false);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/AoapInterface.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/AoapInterface.java
new file mode 100644
index 0000000..0d853d1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/AoapInterface.java
@@ -0,0 +1,135 @@
+/*
+ * 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.usb.device;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+class AoapInterface {
+    /**
+     * Use Google Vendor ID when in accessory mode
+     */
+    public static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+    /**
+     * Product ID to use when in accessory mode
+     */
+    public static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+    /**
+     * Product ID to use when in accessory mode and adb is enabled
+     */
+    public static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+    /**
+     * Indexes for strings sent by the host via ACCESSORY_SEND_STRING
+     */
+    public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+    public static final int ACCESSORY_STRING_MODEL = 1;
+    public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+    public static final int ACCESSORY_STRING_VERSION = 3;
+    public static final int ACCESSORY_STRING_URI = 4;
+    public static final int ACCESSORY_STRING_SERIAL = 5;
+
+    /**
+     * Control request for retrieving device's protocol version
+     *
+     *  requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_GET_PROTOCOL
+     *  value:          0
+     *  index:          0
+     *  data            version number (16 bits little endian)
+     *                     1 for original accessory support
+     *                     2 adds HID and device to host audio support
+     */
+    public static final int ACCESSORY_GET_PROTOCOL = 51;
+
+    /**
+     * Control request for host to send a string to the device
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_SEND_STRING
+     *  value:          0
+     *  index:          string ID
+     *  data            zero terminated UTF8 string
+     *
+     *  The device can later retrieve these strings via the
+     *  ACCESSORY_GET_STRING_* ioctls
+     */
+    public static final int ACCESSORY_SEND_STRING = 52;
+
+    /**
+     * Control request for starting device in accessory mode.
+     * The host sends this after setting all its strings to the device.
+     *
+     *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     *  request:        ACCESSORY_START
+     *  value:          0
+     *  index:          0
+     *  data            none
+     */
+    public static final int ACCESSORY_START = 53;
+
+    /**
+     * Max payload size for AOAP. Limited by driver.
+     */
+    public static final int MAX_PAYLOAD_SIZE = 16384;
+
+    private static final String TAG = AoapInterface.class.getSimpleName();
+
+    public static int getProtocol(UsbDeviceConnection conn) {
+        byte buffer[] = new byte[2];
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+        if (len != 2) {
+            return -1;
+        }
+        return (buffer[1] << 8) | buffer[0];
+    }
+
+    public static void sendString(UsbDeviceConnection conn, int index, String string) {
+        byte[] buffer = (string + "\0").getBytes();
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_SEND_STRING, 0, index,
+                buffer, buffer.length, 10000);
+        if (len != buffer.length) {
+            throw new RuntimeException("Failed to send string " + index + ": \"" + string + "\"");
+        } else {
+            Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
+        }
+    }
+
+    public static void sendAoapStart(UsbDeviceConnection conn) {
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_START, 0, 0, null, 0, 10000);
+        if (len < 0) {
+            throw new RuntimeException("control transfer for accessory start failed:" + len);
+        }
+    }
+
+    public static boolean isDeviceInAoapMode(UsbDevice device) {
+        final int vid = device.getVendorId();
+        final int pid = device.getProductId();
+        return vid == USB_ACCESSORY_VENDOR_ID
+                && (pid == USB_ACCESSORY_PRODUCT_ID
+                        || pid == USB_ACCESSORY_ADB_PRODUCT_ID);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
new file mode 100644
index 0000000..6a1a16a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -0,0 +1,2023 @@
+/*
+ * 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.usb.device;
+
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
+
+import static org.junit.Assert.assertArrayEquals;
+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.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbRequest;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import org.junit.AssumptionViolatedException;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class UsbDeviceTestActivity extends PassFailButtons.Activity {
+    private static final String ACTION_USB_PERMISSION =
+            "com.android.cts.verifier.usb.device.USB_PERMISSION";
+    private static final String LOG_TAG = UsbDeviceTestActivity.class.getSimpleName();
+    private static final int TIMEOUT_MILLIS = 5000;
+    private static final int MAX_BUFFER_SIZE = 16384;
+
+    private UsbManager mUsbManager;
+    private BroadcastReceiver mUsbDeviceConnectionReceiver;
+    private Thread mTestThread;
+    private TextView mStatus;
+    private ProgressBar mProgress;
+
+    private static long now() {
+        return System.nanoTime() / 1000000;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.usb_main);
+        setInfoResources(R.string.usb_device_test, R.string.usb_device_test_info, -1);
+
+        mStatus = (TextView) findViewById(R.id.status);
+        mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+
+        mUsbManager = getSystemService(UsbManager.class);
+
+        getPassButton().setEnabled(false);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+        mStatus.setText(R.string.usb_device_test_step1);
+
+        mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (UsbDeviceTestActivity.this) {
+                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+                    switch (intent.getAction()) {
+                        case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+                            if (!AoapInterface.isDeviceInAoapMode(device)) {
+                                mStatus.setText(R.string.usb_device_test_step2);
+                            }
+
+                            mUsbManager.requestPermission(device,
+                                    PendingIntent.getBroadcast(UsbDeviceTestActivity.this, 0,
+                                            new Intent(ACTION_USB_PERMISSION), 0));
+                            break;
+                        case ACTION_USB_PERMISSION:
+                            boolean granted = intent.getBooleanExtra(
+                                    UsbManager.EXTRA_PERMISSION_GRANTED, false);
+
+                            if (granted) {
+                                if (!AoapInterface.isDeviceInAoapMode(device)) {
+                                    mStatus.setText(R.string.usb_device_test_step3);
+
+                                    UsbDeviceConnection connection = mUsbManager.openDevice(device);
+                                    try {
+                                        makeThisDeviceAnAccessory(connection);
+                                    } finally {
+                                        connection.close();
+                                    }
+                                } else {
+                                    mStatus.setText(R.string.usb_device_test_step4);
+                                    mProgress.setIndeterminate(true);
+                                    mProgress.setVisibility(View.VISIBLE);
+
+                                    unregisterReceiver(mUsbDeviceConnectionReceiver);
+                                    mUsbDeviceConnectionReceiver = null;
+
+                                    // Do not run test on main thread
+                                    mTestThread = new Thread() {
+                                        @Override
+                                        public void run() {
+                                            runTests(device);
+                                        }
+                                    };
+
+                                    mTestThread.start();
+                                }
+                            } else {
+                                fail("Permission to connect to " + device.getProductName()
+                                        + " not granted", null);
+                            }
+                            break;
+                    }
+                }
+            }
+        };
+
+        registerReceiver(mUsbDeviceConnectionReceiver, filter);
+    }
+
+    /**
+     * Indicate that the test failed.
+     */
+    private void fail(@Nullable String s, @Nullable Throwable e) {
+        Log.e(LOG_TAG, s, e);
+        setTestResultAndFinish(false);
+    }
+
+    /**
+     * Converts the device under test into an Android accessory. Accessories are USB hosts that are
+     * detected on the device side via {@link UsbManager#getAccessoryList()}.
+     *
+     * @param connection The connection to the USB device
+     */
+    private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
+                "Android");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
+                "Android device");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
+                "Android device running CTS verifier");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
+                "https://source.android.com/compatibility/cts/verifier.html");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
+        AoapInterface.sendAoapStart(connection);
+    }
+
+    /**
+     * Switch to next test.
+     *
+     * @param connection   Connection to the USB device
+     * @param in           The in endpoint
+     * @param out          The out endpoint
+     * @param nextTestName The name of the new test
+     */
+    private void nextTest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
+            @NonNull UsbEndpoint out, @NonNull CharSequence nextTestName) {
+        Log.v(LOG_TAG, "Finishing previous test");
+
+        // Send name of next test
+        assertTrue(nextTestName.length() <= Byte.MAX_VALUE);
+        ByteBuffer nextTestNameBuffer = Charset.forName("UTF-8")
+                .encode(CharBuffer.wrap(nextTestName));
+        byte[] sizeBuffer = { (byte) nextTestNameBuffer.limit() };
+        int numSent = connection.bulkTransfer(out, sizeBuffer, 1, 0);
+        assertEquals(1, numSent);
+
+        numSent = connection.bulkTransfer(out, nextTestNameBuffer.array(),
+                nextTestNameBuffer.limit(), 0);
+        assertEquals(nextTestNameBuffer.limit(), numSent);
+
+        // Receive result of last test
+        byte[] lastTestResultBytes = new byte[1];
+        int numReceived = connection.bulkTransfer(in, lastTestResultBytes,
+                lastTestResultBytes.length, TIMEOUT_MILLIS);
+        assertEquals(1, numReceived);
+        assertEquals(1, lastTestResultBytes[0]);
+
+        // Send ready signal
+        sizeBuffer[0] = 42;
+        numSent = connection.bulkTransfer(out, sizeBuffer, 1, 0);
+        assertEquals(1, numSent);
+
+        Log.i(LOG_TAG, "Running test \"" + nextTestName + "\"");
+    }
+
+    /**
+     * Send some data and expect it to be echoed back.
+     *
+     * @param connection Connection to the USB device
+     * @param in         The in endpoint
+     * @param out        The out endpoint
+     * @param size       The number of bytes to send
+     */
+    private void echoBulkTransfer(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int size) {
+        byte[] sentBuffer = new byte[size];
+        Random r = new Random();
+        r.nextBytes(sentBuffer);
+
+        int numSent = connection.bulkTransfer(out, sentBuffer, sentBuffer.length, 0);
+        assertEquals(size, numSent);
+
+        byte[] receivedBuffer = new byte[size];
+        int numReceived = connection.bulkTransfer(in, receivedBuffer, receivedBuffer.length,
+                TIMEOUT_MILLIS);
+        assertEquals(size, numReceived);
+
+        assertArrayEquals(sentBuffer, receivedBuffer);
+    }
+
+    /**
+     * Send some data and expect it to be echoed back (but have an offset in the send buffer).
+     *
+     * @param connection Connection to the USB device
+     * @param in         The in endpoint
+     * @param out        The out endpoint
+     * @param size       The number of bytes to send
+     */
+    private void echoBulkTransferOffset(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int offset, int size) {
+        byte[] sentBuffer = new byte[offset + size];
+        Random r = new Random();
+        r.nextBytes(sentBuffer);
+
+        int numSent = connection.bulkTransfer(out, sentBuffer, offset, size, 0);
+        assertEquals(size, numSent);
+
+        byte[] receivedBuffer = new byte[offset + size];
+        int numReceived = connection.bulkTransfer(in, receivedBuffer, offset, size, TIMEOUT_MILLIS);
+        assertEquals(size, numReceived);
+
+        for (int i = 0; i < offset + size; i++) {
+            if (i < offset) {
+                assertEquals(0, receivedBuffer[i]);
+            } else {
+                assertEquals(sentBuffer[i], receivedBuffer[i]);
+            }
+        }
+    }
+
+    /**
+     * Send a transfer that is larger than MAX_BUFFER_SIZE.
+     *
+     * @param connection Connection to the USB device
+     * @param in         The in endpoint
+     * @param out        The out endpoint
+     */
+    private void echoOversizedBulkTransfer(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out) {
+        int totalSize = MAX_BUFFER_SIZE * 3 / 2;
+        byte[] sentBuffer = new byte[totalSize];
+        Random r = new Random();
+        r.nextBytes(sentBuffer);
+
+        int numSent = connection.bulkTransfer(out, sentBuffer, sentBuffer.length, 0);
+
+        // Buffer will only be partially transferred
+        assertEquals(MAX_BUFFER_SIZE, numSent);
+
+        byte[] receivedBuffer = new byte[totalSize];
+        int numReceived = connection.bulkTransfer(in, receivedBuffer, receivedBuffer.length,
+                TIMEOUT_MILLIS);
+
+        // All beyond MAX_BUFFER_SIZE was not send, hence it will not be echoed back
+        assertEquals(MAX_BUFFER_SIZE, numReceived);
+
+        for (int i = 0; i < totalSize; i++) {
+            if (i < MAX_BUFFER_SIZE) {
+                assertEquals(sentBuffer[i], receivedBuffer[i]);
+            } else {
+                assertEquals(0, receivedBuffer[i]);
+            }
+        }
+    }
+
+    /**
+     * Receive a transfer that is larger than MAX_BUFFER_SIZE
+     *
+     * @param connection Connection to the USB device
+     * @param in         The in endpoint
+     */
+    private void receiveOversizedBulkTransfer(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in) {
+        // Buffer will be received as two transfers
+        byte[] receivedBuffer1 = new byte[MAX_BUFFER_SIZE * 3 / 2];
+        int numReceived = connection.bulkTransfer(in, receivedBuffer1, receivedBuffer1.length,
+                TIMEOUT_MILLIS);
+        assertEquals(MAX_BUFFER_SIZE, numReceived);
+
+        byte[] receivedBuffer2 = new byte[MAX_BUFFER_SIZE / 2];
+        numReceived = connection.bulkTransfer(in, receivedBuffer2, receivedBuffer2.length,
+                TIMEOUT_MILLIS);
+        assertEquals(MAX_BUFFER_SIZE / 2, numReceived);
+
+        assertEquals(1, receivedBuffer1[0]);
+        assertEquals(2, receivedBuffer1[MAX_BUFFER_SIZE - 1]);
+        assertEquals(3, receivedBuffer2[0]);
+        assertEquals(4, receivedBuffer2[MAX_BUFFER_SIZE / 2 - 1]);
+    }
+
+    /**
+     * Receive data but supply an empty buffer. This causes the thread to block until any data is
+     * sent. The zero-sized receive-transfer just returns without data and the next transfer can
+     * actually read the data.
+     *
+     * @param connection Connection to the USB device
+     * @param in         The in endpoint
+     * @param buffer     The buffer to use
+     * @param offset     The offset into the buffer
+     * @param length     The lenght of data to receive
+     */
+    private void receiveWithEmptyBuffer(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @Nullable byte[] buffer, int offset, int length) {
+        long startTime = now();
+        int numReceived;
+        if (offset == 0) {
+            numReceived = connection.bulkTransfer(in, buffer, length, 0);
+        } else {
+            numReceived = connection.bulkTransfer(in, buffer, offset, length, 0);
+        }
+        long endTime = now();
+        assertEquals(-1, numReceived);
+
+        // The transfer should block
+        assertTrue(endTime - startTime > 100);
+
+        numReceived = connection.bulkTransfer(in, new byte[1], 1, 0);
+        assertEquals(1, numReceived);
+    }
+
+    /**
+     * Tests {@link UsbDeviceConnection#controlTransfer}.
+     *
+     * <p>Note: We cannot send ctrl data to the device as it thinks it talks to an accessory, hence
+     * the testing is currently limited.</p>
+     *
+     * @param connection The connection to use for testing
+     *
+     * @throws Throwable
+     */
+    private void ctrlTransferTests(@NonNull UsbDeviceConnection connection) throws Throwable {
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 1, 0),
+                IllegalArgumentException.class);
+
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], -1, 0),
+                IllegalArgumentException.class);
+
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 2, 0),
+                IllegalArgumentException.class);
+
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 0, 1, 0),
+                IllegalArgumentException.class);
+
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 0, -1, 0),
+                IllegalArgumentException.class);
+
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 1, 1, 0),
+                IllegalArgumentException.class);
+    }
+
+    /**
+     * Search an {@link UsbInterface} for an {@link UsbEndpoint endpoint} of a certain direction.
+     *
+     * @param iface     The interface to search
+     * @param direction The direction the endpoint is for.
+     *
+     * @return The first endpoint found or {@link null}.
+     */
+    private @NonNull UsbEndpoint getEndpoint(@NonNull UsbInterface iface, int direction) {
+        for (int i = 0; i < iface.getEndpointCount(); i++) {
+            UsbEndpoint ep = iface.getEndpoint(i);
+            if (ep.getDirection() == direction) {
+                return ep;
+            }
+        }
+
+        throw new IllegalStateException("Could not find " + direction + " endpoint in "
+                + iface.getName());
+    }
+
+    /**
+     * Send a USB request using the {@link UsbRequest#queue legacy path} and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     * @param size            The size of the request to send
+     * @param originalSize    The size of the original buffer
+     * @param sliceStart      The start of the final buffer in the original buffer
+     * @param sliceEnd        The end of the final buffer in the original buffer
+     * @param positionInSlice The position parameter in the final buffer
+     * @param limitInSlice    The limited parameter in the final buffer
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int size, int originalSize,
+            int sliceStart, int sliceEnd, int positionInSlice, int limitInSlice,
+            boolean useDirectBuffer) {
+        Random random = new Random();
+
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+        Object sentClientData = new Object();
+        sent.setClientData(sentClientData);
+
+        UsbRequest receive = new UsbRequest();
+        isInited = receive.initialize(connection, in);
+        assertTrue(isInited);
+        Object receiveClientData = new Object();
+        receive.setClientData(receiveClientData);
+
+        ByteBuffer bufferSent;
+        if (useDirectBuffer) {
+            bufferSent = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferSent = ByteBuffer.allocate(originalSize);
+        }
+        for (int i = 0; i < originalSize; i++) {
+            bufferSent.put((byte) random.nextInt());
+        }
+        bufferSent.position(sliceStart);
+        bufferSent.limit(sliceEnd);
+        ByteBuffer bufferSentSliced = bufferSent.slice();
+        bufferSentSliced.position(positionInSlice);
+        bufferSentSliced.limit(limitInSlice);
+
+        bufferSent.position(0);
+        bufferSent.limit(originalSize);
+
+        ByteBuffer bufferReceived;
+        if (useDirectBuffer) {
+            bufferReceived = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferReceived = ByteBuffer.allocate(originalSize);
+        }
+        bufferReceived.position(sliceStart);
+        bufferReceived.limit(sliceEnd);
+        ByteBuffer bufferReceivedSliced = bufferReceived.slice();
+        bufferReceivedSliced.position(positionInSlice);
+        bufferReceivedSliced.limit(limitInSlice);
+
+        bufferReceived.position(0);
+        bufferReceived.limit(originalSize);
+
+        boolean wasQueued = receive.queue(bufferReceivedSliced, size);
+        assertTrue(wasQueued);
+        wasQueued = sent.queue(bufferSentSliced, size);
+        assertTrue(wasQueued);
+
+        for (int reqRun = 0; reqRun < 2; reqRun++) {
+            UsbRequest finished;
+
+            try {
+                finished = connection.requestWait();
+            } catch (IllegalArgumentException e) {
+                if (size > bufferSentSliced.limit() || size > bufferReceivedSliced.limit()) {
+                    Log.e(LOG_TAG, "Expected failure", e);
+                    continue;
+                } else {
+                    throw e;
+                }
+            }
+
+            // Should we have gotten a failure?
+            if (finished == receive) {
+                // We should have gotten an exception if size > limit
+                assumeTrue(bufferReceivedSliced.limit() >= size);
+
+                assertEquals(size, bufferReceivedSliced.position());
+
+                for (int i = 0; i < size; i++) {
+                    if (i < size) {
+                        assertEquals(bufferSent.get(i), bufferReceived.get(i));
+                    } else {
+                        assertEquals(0, bufferReceived.get(i));
+                    }
+                }
+
+                assertSame(receiveClientData, finished.getClientData());
+                assertSame(in, finished.getEndpoint());
+            } else {
+                assertEquals(size, bufferSentSliced.position());
+
+                // We should have gotten an exception if size > limit
+                assumeTrue(bufferSentSliced.limit() >= size);
+                assertSame(sent, finished);
+                assertSame(sentClientData, finished.getClientData());
+                assertSame(out, finished.getEndpoint());
+            }
+            finished.close();
+        }
+    }
+
+    /**
+     * Send a USB request and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     * @param originalSize    The size of the original buffer
+     * @param sliceStart      The start of the final buffer in the original buffer
+     * @param sliceEnd        The end of the final buffer in the original buffer
+     * @param positionInSlice The position parameter in the final buffer
+     * @param limitInSlice    The limited parameter in the final buffer
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
+            @NonNull UsbEndpoint out, int originalSize, int sliceStart, int sliceEnd,
+            int positionInSlice, int limitInSlice, boolean useDirectBuffer,
+            boolean makeSendBufferReadOnly) {
+        Random random = new Random();
+
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+        Object sentClientData = new Object();
+        sent.setClientData(sentClientData);
+
+        UsbRequest receive = new UsbRequest();
+        isInited = receive.initialize(connection, in);
+        assertTrue(isInited);
+        Object receiveClientData = new Object();
+        receive.setClientData(receiveClientData);
+
+        ByteBuffer bufferSent;
+        if (useDirectBuffer) {
+            bufferSent = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferSent = ByteBuffer.allocate(originalSize);
+        }
+        for (int i = 0; i < originalSize; i++) {
+            bufferSent.put((byte) random.nextInt());
+        }
+        if (makeSendBufferReadOnly) {
+            bufferSent = bufferSent.asReadOnlyBuffer();
+        }
+        bufferSent.position(sliceStart);
+        bufferSent.limit(sliceEnd);
+        ByteBuffer bufferSentSliced = bufferSent.slice();
+        bufferSentSliced.position(positionInSlice);
+        bufferSentSliced.limit(limitInSlice);
+
+        bufferSent.position(0);
+        bufferSent.limit(originalSize);
+
+        ByteBuffer bufferReceived;
+        if (useDirectBuffer) {
+            bufferReceived = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferReceived = ByteBuffer.allocate(originalSize);
+        }
+        bufferReceived.position(sliceStart);
+        bufferReceived.limit(sliceEnd);
+        ByteBuffer bufferReceivedSliced = bufferReceived.slice();
+        bufferReceivedSliced.position(positionInSlice);
+        bufferReceivedSliced.limit(limitInSlice);
+
+        bufferReceived.position(0);
+        bufferReceived.limit(originalSize);
+
+        boolean wasQueued = receive.enqueue(bufferReceivedSliced);
+        assertTrue(wasQueued);
+        wasQueued = sent.enqueue(bufferSentSliced);
+        assertTrue(wasQueued);
+
+        for (int reqRun = 0; reqRun < 2; reqRun++) {
+            UsbRequest finished = connection.requestWait();
+
+            if (finished == receive) {
+                assertEquals(limitInSlice, bufferReceivedSliced.limit());
+                assertEquals(limitInSlice, bufferReceivedSliced.position());
+
+                for (int i = 0; i < originalSize; i++) {
+                    if (i >= sliceStart + positionInSlice && i < sliceStart + limitInSlice) {
+                        assertEquals(bufferSent.get(i), bufferReceived.get(i));
+                    } else {
+                        assertEquals(0, bufferReceived.get(i));
+                    }
+                }
+
+                assertSame(receiveClientData, finished.getClientData());
+                assertSame(in, finished.getEndpoint());
+            } else {
+                assertEquals(limitInSlice, bufferSentSliced.limit());
+                assertEquals(limitInSlice, bufferSentSliced.position());
+
+                assertSame(sent, finished);
+                assertSame(sentClientData, finished.getClientData());
+                assertSame(out, finished.getEndpoint());
+            }
+            finished.close();
+        }
+    }
+
+    /**
+     * Send a USB request using the {@link UsbRequest#queue legacy path} and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     * @param size            The size of the request to send
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int size, boolean useDirectBuffer) {
+        echoUsbRequestLegacy(connection, in, out, size, size, 0, size, 0, size, useDirectBuffer);
+    }
+
+    /**
+     * Send a USB request and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     * @param size            The size of the request to send
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
+            @NonNull UsbEndpoint out, int size, boolean useDirectBuffer) {
+        echoUsbRequest(connection, in, out, size, 0, size, 0, size, useDirectBuffer, false);
+    }
+
+    /**
+     * Send a USB request which more than the allowed size and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     */
+    private void echoOversizedUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out) {
+        Random random = new Random();
+        int totalSize = MAX_BUFFER_SIZE * 3 / 2;
+
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        UsbRequest receive = new UsbRequest();
+        isInited = receive.initialize(connection, in);
+        assertTrue(isInited);
+
+        byte[] sentBytes = new byte[totalSize];
+        random.nextBytes(sentBytes);
+        ByteBuffer bufferSent = ByteBuffer.wrap(sentBytes);
+
+        byte[] receivedBytes = new byte[totalSize];
+        ByteBuffer bufferReceived = ByteBuffer.wrap(receivedBytes);
+
+        boolean wasQueued = receive.queue(bufferReceived, totalSize);
+        assertTrue(wasQueued);
+        wasQueued = sent.queue(bufferSent, totalSize);
+        assertTrue(wasQueued);
+
+        for (int requestNum = 0; requestNum < 2; requestNum++) {
+            UsbRequest finished = connection.requestWait();
+            if (finished == receive) {
+                // size beyond MAX_BUFFER_SIZE is ignored
+                for (int i = 0; i < totalSize; i++) {
+                    if (i < MAX_BUFFER_SIZE) {
+                        assertEquals(sentBytes[i], receivedBytes[i]);
+                    } else {
+                        assertEquals(0, receivedBytes[i]);
+                    }
+                }
+            } else {
+                assertSame(sent, finished);
+            }
+            finished.close();
+        }
+    }
+
+    /**
+     * Time out while waiting for USB requests.
+     *
+     * @param connection The connection to use
+     */
+    private void timeoutWhileWaitingForUsbRequest(@NonNull UsbDeviceConnection connection)
+            throws Throwable {
+        runAndAssertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
+
+        long startTime = now();
+        UsbRequest req = connection.requestWait(100);
+        assertNull(req);
+        assertTrue(now() - startTime >= 100);
+        assertTrue(now() - startTime < 400);
+
+        startTime = now();
+        req = connection.requestWait(0);
+        assertNull(req);
+        assertTrue(now() - startTime < 400);
+    }
+
+    /**
+     * Receive a USB request before a timeout triggers
+     *
+     * @param connection The connection to use
+     * @param in         The endpoint to receive requests from
+     */
+    private void receiveAfterTimeout(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, int timeout) throws InterruptedException {
+        UsbRequest reqQueued = new UsbRequest();
+        ByteBuffer buffer = ByteBuffer.allocate(1);
+
+        reqQueued.initialize(connection, in);
+        reqQueued.enqueue(buffer);
+
+        // Let the kernel receive and process the request
+        Thread.sleep(50);
+
+        long startTime = now();
+        UsbRequest reqFinished = connection.requestWait(timeout);
+        assertTrue(now() - startTime < timeout + 50);
+        assertSame(reqQueued, reqFinished);
+        reqFinished.close();
+    }
+
+    /**
+     * Send a USB request with size 0 using the {@link UsbRequest#queue legacy path}.
+     *
+     * @param connection      The connection to use
+     * @param out             The endpoint to send requests to
+     * @param useDirectBuffer Send data from a direct buffer
+     */
+    private void sendZeroLengthRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint out, boolean useDirectBuffer) {
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        ByteBuffer buffer;
+        if (useDirectBuffer) {
+            buffer = ByteBuffer.allocateDirect(0);
+        } else {
+            buffer = ByteBuffer.allocate(0);
+        }
+
+        boolean isQueued = sent.queue(buffer, 0);
+        assumeTrue(isQueued);
+        UsbRequest finished = connection.requestWait();
+        assertSame(finished, sent);
+        finished.close();
+    }
+
+    /**
+     * Send a USB request with size 0.
+     *
+     * @param connection      The connection to use
+     * @param out             The endpoint to send requests to
+     * @param useDirectBuffer Send data from a direct buffer
+     */
+    private void sendZeroLengthRequest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint out, boolean useDirectBuffer) {
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        ByteBuffer buffer;
+        if (useDirectBuffer) {
+            buffer = ByteBuffer.allocateDirect(0);
+        } else {
+            buffer = ByteBuffer.allocate(0);
+        }
+
+        boolean isQueued = sent.enqueue(buffer);
+        assumeTrue(isQueued);
+        UsbRequest finished = connection.requestWait();
+        assertSame(finished, sent);
+        finished.close();
+    }
+
+    /**
+     * Send a USB request with a null buffer.
+     *
+     * @param connection      The connection to use
+     * @param out             The endpoint to send requests to
+     */
+    private void sendNullRequest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint out) {
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        boolean isQueued = sent.enqueue(null);
+        assumeTrue(isQueued);
+        UsbRequest finished = connection.requestWait();
+        assertSame(finished, sent);
+        finished.close();
+    }
+
+    /**
+     * Receive a USB request with size 0.
+     *
+     * @param connection      The connection to use
+     * @param in             The endpoint to recevie requests from
+     */
+    private void receiveZeroLengthRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, boolean useDirectBuffer) {
+        UsbRequest zeroReceived = new UsbRequest();
+        boolean isInited = zeroReceived.initialize(connection, in);
+        assertTrue(isInited);
+
+        UsbRequest oneReceived = new UsbRequest();
+        isInited = oneReceived.initialize(connection, in);
+        assertTrue(isInited);
+
+        ByteBuffer buffer;
+        if (useDirectBuffer) {
+            buffer = ByteBuffer.allocateDirect(0);
+        } else {
+            buffer = ByteBuffer.allocate(0);
+        }
+
+        ByteBuffer buffer1;
+        if (useDirectBuffer) {
+            buffer1 = ByteBuffer.allocateDirect(1);
+        } else {
+            buffer1 = ByteBuffer.allocate(1);
+        }
+
+        boolean isQueued = zeroReceived.enqueue(buffer);
+        assumeTrue(isQueued);
+        isQueued = oneReceived.enqueue(buffer1);
+        assumeTrue(isQueued);
+
+        // We expect both to be returned after some time
+        ArrayList<UsbRequest> finished = new ArrayList<>(2);
+
+        // We expect both request to come back after the delay, but then quickly
+        long startTime = now();
+        finished.add(connection.requestWait());
+        long firstReturned = now();
+        finished.add(connection.requestWait());
+        long secondReturned = now();
+
+        assumeTrue(firstReturned - startTime > 100);
+        assumeTrue(secondReturned - firstReturned < 100);
+
+        assertTrue(finished.contains(zeroReceived));
+        assertTrue(finished.contains(oneReceived));
+    }
+
+    /**
+     * Tests the {@link UsbRequest#queue legacy implementaion} of {@link UsbRequest} and
+     * {@link UsbDeviceConnection#requestWait()}.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     * @throws Throwable
+     */
+    private void usbRequestLegacyTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        // Find bulk in and out endpoints
+        assumeTrue(iface.getEndpointCount() == 2);
+        final UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        final UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+        assertNotNull(in);
+        assertNotNull(out);
+
+        // Single threaded send and receive
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequestLegacy(connection, in, out, 1, true);
+
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequestLegacy(connection, in, out, 1, false);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequestLegacy(connection, in, out, MAX_BUFFER_SIZE, true);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequestLegacy(connection, in, out, MAX_BUFFER_SIZE, false);
+
+        nextTest(connection, in, out, "Echo oversized buffer");
+        echoOversizedUsbRequestLegacy(connection, in, out);
+
+        // Send empty requests
+        sendZeroLengthRequestLegacy(connection, out, true);
+        sendZeroLengthRequestLegacy(connection, out, false);
+
+        // waitRequest with timeout
+        timeoutWhileWaitingForUsbRequest(connection);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveAfterTimeout(connection, in, 400);
+
+        nextTest(connection, in, out, "Receive byte immediately");
+        // Make sure the data is received before we queue the request for it
+        Thread.sleep(50);
+        receiveAfterTimeout(connection, in, 0);
+
+        /* TODO: Unreliable
+
+        // Zero length means waiting for the next data and then return
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequestLegacy(connection, in, true);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequestLegacy(connection, in, true);
+
+        */
+
+        // UsbRequest.queue ignores position, limit, arrayOffset, and capacity
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 42, 5, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 42, 0, 36, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 5, 42, 0, 36, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 36, 0, 31, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 47, 0, 47, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 5, 47, 0, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 42, 0, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 47, 5, 47, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 5, 47, 5, 36, false);
+
+        // Illegal arguments
+        final UsbRequest req1 = new UsbRequest();
+        runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
+        boolean isInited = req1.initialize(connection, in);
+        assertTrue(isInited);
+        runAndAssertException(() -> req1.queue(null, 0), NullPointerException.class);
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
+                IllegalArgumentException.class);
+        req1.close();
+
+        // Cannot queue closed request
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1), 1),
+                NullPointerException.class);
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
+                NullPointerException.class);
+    }
+
+    /**
+     * Repeat c n times
+     *
+     * @param c The character to repeat
+     * @param n The number of times to repeat
+     *
+     * @return c repeated n times
+     */
+    public static String repeat(char c, int n) {
+        final StringBuilder result = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            if (c != ' ' && i % 10 == 0) {
+                result.append(i / 10);
+            } else {
+                result.append(c);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Tests {@link UsbRequest} and {@link UsbDeviceConnection#requestWait()}.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     * @throws Throwable
+     */
+    private void usbRequestTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        // Find bulk in and out endpoints
+        assumeTrue(iface.getEndpointCount() == 2);
+        final UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        final UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+        assertNotNull(in);
+        assertNotNull(out);
+
+        // Single threaded send and receive
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequest(connection, in, out, 1, true);
+
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequest(connection, in, out, 1, false);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequest(connection, in, out, MAX_BUFFER_SIZE, true);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequest(connection, in, out, MAX_BUFFER_SIZE, false);
+
+        // Send empty requests
+        sendZeroLengthRequest(connection, out, true);
+        sendZeroLengthRequest(connection, out, false);
+        sendNullRequest(connection, out);
+
+        /* TODO: Unreliable
+
+        // Zero length means waiting for the next data and then return
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequest(connection, in, true);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequest(connection, in, true);
+
+        */
+
+        for (int startOfSlice : new int[]{0, 1}) {
+            for (int endOffsetOfSlice : new int[]{0, 2}) {
+                for (int positionInSlice : new int[]{0, 5}) {
+                    for (int limitOffsetInSlice : new int[]{0, 11}) {
+                        for (boolean useDirectBuffer : new boolean[]{true, false}) {
+                            for (boolean makeSendBufferReadOnly : new boolean[]{true, false}) {
+                                int sliceSize = 42 + positionInSlice + limitOffsetInSlice;
+                                int originalSize = sliceSize + startOfSlice + endOffsetOfSlice;
+
+                                nextTest(connection, in, out, "Echo 42 bytes");
+
+                                // Log buffer, slice, and data offsets
+                                Log.i(LOG_TAG,
+                                        "buffer" + (makeSendBufferReadOnly ? "(ro): [" : ":     [")
+                                                + repeat('.', originalSize) + "]");
+                                Log.i(LOG_TAG,
+                                        "slice:     " + repeat(' ', startOfSlice) + " [" + repeat(
+                                                '.', sliceSize) + "]");
+                                Log.i(LOG_TAG,
+                                        "data:      " + repeat(' ', startOfSlice + positionInSlice)
+                                                + " [" + repeat('.', 42) + "]");
+
+                                echoUsbRequest(connection, in, out, originalSize, startOfSlice,
+                                        originalSize - endOffsetOfSlice, positionInSlice,
+                                        sliceSize - limitOffsetInSlice, useDirectBuffer,
+                                        makeSendBufferReadOnly);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Illegal arguments
+        final UsbRequest req1 = new UsbRequest();
+        runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
+        boolean isInited = req1.initialize(connection, in);
+        assertTrue(isInited);
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
+                IllegalArgumentException.class);
+        req1.close();
+
+        // Cannot queue closed request
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1)),
+                IllegalStateException.class);
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
+                IllegalStateException.class);
+
+        // Initialize
+        UsbRequest req2 = new UsbRequest();
+        isInited = req2.initialize(connection, in);
+        assertTrue(isInited);
+        isInited = req2.initialize(connection, out);
+        assertTrue(isInited);
+        req2.close();
+
+        // Close
+        req2 = new UsbRequest();
+        req2.close();
+
+        req2.initialize(connection, in);
+        req2.close();
+        req2.close();
+    }
+
+    /** State of a {@link UsbRequest} in flight */
+    private static class RequestState {
+        final ByteBuffer buffer;
+        final Object clientData;
+
+        private RequestState(ByteBuffer buffer, Object clientData) {
+            this.buffer = buffer;
+            this.clientData = clientData;
+        }
+    }
+
+    /** Recycles elements that might be expensive to create */
+    private abstract class Recycler<T> {
+        private final Random mRandom;
+        private final LinkedList<T> mData;
+
+        protected Recycler() {
+            mData = new LinkedList<>();
+            mRandom = new Random();
+        }
+
+        /**
+         * Add a new element to be recycled.
+         *
+         * @param newElement The element that is not used anymore and can be used by someone else.
+         */
+        private void recycle(@NonNull T newElement) {
+            synchronized (mData) {
+                if (mRandom.nextBoolean()) {
+                    mData.addLast(newElement);
+                } else {
+                    mData.addFirst(newElement);
+                }
+            }
+        }
+
+        /**
+         * Get a recycled element or create a new one if needed.
+         *
+         * @return An element that can be used (maybe recycled)
+         */
+        private @NonNull T get() {
+            T recycledElement;
+
+            try {
+                synchronized (mData) {
+                    recycledElement = mData.pop();
+                }
+            } catch (NoSuchElementException ignored) {
+                recycledElement = create();
+            }
+
+            reset(recycledElement);
+
+            return recycledElement;
+        }
+
+        /** Reset internal state of {@code recycledElement} */
+        protected abstract void reset(@NonNull T recycledElement);
+
+        /** Create a new element */
+        protected abstract @NonNull T create();
+
+        /** Get all elements that are currently recycled and waiting to be used again */
+        public @NonNull LinkedList<T> getAll() {
+            return mData;
+        }
+    }
+
+    /**
+     * Common code between {@link QueuerThread} and {@link ReceiverThread}.
+     */
+    private class TestThread extends Thread {
+        /** State copied from the main thread (see runTest()) */
+        protected final UsbDeviceConnection mConnection;
+        protected final Recycler<UsbRequest> mInRequestRecycler;
+        protected final Recycler<UsbRequest> mOutRequestRecycler;
+        protected final Recycler<ByteBuffer> mBufferRecycler;
+        protected final HashMap<UsbRequest, RequestState> mRequestsInFlight;
+        protected final HashMap<Integer, Integer> mData;
+        protected final ArrayList<Throwable> mErrors;
+
+        protected volatile boolean mShouldStop;
+
+        TestThread(@NonNull UsbDeviceConnection connection,
+                @NonNull Recycler<UsbRequest> inRequestRecycler,
+                @NonNull Recycler<UsbRequest> outRequestRecycler,
+                @NonNull Recycler<ByteBuffer> bufferRecycler,
+                @NonNull HashMap<UsbRequest, RequestState> requestsInFlight,
+                @NonNull HashMap<Integer, Integer> data,
+                @NonNull ArrayList<Throwable> errors) {
+            super();
+
+            mShouldStop = false;
+            mConnection = connection;
+            mBufferRecycler = bufferRecycler;
+            mInRequestRecycler = inRequestRecycler;
+            mOutRequestRecycler = outRequestRecycler;
+            mRequestsInFlight = requestsInFlight;
+            mData = data;
+            mErrors = errors;
+        }
+
+        /**
+         * Stop thread
+         */
+        void abort() {
+            mShouldStop = true;
+            interrupt();
+        }
+    }
+
+    /**
+     * A thread that queues matching write and read {@link UsbRequest requests}. We expect the
+     * writes to be echoed back and return in unchanged in the read requests.
+     * <p> This thread just issues the requests and does not care about them anymore after the
+     * system took them. The {@link ReceiverThread} handles the result of both write and read
+     * requests.</p>
+     */
+    private class QueuerThread extends TestThread {
+        private static final int MAX_IN_FLIGHT = 64;
+        private static final long RUN_TIME = 10 * 1000;
+
+        private final AtomicInteger mCounter;
+
+        /**
+         * Create a new thread that queues matching write and read UsbRequests.
+         *
+         * @param connection Connection to communicate with
+         * @param inRequestRecycler Pool of in-requests that can be reused
+         * @param outRequestRecycler Pool of out-requests that can be reused
+         * @param bufferRecycler Pool of byte buffers that can be reused
+         * @param requestsInFlight State of the requests currently in flight
+         * @param data Mapping counter -> data
+         * @param counter An atomic counter
+         * @param errors Pool of throwables created by threads like this
+         */
+        QueuerThread(@NonNull UsbDeviceConnection connection,
+                @NonNull Recycler<UsbRequest> inRequestRecycler,
+                @NonNull Recycler<UsbRequest> outRequestRecycler,
+                @NonNull Recycler<ByteBuffer> bufferRecycler,
+                @NonNull HashMap<UsbRequest, RequestState> requestsInFlight,
+                @NonNull HashMap<Integer, Integer> data,
+                @NonNull AtomicInteger counter,
+                @NonNull ArrayList<Throwable> errors) {
+            super(connection, inRequestRecycler, outRequestRecycler, bufferRecycler,
+                    requestsInFlight, data, errors);
+
+            mCounter = counter;
+        }
+
+        @Override
+        public void run() {
+            Random random = new Random();
+
+            long endTime = now() + RUN_TIME;
+
+            while (now() < endTime && !mShouldStop) {
+                try {
+                    int counter = mCounter.getAndIncrement();
+
+                    if (counter % 1024 == 0) {
+                        Log.i(LOG_TAG, "Counter is " + counter);
+                    }
+
+                    // Write [1:counter:data]
+                    UsbRequest writeRequest = mOutRequestRecycler.get();
+                    ByteBuffer writeBuffer = mBufferRecycler.get();
+                    int data = random.nextInt();
+                    writeBuffer.put((byte)1).putInt(counter).putInt(data);
+                    writeBuffer.flip();
+
+                    // Send read that will receive the data back from the write as the other side
+                    // will echo all requests.
+                    UsbRequest readRequest = mInRequestRecycler.get();
+                    ByteBuffer readBuffer = mBufferRecycler.get();
+
+                    // Register requests
+                    synchronized (mRequestsInFlight) {
+                        // Wait until previous requests were processed
+                        while (mRequestsInFlight.size() > MAX_IN_FLIGHT) {
+                            try {
+                                mRequestsInFlight.wait();
+                            } catch (InterruptedException e) {
+                                break;
+                            }
+                        }
+
+                        if (mShouldStop) {
+                            break;
+                        } else {
+                            mRequestsInFlight.put(writeRequest, new RequestState(writeBuffer,
+                                    writeRequest.getClientData()));
+                            mRequestsInFlight.put(readRequest, new RequestState(readBuffer,
+                                    readRequest.getClientData()));
+                            mRequestsInFlight.notifyAll();
+                        }
+                    }
+
+                    // Store which data was written for the counter
+                    synchronized (mData) {
+                        mData.put(counter, data);
+                    }
+
+                    // Send both requests to the system. Once they finish the ReceiverThread will
+                    // be notified
+                    boolean isQueued = writeRequest.enqueue(writeBuffer);
+                    assertTrue(isQueued);
+
+                    isQueued = readRequest.queue(readBuffer, 9);
+                    assertTrue(isQueued);
+                } catch (Throwable t) {
+                    synchronized (mErrors) {
+                        mErrors.add(t);
+                        mErrors.notify();
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * A thread that receives processed UsbRequests and compares the expected result. The requests
+     * can be both read and write requests. The requests were created and given to the system by
+     * the {@link QueuerThread}.
+     */
+    private class ReceiverThread extends TestThread {
+        private final UsbEndpoint mOut;
+
+        /**
+         * Create a thread that receives processed UsbRequests and compares the expected result.
+         *
+         * @param connection Connection to communicate with
+         * @param out Endpoint to queue write requests on
+         * @param inRequestRecycler Pool of in-requests that can be reused
+         * @param outRequestRecycler Pool of out-requests that can be reused
+         * @param bufferRecycler Pool of byte buffers that can be reused
+         * @param requestsInFlight State of the requests currently in flight
+         * @param data Mapping counter -> data
+         * @param errors Pool of throwables created by threads like this
+         */
+        ReceiverThread(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint out,
+                @NonNull Recycler<UsbRequest> inRequestRecycler,
+                @NonNull Recycler<UsbRequest> outRequestRecycler,
+                @NonNull Recycler<ByteBuffer> bufferRecycler,
+                @NonNull HashMap<UsbRequest, RequestState> requestsInFlight,
+                @NonNull HashMap<Integer, Integer> data, @NonNull ArrayList<Throwable> errors) {
+            super(connection, inRequestRecycler, outRequestRecycler, bufferRecycler,
+                    requestsInFlight, data, errors);
+
+            mOut = out;
+        }
+
+        @Override
+        public void run() {
+            while (!mShouldStop) {
+                try {
+                    // Wait until a request is queued as mConnection.requestWait() cannot be
+                    // interrupted.
+                    synchronized (mRequestsInFlight) {
+                        while (mRequestsInFlight.isEmpty()) {
+                            try {
+                                mRequestsInFlight.wait();
+                            } catch (InterruptedException e) {
+                                break;
+                            }
+                        }
+
+                        if (mShouldStop) {
+                            break;
+                        }
+                    }
+
+                    // Receive request
+                    UsbRequest request = mConnection.requestWait();
+                    assertNotNull(request);
+
+                    // Find the state the request should have
+                    RequestState state;
+                    synchronized (mRequestsInFlight) {
+                        state = mRequestsInFlight.remove(request);
+                        mRequestsInFlight.notifyAll();
+                    }
+
+                    // Compare client data
+                    assertSame(state.clientData, request.getClientData());
+
+                    // There is nothing more to check about write requests, but for read requests
+                    // (the ones going to an out endpoint) we know that it just an echoed back write
+                    // request.
+                    if (!request.getEndpoint().equals(mOut)) {
+                        state.buffer.flip();
+
+                        // Read request buffer, check that data is correct
+                        byte alive = state.buffer.get();
+                        int counter = state.buffer.getInt();
+                        int receivedData = state.buffer.getInt();
+
+                        // We stored which data-combinations were written
+                        int expectedData;
+                        synchronized(mData) {
+                            expectedData = mData.remove(counter);
+                        }
+
+                        // Make sure read request matches a write request we sent before
+                        assertEquals(1, alive);
+                        assertEquals(expectedData, receivedData);
+                    }
+
+                    // Recycle buffers and requests so they can be reused later.
+                    mBufferRecycler.recycle(state.buffer);
+
+                    if (request.getEndpoint().equals(mOut)) {
+                        mOutRequestRecycler.recycle(request);
+                    } else {
+                        mInRequestRecycler.recycle(request);
+                    }
+                } catch (Throwable t) {
+                    synchronized (mErrors) {
+                        mErrors.add(t);
+                        mErrors.notify();
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Tests parallel issuance and receiving of {@link UsbRequest usb requests}.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     */
+    private void parallelUsbRequestsTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) {
+        // Find bulk in and out endpoints
+        assumeTrue(iface.getEndpointCount() == 2);
+        final UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        final UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+        assertNotNull(in);
+        assertNotNull(out);
+
+        // Recycler for requests for the in-endpoint
+        Recycler<UsbRequest> inRequestRecycler = new Recycler<UsbRequest>() {
+            @Override
+            protected void reset(@NonNull UsbRequest recycledElement) {
+                recycledElement.setClientData(new Object());
+            }
+
+            @Override
+            protected @NonNull UsbRequest create() {
+                UsbRequest request = new UsbRequest();
+                request.initialize(connection, in);
+
+                return request;
+            }
+        };
+
+        // Recycler for requests for the in-endpoint
+        Recycler<UsbRequest> outRequestRecycler = new Recycler<UsbRequest>() {
+            @Override
+            protected void reset(@NonNull UsbRequest recycledElement) {
+                recycledElement.setClientData(new Object());
+            }
+
+            @Override
+            protected @NonNull UsbRequest create() {
+                UsbRequest request = new UsbRequest();
+                request.initialize(connection, out);
+
+                return request;
+            }
+        };
+
+        // Recycler for requests for read and write buffers
+        Recycler<ByteBuffer> bufferRecycler = new Recycler<ByteBuffer>() {
+            @Override
+            protected void reset(@NonNull ByteBuffer recycledElement) {
+                recycledElement.rewind();
+            }
+
+            @Override
+            protected @NonNull ByteBuffer create() {
+                return ByteBuffer.allocateDirect(9);
+            }
+        };
+
+        HashMap<UsbRequest, RequestState> requestsInFlight = new HashMap<>();
+
+        // Data in the requests
+        HashMap<Integer, Integer> data = new HashMap<>();
+        AtomicInteger counter = new AtomicInteger(0);
+
+        // Errors created in the threads
+        ArrayList<Throwable> errors = new ArrayList<>();
+
+        // Create two threads that queue read and write requests
+        QueuerThread queuer1 = new QueuerThread(connection, inRequestRecycler,
+                outRequestRecycler, bufferRecycler, requestsInFlight, data, counter, errors);
+        QueuerThread queuer2 = new QueuerThread(connection, inRequestRecycler,
+                outRequestRecycler, bufferRecycler, requestsInFlight, data, counter, errors);
+
+        // Create a thread that receives the requests after they are processed.
+        ReceiverThread receiver = new ReceiverThread(connection, out, inRequestRecycler,
+                outRequestRecycler, bufferRecycler, requestsInFlight, data, errors);
+
+        nextTest(connection, in, out, "Echo until stop signal");
+
+        queuer1.start();
+        queuer2.start();
+        receiver.start();
+
+        Log.i(LOG_TAG, "Waiting for queuers to stop");
+
+        try {
+            queuer1.join();
+            queuer2.join();
+        } catch (InterruptedException e) {
+            synchronized(errors) {
+                errors.add(e);
+            }
+        }
+
+        if (errors.isEmpty()) {
+            Log.i(LOG_TAG, "Wait for all requests to finish");
+            synchronized (requestsInFlight) {
+                while (!requestsInFlight.isEmpty()) {
+                    try {
+                        requestsInFlight.wait();
+                    } catch (InterruptedException e) {
+                        synchronized(errors) {
+                            errors.add(e);
+                        }
+                        break;
+                    }
+                }
+            }
+
+            receiver.abort();
+
+            try {
+                receiver.join();
+            } catch (InterruptedException e) {
+                synchronized(errors) {
+                    errors.add(e);
+                }
+            }
+
+            // Close all requests that are currently recycled
+            inRequestRecycler.getAll().forEach(UsbRequest::close);
+            outRequestRecycler.getAll().forEach(UsbRequest::close);
+        } else {
+            receiver.abort();
+        }
+
+        for (Throwable t : errors) {
+            Log.e(LOG_TAG, "Error during test", t);
+        }
+
+        byte[] stopBytes = new byte[9];
+        connection.bulkTransfer(out, stopBytes, 9, 0);
+
+        // If we had any error make the test fail
+        assertEquals(0, errors.size());
+    }
+
+    /**
+     * Tests {@link UsbDeviceConnection#bulkTransfer}.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     * @throws Throwable
+     */
+    private void bulkTransferTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        // Find bulk in and out endpoints
+        assumeTrue(iface.getEndpointCount() == 2);
+        final UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        final UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+        assertNotNull(in);
+        assertNotNull(out);
+
+        // Transmission tests
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoBulkTransfer(connection, in, out, 1);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoBulkTransferOffset(connection, in, out, 23, 42);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoBulkTransfer(connection, in, out, MAX_BUFFER_SIZE);
+
+        nextTest(connection, in, out, "Echo oversized buffer");
+        echoOversizedBulkTransfer(connection, in, out);
+
+        nextTest(connection, in, out, "Receive oversized buffer");
+        receiveOversizedBulkTransfer(connection, in);
+
+        // Illegal arguments
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 2, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 2, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[2], 1, 2, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[2], 1, 2, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 1, -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 1, -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, -1, 0),
+                IllegalArgumentException.class);
+        runAndAssertException(() -> connection.bulkTransfer(null, new byte[1], 1, 0),
+                NullPointerException.class);
+
+        // Transmissions that do nothing
+        int numSent = connection.bulkTransfer(out, null, 0, 0);
+        assertEquals(0, numSent);
+
+        numSent = connection.bulkTransfer(out, null, 0, 0, 0);
+        assertEquals(0, numSent);
+
+        numSent = connection.bulkTransfer(out, new byte[0], 0, 0);
+        assertEquals(0, numSent);
+
+        numSent = connection.bulkTransfer(out, new byte[0], 0, 0, 0);
+        assertEquals(0, numSent);
+
+        numSent = connection.bulkTransfer(out, new byte[2], 2, 0, 0);
+        assertEquals(0, numSent);
+
+        /* TODO: These tests are flaky as they appear to be affected by previous tests
+
+        // Transmissions that do not transfer data:
+        // - first transfer blocks until data is received, but does not return the data.
+        // - The data is read in the second transfer
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveWithEmptyBuffer(connection, in, null, 0, 0);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveWithEmptyBuffer(connection, in, new byte[0], 0, 0);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveWithEmptyBuffer(connection, in, new byte[2], 2, 0);
+
+        */
+
+        // Timeouts
+        int numReceived = connection.bulkTransfer(in, new byte[1], 1, 100);
+        assertEquals(-1, numReceived);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        numReceived = connection.bulkTransfer(in, new byte[1], 1, 10000);
+        assertEquals(1, numReceived);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        numReceived = connection.bulkTransfer(in, new byte[1], 1, 0);
+        assertEquals(1, numReceived);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        numReceived = connection.bulkTransfer(in, new byte[1], 1, -1);
+        assertEquals(1, numReceived);
+
+        numReceived = connection.bulkTransfer(in, new byte[2], 1, 1, 100);
+        assertEquals(-1, numReceived);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        numReceived = connection.bulkTransfer(in, new byte[2], 1, 1, 0);
+        assertEquals(1, numReceived);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        numReceived = connection.bulkTransfer(in, new byte[2], 1, 1, -1);
+        assertEquals(1, numReceived);
+    }
+
+    /**
+     * Send signal to the remove device that testing is finished.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     */
+    private void endTesting(@NonNull UsbDeviceConnection connection, @NonNull UsbInterface iface) {
+        // "done" signals that testing is over
+        nextTest(connection, getEndpoint(iface, UsbConstants.USB_DIR_IN),
+                getEndpoint(iface, UsbConstants.USB_DIR_OUT), "done");
+    }
+
+    /**
+     * Test the behavior of {@link UsbDeviceConnection#claimInterface} and
+     * {@link UsbDeviceConnection#releaseInterface}.
+     *
+     * <p>Note: The interface under test is <u>not</u> claimed by a kernel driver, hence there is
+     * no difference in behavior between force and non-force versions of
+     * {@link UsbDeviceConnection#claimInterface}</p>
+     *
+     * @param connection The connection to use
+     * @param iface The interface to claim and release
+     *
+     * @throws Throwable
+     */
+    private void claimInterfaceTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        // The interface is not claimed by the kernel driver, so not forcing it should work
+        boolean claimed = connection.claimInterface(iface, false);
+        assertTrue(claimed);
+        boolean released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        // Forcing if it is not necessary does no harm
+        claimed = connection.claimInterface(iface, true);
+        assertTrue(claimed);
+
+        // Re-claiming does nothing
+        claimed = connection.claimInterface(iface, true);
+        assertTrue(claimed);
+
+        released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        // Re-releasing is not allowed
+        released = connection.releaseInterface(iface);
+        assertFalse(released);
+
+        // Using an unclaimed interface claims it automatically
+        int numSent = connection.bulkTransfer(getEndpoint(iface, UsbConstants.USB_DIR_OUT), null, 0,
+                0);
+        assertEquals(0, numSent);
+
+        released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        runAndAssertException(() -> connection.claimInterface(null, true),
+                NullPointerException.class);
+        runAndAssertException(() -> connection.claimInterface(null, false),
+                NullPointerException.class);
+        runAndAssertException(() -> connection.releaseInterface(null), NullPointerException.class);
+    }
+
+    /**
+     * Test all input parameters to {@link UsbDeviceConnection#setConfiguration} .
+     *
+     * <p>Note:
+     * <ul>
+     *     <li>The device under test only supports one configuration, hence changing configuration
+     * is not tested.</li>
+     *     <li>This test sets the current configuration again. This resets the device.</li>
+     * </ul></p>
+     *
+     * @param device the device under test
+     * @param connection The connection to use
+     * @param iface An interface of the device
+     *
+     * @throws Throwable
+     */
+    private void setConfigurationTests(@NonNull UsbDevice device,
+            @NonNull UsbDeviceConnection connection, @NonNull UsbInterface iface) throws Throwable {
+        assumeTrue(device.getConfigurationCount() == 1);
+        boolean wasSet = connection.setConfiguration(device.getConfiguration(0));
+        assertTrue(wasSet);
+
+        // Cannot set configuration for a device with a claimed interface
+        boolean claimed = connection.claimInterface(iface, false);
+        assertTrue(claimed);
+        wasSet = connection.setConfiguration(device.getConfiguration(0));
+        assertFalse(wasSet);
+        boolean released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        runAndAssertException(() -> connection.setConfiguration(null), NullPointerException.class);
+    }
+
+    /**
+     * Test all input parameters to {@link UsbDeviceConnection#setConfiguration} .
+     *
+     * <p>Note: The interface under test only supports one settings, hence changing the setting can
+     * not be tested.</p>
+     *
+     * @param connection The connection to use
+     * @param iface The interface to test
+     *
+     * @throws Throwable
+     */
+    private void setInterfaceTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        boolean claimed = connection.claimInterface(iface, false);
+        assertTrue(claimed);
+        boolean wasSet = connection.setInterface(iface);
+        assertTrue(wasSet);
+        boolean released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        // Setting the interface for an unclaimed interface automatically claims it
+        wasSet = connection.setInterface(iface);
+        assertTrue(wasSet);
+        released = connection.releaseInterface(iface);
+        assertTrue(released);
+
+        runAndAssertException(() -> connection.setInterface(null), NullPointerException.class);
+    }
+
+    /**
+     * Enumerate all known devices and check basic relationship between the properties.
+     */
+    private void enumerateDevices() throws Exception {
+        Set<Integer> knownDeviceIds = new ArraySet<>();
+
+        for (Map.Entry<String, UsbDevice> entry : mUsbManager.getDeviceList().entrySet()) {
+            UsbDevice device = entry.getValue();
+
+            assertEquals(entry.getKey(), device.getDeviceName());
+            assertNotNull(device.getDeviceName());
+
+            // Device ID should be unique
+            assertFalse(knownDeviceIds.contains(device.getDeviceId()));
+            knownDeviceIds.add(device.getDeviceId());
+
+            assertEquals(device.getDeviceName(), UsbDevice.getDeviceName(device.getDeviceId()));
+
+            // Properties without constraints
+            device.getManufacturerName();
+            device.getProductName();
+            device.getVersion();
+            device.getSerialNumber();
+            device.getVendorId();
+            device.getProductId();
+            device.getDeviceClass();
+            device.getDeviceSubclass();
+            device.getDeviceProtocol();
+
+            Set<UsbInterface> interfacesFromAllConfigs = new ArraySet<>();
+            Set<Pair<Integer, Integer>> knownInterfaceIds = new ArraySet<>();
+            Set<Integer> knownConfigurationIds = new ArraySet<>();
+            int numConfigurations = device.getConfigurationCount();
+            for (int configNum = 0; configNum < numConfigurations; configNum++) {
+                UsbConfiguration config = device.getConfiguration(configNum);
+
+                // Configuration ID should be unique
+                assertFalse(knownConfigurationIds.contains(config.getId()));
+                knownConfigurationIds.add(config.getId());
+
+                assertTrue(config.getMaxPower() >= 0);
+
+                // Properties without constraints
+                config.getName();
+                config.isSelfPowered();
+                config.isRemoteWakeup();
+
+                int numInterfaces = config.getInterfaceCount();
+                for (int interfaceNum = 0; interfaceNum < numInterfaces; interfaceNum++) {
+                    UsbInterface iface = config.getInterface(interfaceNum);
+                    interfacesFromAllConfigs.add(iface);
+
+                    Pair<Integer, Integer> ifaceId = new Pair<>(iface.getId(),
+                            iface.getAlternateSetting());
+                    assertFalse(knownInterfaceIds.contains(ifaceId));
+                    knownInterfaceIds.add(ifaceId);
+
+                    // Properties without constraints
+                    iface.getName();
+                    iface.getInterfaceClass();
+                    iface.getInterfaceSubclass();
+                    iface.getInterfaceProtocol();
+
+                    int numEndpoints = iface.getEndpointCount();
+                    for (int endpointNum = 0; endpointNum < numEndpoints; endpointNum++) {
+                        UsbEndpoint endpoint = iface.getEndpoint(endpointNum);
+
+                        assertEquals(endpoint.getAddress(),
+                                endpoint.getEndpointNumber() | endpoint.getDirection());
+
+                        assertTrue(endpoint.getDirection() == UsbConstants.USB_DIR_OUT ||
+                                endpoint.getDirection() == UsbConstants.USB_DIR_IN);
+
+                        assertTrue(endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL ||
+                                endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_ISOC ||
+                                endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK ||
+                                endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT);
+
+                        assertTrue(endpoint.getMaxPacketSize() >= 0);
+                        assertTrue(endpoint.getInterval() >= 0);
+
+                        // Properties without constraints
+                        endpoint.getAttributes();
+                    }
+                }
+            }
+
+            int numInterfaces = device.getInterfaceCount();
+            for (int interfaceNum = 0; interfaceNum < numInterfaces; interfaceNum++) {
+                assertTrue(interfacesFromAllConfigs.contains(device.getInterface(interfaceNum)));
+            }
+        }
+    }
+
+    /**
+     * Run tests.
+     *
+     * @param device The device to run the test against. This device is running
+     *               com.android.cts.verifierusbcompanion.DeviceTestCompanion
+     */
+    private void runTests(@NonNull UsbDevice device) {
+        try {
+            // Find the AOAP interface
+            UsbInterface iface = null;
+            for (int i = 0; i < device.getConfigurationCount(); i++) {
+                if (device.getInterface(i).getName().equals("Android Accessory Interface")) {
+                    iface = device.getInterface(i);
+                    break;
+                }
+            }
+            assumeNotNull(iface);
+
+            enumerateDevices();
+
+            UsbDeviceConnection connection = mUsbManager.openDevice(device);
+            assertNotNull(connection);
+
+            claimInterfaceTests(connection, iface);
+
+            boolean claimed = connection.claimInterface(iface, false);
+            assertTrue(claimed);
+
+            usbRequestLegacyTests(connection, iface);
+            usbRequestTests(connection, iface);
+            parallelUsbRequestsTests(connection, iface);
+            ctrlTransferTests(connection);
+            bulkTransferTests(connection, iface);
+
+            // Signal to the DeviceTestCompanion that there are no more transfer test
+            endTesting(connection, iface);
+            boolean released = connection.releaseInterface(iface);
+            assertTrue(released);
+
+            setInterfaceTests(connection, iface);
+            setConfigurationTests(device, connection, iface);
+
+            assertFalse(connection.getFileDescriptor() == -1);
+            assertNotNull(connection.getRawDescriptors());
+            assertFalse(connection.getRawDescriptors().length == 0);
+            assertEquals(device.getSerialNumber(), connection.getSerial());
+
+            connection.close();
+
+            // We should not be able to communicate with the device anymore
+            assertFalse(connection.claimInterface(iface, true));
+            assertFalse(connection.releaseInterface(iface));
+            assertFalse(connection.setConfiguration(device.getConfiguration(0)));
+            assertFalse(connection.setInterface(iface));
+            assertTrue(connection.getFileDescriptor() == -1);
+            assertNull(connection.getRawDescriptors());
+            assertNull(connection.getSerial());
+            assertEquals(-1, connection.bulkTransfer(getEndpoint(iface, UsbConstants.USB_DIR_OUT),
+                    new byte[1], 1, 0));
+            assertEquals(-1, connection.bulkTransfer(getEndpoint(iface, UsbConstants.USB_DIR_OUT),
+                    null, 0, 0));
+            assertEquals(-1, connection.bulkTransfer(getEndpoint(iface, UsbConstants.USB_DIR_IN),
+                    null, 0, 0));
+            assertFalse((new UsbRequest()).initialize(connection, getEndpoint(iface,
+                    UsbConstants.USB_DIR_IN)));
+
+            // Double close should do no harm
+            connection.close();
+
+            setTestResultAndFinish(true);
+        } catch (AssumptionViolatedException e) {
+            // Assumptions failing means that somehow the device/connection is set up incorrectly
+            Toast.makeText(this, getString(R.string.usb_device_unexpected, e.getLocalizedMessage()),
+                    Toast.LENGTH_LONG).show();
+        } catch (Throwable e) {
+            fail(null, e);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (mUsbDeviceConnectionReceiver != null) {
+            unregisterReceiver(mUsbDeviceConnectionReceiver);
+        }
+
+        super.onDestroy();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java
new file mode 100644
index 0000000..e0538f5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java
@@ -0,0 +1,422 @@
+/*
+ * 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.usb.mtp;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
+import android.mtp.MtpDevice;
+import android.mtp.MtpDeviceInfo;
+import android.mtp.MtpEvent;
+import android.mtp.MtpObjectInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.util.MutableInt;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import junit.framework.AssertionFailedError;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MtpHostTestActivity extends PassFailButtons.Activity implements Handler.Callback {
+    private static final int MESSAGE_PASS = 0;
+    private static final int MESSAGE_FAIL = 1;
+    private static final int MESSAGE_RUN = 2;
+
+    private static final int ITEM_STATE_PASS = 0;
+    private static final int ITEM_STATE_FAIL = 1;
+    private static final int ITEM_STATE_INDETERMINATE = 2;
+
+    /**
+     * Subclass for PTP.
+     */
+    private static final int SUBCLASS_STILL_IMAGE_CAPTURE = 1;
+
+    /**
+     * Subclass for Android style MTP.
+     */
+    private static final int SUBCLASS_MTP = 0xff;
+
+    /**
+     * Protocol for Picture Transfer Protocol (PIMA 15470).
+     */
+    private static final int PROTOCOL_PICTURE_TRANSFER = 1;
+
+    /**
+     * Protocol for Android style MTP.
+     */
+    private static final int PROTOCOL_MTP = 0;
+
+    private static final int RETRY_DELAY_MS = 1000;
+
+    private static final String ACTION_PERMISSION_GRANTED =
+            "com.android.cts.verifier.usb.ACTION_PERMISSION_GRANTED";
+
+    private static final String TEST_FILE_NAME = "CtsVerifierTest_testfile.txt";
+    private static final byte[] TEST_FILE_CONTENTS =
+            "This is a test file created by CTS verifier test.".getBytes(StandardCharsets.US_ASCII);
+
+    private final Handler mHandler = new Handler(this);
+    private int mStep;
+    private final ArrayList<TestItem> mItems = new ArrayList<>();
+
+    private UsbManager mUsbManager;
+    private BroadcastReceiver mReceiver;
+    private UsbDevice mUsbDevice;
+    private MtpDevice mMtpDevice;
+    private ExecutorService mExecutor;
+    private TextView mErrorText;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.mtp_host_activity);
+        setInfoResources(R.string.mtp_host_test, R.string.mtp_host_test_info, -1);
+        setPassFailButtonClickListeners();
+
+        final LayoutInflater inflater = getLayoutInflater();
+        final LinearLayout itemsView = (LinearLayout) findViewById(R.id.mtp_host_list);
+
+        mErrorText = (TextView) findViewById(R.id.error_text);
+
+        // Don't allow a test pass until all steps are passed.
+        getPassButton().setEnabled(false);
+
+        // Build test items.
+        mItems.add(new TestItem(
+                inflater,
+                R.string.mtp_host_device_lookup_message,
+                new int[] { R.id.next_item_button }));
+        mItems.add(new TestItem(
+                inflater,
+                R.string.mtp_host_grant_permission_message,
+                null));
+        mItems.add(new TestItem(
+                inflater,
+                R.string.mtp_host_test_read_event_message,
+                null));
+        mItems.add(new TestItem(
+                inflater,
+                R.string.mtp_host_test_send_object_message,
+                null));
+        mItems.add(new TestItem(
+                inflater,
+                R.string.mtp_host_test_notification_message,
+                new int[] { R.id.pass_item_button, R.id.fail_item_button }));
+        for (final TestItem item : mItems) {
+            itemsView.addView(item.view);
+        }
+
+        mExecutor = Executors.newSingleThreadExecutor();
+        mUsbManager = getSystemService(UsbManager.class);
+
+        mStep = 0;
+        mHandler.sendEmptyMessage(MESSAGE_RUN);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mReceiver != null) {
+            unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        final TestItem item = mStep < mItems.size() ? mItems.get(mStep) : null;
+
+        switch (msg.what) {
+            case MESSAGE_RUN:
+                if (item == null) {
+                    getPassButton().setEnabled(true);
+                    return true;
+                }
+                item.setEnabled(true);
+                mExecutor.execute(new Runnable() {
+                    private final int mCurrentStep = mStep;
+
+                    @Override
+                    public void run() {
+                        try {
+                            int i = mCurrentStep;
+                            if (i-- == 0) stepFindMtpDevice();
+                            if (i-- == 0) stepGrantPermission();
+                            if (i-- == 0) stepTestReadEvent();
+                            if (i-- == 0) stepTestSendObject();
+                            if (i-- == 0) stepTestNotification();
+                            mHandler.sendEmptyMessage(MESSAGE_PASS);
+                        } catch (Exception | AssertionFailedError exception) {
+                            mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_FAIL, exception));
+                        }
+                    }
+                });
+                break;
+
+            case MESSAGE_PASS:
+                item.setState(ITEM_STATE_PASS);
+                item.setEnabled(false);
+                mStep++;
+                mHandler.sendEmptyMessage(MESSAGE_RUN);
+                break;
+
+            case MESSAGE_FAIL:
+                item.setState(ITEM_STATE_FAIL);
+                item.setEnabled(false);
+                final StringWriter writer = new StringWriter();
+                final Throwable throwable = (Throwable) msg.obj;
+                throwable.printStackTrace(new PrintWriter(writer));
+                mErrorText.setText(writer.toString());
+                break;
+        }
+
+        return true;
+    }
+
+    private void stepFindMtpDevice() throws InterruptedException {
+        assertEquals(R.id.next_item_button, waitForButtonClick());
+
+        UsbDevice device = null;
+        for (final UsbDevice candidate : mUsbManager.getDeviceList().values()) {
+            if (isMtpDevice(candidate)) {
+                device = candidate;
+                break;
+            }
+        }
+        assertNotNull(device);
+        mUsbDevice = device;
+    }
+
+    private void stepGrantPermission() throws InterruptedException {
+        if (!mUsbManager.hasPermission(mUsbDevice)) {
+            final CountDownLatch latch = new CountDownLatch(1);
+            mReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    unregisterReceiver(this);
+                    mReceiver = null;
+                    latch.countDown();
+                }
+            };
+            registerReceiver(mReceiver, new IntentFilter(ACTION_PERMISSION_GRANTED));
+            mUsbManager.requestPermission(
+                    mUsbDevice,
+                    PendingIntent.getBroadcast(
+                            MtpHostTestActivity.this, 0, new Intent(ACTION_PERMISSION_GRANTED), 0));
+
+            latch.await();
+            assertTrue(mUsbManager.hasPermission(mUsbDevice));
+        }
+
+        final UsbDeviceConnection connection = mUsbManager.openDevice(mUsbDevice);
+        assertNotNull(connection);
+
+        // Try to rob device ownership from other applications.
+        for (int i = 0; i < mUsbDevice.getInterfaceCount(); i++) {
+            connection.claimInterface(mUsbDevice.getInterface(i), true);
+            connection.releaseInterface(mUsbDevice.getInterface(i));
+        }
+        mMtpDevice = new MtpDevice(mUsbDevice);
+        assertTrue(mMtpDevice.open(connection));
+        assertTrue(mMtpDevice.getStorageIds().length > 0);
+    }
+
+    private void stepTestReadEvent() {
+        assertNotNull(mMtpDevice.getDeviceInfo().getEventsSupported());
+        assertTrue(mMtpDevice.getDeviceInfo().isEventSupported(MtpEvent.EVENT_OBJECT_ADDED));
+
+        mMtpDevice.getObjectHandles(0xFFFFFFFF, 0x0, 0x0);
+        while (true) {
+            MtpEvent event;
+            try {
+                event = mMtpDevice.readEvent(null);
+            } catch (IOException e) {
+                fail();
+                return;
+            }
+            if (event.getEventCode() == MtpEvent.EVENT_OBJECT_ADDED) {
+                break;
+            }
+            SystemClock.sleep(RETRY_DELAY_MS);
+        }
+    }
+
+    private void stepTestSendObject() throws IOException {
+        final MtpDeviceInfo deviceInfo = mMtpDevice.getDeviceInfo();
+        assertNotNull(deviceInfo.getOperationsSupported());
+        assertTrue(deviceInfo.isOperationSupported(MtpConstants.OPERATION_SEND_OBJECT_INFO));
+        assertTrue(deviceInfo.isOperationSupported(MtpConstants.OPERATION_SEND_OBJECT));
+
+        // Delete an existing test file that may be created by the test previously.
+        final int storageId = mMtpDevice.getStorageIds()[0];
+        for (final int objectHandle : mMtpDevice.getObjectHandles(
+                storageId, /* all format */ 0, /* Just under the root */ -1)) {
+            final MtpObjectInfo info = mMtpDevice.getObjectInfo(objectHandle);
+            if (TEST_FILE_NAME.equals(info.getName())) {
+                assertTrue(mMtpDevice.deleteObject(objectHandle));
+            }
+        }
+
+        final MtpObjectInfo info = new MtpObjectInfo.Builder()
+                .setStorageId(storageId)
+                .setName(TEST_FILE_NAME)
+                .setCompressedSize(TEST_FILE_CONTENTS.length)
+                .setFormat(MtpConstants.FORMAT_TEXT)
+                .setParent(-1)
+                .build();
+        final MtpObjectInfo newInfo = mMtpDevice.sendObjectInfo(info);
+        assertNotNull(newInfo);
+        assertTrue(newInfo.getObjectHandle() != -1);
+
+        final ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
+        try {
+            try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(pipes[1])) {
+                stream.write(TEST_FILE_CONTENTS);
+            }
+            assertTrue(mMtpDevice.sendObject(
+                    newInfo.getObjectHandle(),
+                    newInfo.getCompressedSizeLong(),
+                    pipes[0]));
+        } finally {
+            pipes[0].close();
+        }
+    }
+
+    private void stepTestNotification() throws InterruptedException {
+        assertEquals(R.id.pass_item_button, waitForButtonClick());
+    }
+
+    private int waitForButtonClick() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final MutableInt result = new MutableInt(-1);
+        mItems.get(mStep).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                result.value = v.getId();
+                latch.countDown();
+            }
+        });
+        latch.await();
+        return result.value;
+    }
+
+    private static boolean isMtpDevice(UsbDevice device) {
+        for (int i = 0; i < device.getInterfaceCount(); i++) {
+            final UsbInterface usbInterface = device.getInterface(i);
+            if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
+                    usbInterface.getInterfaceSubclass() == SUBCLASS_STILL_IMAGE_CAPTURE &&
+                    usbInterface.getInterfaceProtocol() == PROTOCOL_PICTURE_TRANSFER)) {
+                return true;
+            }
+            if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
+                    usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
+                    usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
+                    "MTP".equals(usbInterface.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static class TestItem {
+        private final View view;
+        private final int[] buttons;
+
+        TestItem(LayoutInflater inflater,
+                 int messageText,
+                 int[] buttons) {
+            this.view = inflater.inflate(R.layout.mtp_host_item, null, false);
+
+            final TextView textView = (TextView) view.findViewById(R.id.instructions);
+            textView.setText(messageText);
+
+            this.buttons = buttons != null ? buttons : new int[0];
+            for (final int id : this.buttons) {
+                final Button button = (Button) view.findViewById(id);
+                button.setVisibility(View.VISIBLE);
+                button.setEnabled(false);
+            }
+        }
+
+        void setOnClickListener(OnClickListener listener) {
+            for (final int id : buttons) {
+                final Button button = (Button) view.findViewById(id);
+                button.setOnClickListener(listener);
+            }
+        }
+
+        void setEnabled(boolean value) {
+            for (final int id : buttons) {
+                final Button button = (Button) view.findViewById(id);
+                button.setEnabled(value);
+            }
+        }
+
+        Button getButton(int id) {
+            return (Button) view.findViewById(id);
+        }
+
+        void setState(int state) {
+            final ImageView imageView = (ImageView) view.findViewById(R.id.status);
+            switch (state) {
+                case ITEM_STATE_PASS:
+                    imageView.setImageResource(R.drawable.fs_good);
+                    break;
+                case ITEM_STATE_FAIL:
+                    imageView.setImageResource(R.drawable.fs_error);
+                    break;
+                case ITEM_STATE_INDETERMINATE:
+                    imageView.setImageResource(R.drawable.fs_indeterminate);
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/Android.mk b/apps/CtsVerifierUSBCompanion/Android.mk
new file mode 100644
index 0000000..947a4ca
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/Android.mk
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations junit4-target
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsVerifierUSBCompanion
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/apps/CtsVerifierUSBCompanion/AndroidManifest.xml b/apps/CtsVerifierUSBCompanion/AndroidManifest.xml
new file mode 100644
index 0000000..594f4ee
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.verifierusbcompanion">
+
+    <uses-sdk android:minSdkVersion="12" android:targetSdkVersion="25" />
+
+    <uses-feature android:name="android.hardware.usb.accessory" />
+    <uses-feature android:name="android.hardware.usb.host" />
+
+    <application android:label="@string/app_name"
+            android:icon="@drawable/icon">
+
+        <activity android:name=".Main"
+                android:screenOrientation="portrait"
+                android:configChanges="orientation|keyboardHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".AccessoryAttachmentHandler">
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+            </intent-filter>
+
+            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                    android:resource="@xml/accessory_filter" />
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/CtsVerifierUSBCompanion/res/drawable-hdpi/icon.png b/apps/CtsVerifierUSBCompanion/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..da28c1f
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/apps/CtsVerifierUSBCompanion/res/layout/main.xml b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
new file mode 100644
index 0000000..6eb2cec
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
@@ -0,0 +1,64 @@
+<?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">
+
+    <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="8dp"
+            android:id="@+id/status">
+
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/status_label"
+                android:layout_marginEnd="4sp"
+                android:textStyle="bold" />
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/status_message" />
+
+    </LinearLayout>
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status"
+            android:id="@+id/deviceTest"
+            android:text="@string/device_test_button" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/deviceTest"
+        android:id="@+id/accessoryTest"
+        android:text="@string/accessory_test_button" />
+
+    <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/status"
+            android:id="@+id/abort"
+            android:text="@string/abort_button"
+            android:visibility="gone" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifierUSBCompanion/res/values/strings.xml b/apps/CtsVerifierUSBCompanion/res/values/strings.xml
new file mode 100644
index 0000000..56bc71f
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/res/values/strings.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.
+  -->
+
+<resources>
+    <string name="status_label">Status:</string>
+    <string name="device_test_button">Start device test companion</string>
+    <string name="accessory_test_button">Start accessory test companion</string>
+    <string name="abort_button">Abort</string>
+    <string name="app_name">Cts Verifier USB Companion</string>
+    <string name="status_no_test">No test run</string>
+    <string name="status_finished">Test finished</string>
+    <string name="status_abort">Aborted</string>
+</resources>
diff --git a/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml b/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml
new file mode 100644
index 0000000..b511879
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/res/xml/accessory_filter.xml
@@ -0,0 +1,19 @@
+<?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>
+    <usb-accessory />
+</resources>
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryAttachmentHandler.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryAttachmentHandler.java
new file mode 100644
index 0000000..ec60ab9
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryAttachmentHandler.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.verifierusbcompanion;
+
+import android.app.Activity;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Utility to receive callbacks when an USB accessory is attached.
+ */
+public class AccessoryAttachmentHandler extends Activity {
+    private static final ArrayList<AccessoryAttachmentObserver> sObservers = new ArrayList<>();
+
+    /**
+     * Register an observer to be called when an USB accessory connects.
+     *
+     * @param observer The observer that should be called when an USB accessory connects.
+     */
+    static void addObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.add(observer);
+        }
+    }
+
+    /**
+     * Remove an observer that was added in {@link #addObserver}.
+     *
+     * @param observer The observer to remove
+     */
+    static void removeObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.remove(observer);
+        }
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        UsbAccessory accessory = getIntent().getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+        synchronized (sObservers) {
+            ArrayList<AccessoryAttachmentObserver> observers =
+                    (ArrayList<AccessoryAttachmentObserver>) sObservers.clone();
+
+            for (AccessoryAttachmentObserver observer : observers) {
+                observer.onAttached(accessory);
+            }
+        }
+
+        finish();
+    }
+
+    /**
+     * Callback when an accessory is attached
+     */
+    interface AccessoryAttachmentObserver {
+        void onAttached(UsbAccessory accessory);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
new file mode 100644
index 0000000..dc5cc3d
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
@@ -0,0 +1,301 @@
+/*
+ * 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.verifierusbcompanion;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.support.annotation.NonNull;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Companion code for com.android.cts.verifier.usb.device.UsbAccessoryTestActivity
+ */
+class AccessoryTestCompanion extends TestCompanion {
+    private static final int MAX_BUFFER_SIZE = 16384;
+
+    private static final String ACTION_USB_PERMISSION =
+            "com.android.cts.verifierusbcompanion.USB_PERMISSION";
+
+    private UsbManager mUsbManager;
+    private BroadcastReceiver mUsbDeviceConnectionReceiver;
+    private UsbDevice mDevice;
+
+    AccessoryTestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
+        super(context, observer);
+    }
+
+    /**
+     * @throws Throwable
+     */
+    @Override
+    protected void runTest() throws Throwable {
+        updateStatus("Waiting for device under test to connect");
+
+        mUsbManager = getContext().getSystemService(UsbManager.class);
+
+        mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (AccessoryTestCompanion.this) {
+                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+                    switch (intent.getAction()) {
+                        case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+                            if (mUsbManager.hasPermission(device)) {
+                                onDeviceAccessPermitted(device);
+                            } else {
+                                mUsbManager.requestPermission(device,
+                                        PendingIntent.getBroadcast(getContext(), 0,
+                                                new Intent(ACTION_USB_PERMISSION), 0));
+                            }
+                            break;
+                        case ACTION_USB_PERMISSION:
+                            boolean granted = intent.getBooleanExtra(
+                                    UsbManager.EXTRA_PERMISSION_GRANTED, false);
+
+                            if (granted) {
+                                onDeviceAccessPermitted(device);
+                            } else {
+                                fail("Permission to connect to " + device.getProductName()
+                                        + " not granted");
+                            }
+                            break;
+                    }
+                }
+            }
+        };
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+        getContext().registerReceiver(mUsbDeviceConnectionReceiver, filter);
+
+        synchronized (this) {
+            while (mDevice == null) {
+                wait();
+            }
+        }
+
+        UsbInterface iface = null;
+        for (int i = 0; i < mDevice.getConfigurationCount(); i++) {
+            if (mDevice.getInterface(i).getName().equals("Android Accessory Interface")) {
+                iface = mDevice.getInterface(i);
+                break;
+            }
+        }
+
+        UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+
+        UsbDeviceConnection connection = mUsbManager.openDevice(mDevice);
+
+        try {
+            String testName;
+            do {
+                testName = nextTest(connection, in, out, true);
+
+                updateStatus("Running test \"" + testName + "\"");
+
+                switch (testName) {
+                    case "echo 32 bytes": {
+                        byte[] buffer = new byte[32];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+                    }
+                    break;
+
+                    case "echo two 16 byte transfers as one": {
+                        byte[] buffer = new byte[48];
+
+                        // We receive the individual transfers even if we wait for more data
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(16, numTransferred);
+                        numTransferred = connection.bulkTransfer(in, buffer, 16, 32, 0);
+                        assertEquals(16, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+                    }
+                    break;
+
+                    case "echo 32 bytes as two 16 byte transfers": {
+                        byte[] buffer = new byte[32];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 16, 0);
+                        assertEquals(16, numTransferred);
+                        numTransferred = connection.bulkTransfer(out, buffer, 16, 16, 0);
+                        assertEquals(16, numTransferred);
+                    }
+                    break;
+
+                    case "echo max bytes": {
+                        byte[] buffer = new byte[MAX_BUFFER_SIZE];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+                    }
+                    break;
+
+                    case "echo max*2 bytes": {
+                        byte[] buffer = new byte[MAX_BUFFER_SIZE * 2];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        // Oversized transfers get split into two
+                        numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE,
+                                MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+                    }
+                    break;
+
+                    default:
+                        break;
+                }
+            } while (!testName.equals("done"));
+        } finally {
+            connection.close();
+        }
+    }
+
+    /**
+     * If access to a device was permitted either make the device an accessory if it already is,
+     * start the test.
+     *
+     * @param device The device access was permitted to
+     */
+    private void onDeviceAccessPermitted(@NonNull UsbDevice device) {
+        if (!AoapInterface.isDeviceInAoapMode(device)) {
+            UsbDeviceConnection connection = mUsbManager.openDevice(device);
+            try {
+                makeThisDeviceAnAccessory(connection);
+            } finally {
+                connection.close();
+            }
+        } else {
+            getContext().unregisterReceiver(mUsbDeviceConnectionReceiver);
+            mUsbDeviceConnectionReceiver = null;
+
+            synchronized (AccessoryTestCompanion.this) {
+                mDevice = device;
+
+                AccessoryTestCompanion.this.notifyAll();
+            }
+        }
+    }
+
+    @NonNull private String nextTest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, boolean isSuccess) {
+        byte[] sizeBuffer = new byte[1];
+
+        updateStatus("Waiting for next test");
+
+        int numTransferred = connection.bulkTransfer(in, sizeBuffer, 1, 0);
+        assertEquals(1, numTransferred);
+
+        int nameSize = sizeBuffer[0];
+
+        byte[] nameBuffer = new byte[nameSize];
+        numTransferred = connection.bulkTransfer(in, nameBuffer, nameSize, 0);
+        assertEquals(nameSize, numTransferred);
+
+        numTransferred = connection.bulkTransfer(out, new byte[]{(byte) (isSuccess ? 1 : 0)}, 1, 0);
+        assertEquals(1, numTransferred);
+
+        numTransferred = connection.bulkTransfer(in, new byte[1], 1, 0);
+        assertEquals(1, numTransferred);
+
+        String name = Charset.forName("UTF-8").decode(ByteBuffer.wrap(nameBuffer)).toString();
+
+        updateStatus("Next test is " + name);
+
+        return name;
+    }
+
+    /**
+     * Search an {@link UsbInterface} for an {@link UsbEndpoint endpoint} of a certain direction.
+     *
+     * @param iface     The interface to search
+     * @param direction The direction the endpoint is for.
+     *
+     * @return The first endpoint found or {@link null}.
+     */
+    @NonNull private UsbEndpoint getEndpoint(@NonNull UsbInterface iface, int direction) {
+        for (int i = 0; i < iface.getEndpointCount(); i++) {
+            UsbEndpoint ep = iface.getEndpoint(i);
+            if (ep.getDirection() == direction) {
+                return ep;
+            }
+        }
+
+        throw new IllegalStateException("Could not find " + direction + " endpoint in "
+                + iface.getName());
+    }
+
+    /**
+     * Converts the device under test into an Android accessory. Accessories are USB hosts that are
+     * detected on the device side via {@link UsbManager#getAccessoryList()}.
+     *
+     * @param connection The connection to the USB device
+     */
+    private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
+                "Android");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
+                "Android device");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
+                "Android device running CTS verifier");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
+                "https://source.android.com/compatibility/cts/verifier.html");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
+        AoapInterface.sendAoapStart(connection);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
new file mode 100644
index 0000000..6f8d1a1
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
@@ -0,0 +1,130 @@
+/*
+ * 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.verifierusbcompanion;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+class AoapInterface {
+    /**
+     * Use Google Vendor ID when in accessory mode
+     */
+    private static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+    /**
+     * Product ID to use when in accessory mode
+     */
+    private static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+    /**
+     * Product ID to use when in accessory mode and adb is enabled
+     */
+    private static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+    /**
+     * Indexes for strings sent by the host via ACCESSORY_SEND_STRING
+     */
+    public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+    public static final int ACCESSORY_STRING_MODEL = 1;
+    public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+    public static final int ACCESSORY_STRING_VERSION = 3;
+    public static final int ACCESSORY_STRING_URI = 4;
+    public static final int ACCESSORY_STRING_SERIAL = 5;
+
+    /**
+     * Control request for retrieving device's protocol version
+     *
+     * requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     * request:        ACCESSORY_GET_PROTOCOL
+     * value:          0
+     * index:          0
+     * data            version number (16 bits little endian)
+     * 1 for original accessory support
+     * 2 adds HID and device to host audio support
+     */
+    private static final int ACCESSORY_GET_PROTOCOL = 51;
+
+    /**
+     * Control request for host to send a string to the device
+     *
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_SEND_STRING
+     * value:          0
+     * index:          string ID
+     * data            zero terminated UTF8 string
+     *
+     * The device can later retrieve these strings via the
+     * ACCESSORY_GET_STRING_* ioctls
+     */
+    private static final int ACCESSORY_SEND_STRING = 52;
+
+    /**
+     * Control request for starting device in accessory mode.
+     * The host sends this after setting all its strings to the device.
+     *
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_START
+     * value:          0
+     * index:          0
+     * data            none
+     */
+    private static final int ACCESSORY_START = 53;
+
+    private static final String TAG = AoapInterface.class.getSimpleName();
+
+    public static int getProtocol(UsbDeviceConnection conn) {
+        byte[] buffer = new byte[2];
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+        if (len != 2) {
+            return -1;
+        }
+        return (buffer[1] << 8) | buffer[0];
+    }
+
+    public static void sendString(UsbDeviceConnection conn, int index, String string) {
+        byte[] buffer = (string + "\0").getBytes();
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_SEND_STRING, 0, index,
+                buffer, buffer.length, 10000);
+        if (len != buffer.length) {
+            throw new RuntimeException("Failed to send string " + index + ": \"" + string + "\"");
+        } else {
+            Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
+        }
+    }
+
+    public static void sendAoapStart(UsbDeviceConnection conn) {
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_START, 0, 0, null, 0, 10000);
+        if (len < 0) {
+            throw new RuntimeException("control transfer for accessory start failed:" + len);
+        }
+    }
+
+    public static boolean isDeviceInAoapMode(UsbDevice device) {
+        final int vid = device.getVendorId();
+        final int pid = device.getProductId();
+        return vid == USB_ACCESSORY_VENDOR_ID
+                && (pid == USB_ACCESSORY_PRODUCT_ID
+                || pid == USB_ACCESSORY_ADB_PRODUCT_ID);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java
new file mode 100644
index 0000000..15ea2f4
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java
@@ -0,0 +1,223 @@
+/*
+ * 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.verifierusbcompanion;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Companion code for com.android.cts.verifier.usb.device.UsbDeviceTestActivity
+ */
+class DeviceTestCompanion extends TestCompanion {
+    private static final int MAX_BUFFER_SIZE = 16384;
+
+    DeviceTestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
+        super(context, observer);
+    }
+
+    /**
+     * Switches to next test:
+     * <ol>
+     *     <li>Send result of last test to device under test</li>
+     *     <li>Receive name of next test</li>
+     * </ol>
+     *
+     * @param is                The stream to read from
+     * @param os                The stream to write to
+     * @param lastTestSucceeded If the last test succeeded
+     *
+     * @return Name of next test or empty string if there is no next test
+     *
+     * @throws IOException if the communication with the device under test is disturbed
+     */
+    private String nextTest(@NonNull InputStream is, @NonNull OutputStream os,
+            boolean lastTestSucceeded) throws IOException {
+        // Read next test name
+        byte[] sizeBuffer = new byte[1];
+        int numRead = is.read(sizeBuffer);
+        assertEquals(1, numRead);
+
+        byte[] nextTestNameBytes = new byte[sizeBuffer[0]];
+        numRead = is.read(nextTestNameBytes);
+        assertEquals(sizeBuffer[0], numRead);
+
+        // Write test result
+        os.write(lastTestSucceeded ? (byte) 1 : (byte) 0);
+
+        // Wait for ready signal
+        numRead = is.read(sizeBuffer);
+        assertEquals(42, sizeBuffer[0]);
+        assertEquals(1, numRead);
+
+        return Charset.forName("UTF-8").decode(ByteBuffer.wrap(nextTestNameBytes)).toString();
+    }
+
+    /**
+     * Read some bytes and send them back to the sender.
+     *
+     * @param is   Stream to read from
+     * @param os   Stream to write to
+     * @param size The number of bytes to read
+     *
+     * @return {@code true} iff the bytes could be read and written
+     *
+     * @throws IOException
+     */
+    private boolean echoBytes(@NonNull InputStream is, @NonNull OutputStream os, int size)
+            throws IOException {
+        byte[] buffer = new byte[size];
+
+        int numRead = is.read(buffer);
+        if (numRead != size) {
+            return false;
+        }
+
+        os.write(buffer);
+        return true;
+    }
+
+    /**
+     * Read packages of (size:data) send the data back to the sender. Do this until the package size
+     * is declared as 0.
+     *
+     * @param is Stream to read from
+     * @param os Stream to write to
+     *
+     * @return {@code true} iff the bytes could be read and written
+     *
+     * @throws IOException
+     */
+    private boolean echoUntilStopSignal(@NonNull InputStream is, @NonNull OutputStream os) {
+        try {
+            while (!shouldAbort()) {
+                byte[] dataBytes = new byte[9];
+                int numRead = is.read(dataBytes);
+                assertEquals(9, numRead);
+
+                if (shouldAbort() || dataBytes[0] == 0) {
+                    break;
+                }
+
+                os.write(dataBytes);
+            }
+
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        UsbAccessory accessory;
+
+        final UsbAccessory[] accessoryReceiver = new UsbAccessory[1];
+        AccessoryAttachmentHandler.AccessoryAttachmentObserver accessoryAttachmentObserver =
+                a -> {
+                    synchronized (DeviceTestCompanion.this) {
+                        accessoryReceiver[0] = a;
+                        notifyAll();
+                    }
+                };
+        AccessoryAttachmentHandler.addObserver(accessoryAttachmentObserver);
+
+        updateStatus("Waiting for device under test to connect");
+        synchronized (this) {
+            do {
+                wait();
+            } while (accessoryReceiver[0] == null);
+
+            accessory = accessoryReceiver[0];
+        }
+
+        updateStatus("Connecting to " + accessory.getDescription());
+        UsbManager usbManager = getContext().getSystemService(UsbManager.class);
+        ParcelFileDescriptor fd = usbManager.openAccessory(accessory);
+        assertNotNull(fd);
+
+        try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+            try (OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+                String testName;
+                boolean isSuccess = true;
+
+                do {
+                    testName = nextTest(is, os, isSuccess);
+
+                    updateStatus("Running test \"" + testName + "\"");
+
+                    switch (testName) {
+                        case "Echo 1 byte":
+                            isSuccess = echoBytes(is, os, 1);
+                            break;
+                        case "Echo 42 bytes":
+                            isSuccess = echoBytes(is, os, 42);
+                            break;
+                        case "Echo max bytes":
+                            isSuccess = echoBytes(is, os, MAX_BUFFER_SIZE);
+                            break;
+                        case "Echo oversized buffer":
+                            // The bytes beyond MAX_BUFFER_SIZE got ignored when sending
+                            isSuccess = echoBytes(is, os, MAX_BUFFER_SIZE);
+                            break;
+                        case "Receive oversized buffer": {
+                            byte[] buffer = new byte[MAX_BUFFER_SIZE * 3 / 2];
+                            buffer[0] = 1;
+                            buffer[MAX_BUFFER_SIZE - 1] = 2;
+                            buffer[MAX_BUFFER_SIZE] = 3;
+                            buffer[MAX_BUFFER_SIZE * 3 / 2 - 1] = 4;
+
+                            os.write(buffer);
+
+                            isSuccess = true;
+                        }
+                        break;
+                        case "Receive byte after some time":
+                            Thread.sleep(200);
+                            os.write(new byte[1]);
+                            isSuccess = true;
+                            break;
+                        case "Receive byte immediately":
+                            os.write(new byte[1]);
+                            isSuccess = true;
+                            break;
+                        case "Echo until stop signal":
+                            isSuccess = echoUntilStopSignal(is, os);
+                            break;
+                        case "done":
+                        default:
+                            isSuccess = true;
+                            break;
+                    }
+                } while (!"done".equals(testName));
+            }
+        }
+
+        AccessoryAttachmentHandler.removeObserver(accessoryAttachmentObserver);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
new file mode 100644
index 0000000..a87f9ce
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
@@ -0,0 +1,123 @@
+/*
+ * 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.verifierusbcompanion;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * UI of this app
+ */
+public class Main extends Activity implements TestCompanion.TestObserver {
+    private TextView mStatusMessage;
+    private Button mDeviceTestButton;
+    private Button mAccessoryTestButton;
+    private Button mAbortButton;
+    private TestCompanion mCurrentTest;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        setContentView(R.layout.main);
+
+        mStatusMessage = (TextView) findViewById(R.id.status_message);
+        mDeviceTestButton = (Button) findViewById(R.id.deviceTest);
+        mAccessoryTestButton = (Button) findViewById(R.id.accessoryTest);
+        mAbortButton = (Button) findViewById(R.id.abort);
+
+        mStatusMessage.setText(getString(R.string.status_no_test));
+
+        mDeviceTestButton.setOnClickListener(view -> runDeviceTest());
+        mAccessoryTestButton.setOnClickListener(view -> runAccessoryTest());
+        mAbortButton.setOnClickListener(view -> abortCurrentTest());
+    }
+
+    /**
+     * Abort the current test companion.
+     */
+    private void abortCurrentTest() {
+        mCurrentTest.requestAbort();
+    }
+
+    /**
+     * Run the {@link DeviceTestCompanion}
+     */
+    private void runDeviceTest() {
+        runTestCompanion(new DeviceTestCompanion(this, this));
+    }
+
+    /**
+     * Run the {@link AccessoryTestCompanion}
+     */
+    private void runAccessoryTest() {
+        runTestCompanion(new AccessoryTestCompanion(this, this));
+    }
+
+    /**
+     * Run a test.
+     * @param test The test to run
+     */
+    private void runTestCompanion(@NonNull TestCompanion test) {
+        mAbortButton.setVisibility(View.VISIBLE);
+        mDeviceTestButton.setVisibility(View.GONE);
+        mAccessoryTestButton.setVisibility(View.GONE);
+
+        mCurrentTest = test;
+        test.start();
+    }
+
+    /**
+     * Reset the UI after a test
+     */
+    private void resetUI() {
+        mAbortButton.setVisibility(View.GONE);
+        mDeviceTestButton.setVisibility(View.VISIBLE);
+        mAccessoryTestButton.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    public void onStatusUpdate(@NonNull CharSequence status) {
+        mStatusMessage.setText(status);
+    }
+
+    @Override
+    public void onSuccess() {
+        mStatusMessage.setText(getString(R.string.status_finished));
+        resetUI();
+    }
+
+    @Override
+    public void onFail(@NonNull CharSequence error) {
+        mStatusMessage.setText(error);
+        resetUI();
+    }
+
+    @Override
+    public void onAbort() {
+        mStatusMessage.setText(getString(R.string.status_abort));
+        resetUI();
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/TestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/TestCompanion.java
new file mode 100644
index 0000000..e766a18
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/TestCompanion.java
@@ -0,0 +1,166 @@
+/*
+ * 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.verifierusbcompanion;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Framework for all companion tests of this app.
+ */
+abstract class TestCompanion extends Thread {
+    private final @NonNull Context mContext;
+    private final @NonNull TestHandler mHandler;
+    private boolean mShouldAbort;
+
+    /**
+     * Create a new test companion
+     *
+     * @param context Context to be used for the test companion
+     * @param observer Observer observing the test companion
+     */
+    TestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
+        mContext = context;
+        mHandler = new TestHandler(observer);
+    }
+
+    /**
+     * @return the context to be used by the test companion
+     */
+    protected @NonNull Context getContext() {
+        return mContext;
+    }
+
+    void requestAbort() {
+        mShouldAbort = true;
+        interrupt();
+    }
+
+    /**
+     * @return if the test companion should abort
+     */
+    protected boolean shouldAbort() {
+        return mShouldAbort;
+    }
+
+    /**
+     * Indicate that the test companion succeeded.
+     */
+    protected void success() {
+        mHandler.obtainMessage(TestHandler.SUCCESS).sendToTarget();
+    }
+
+    /**
+     * Indicate that the test companion failed.
+     *
+     * @param error Description why the test failed
+     */
+    protected void fail(@NonNull CharSequence error) {
+        mHandler.obtainMessage(TestHandler.FAIL, error).sendToTarget();
+    }
+
+    /**
+     * Indicate that the test companion was aborted.
+     */
+    private void abort() {
+        mHandler.obtainMessage(TestHandler.ABORT).sendToTarget();
+    }
+
+    /**
+     * Update the status of the test companion.
+     *
+     * @param status The new status message
+     */
+    protected void updateStatus(@NonNull CharSequence status) {
+        Log.i(this.getClass().getSimpleName(), "Status: " + status);
+
+        mHandler.obtainMessage(TestHandler.UPDATE_STATUS, status).sendToTarget();
+    }
+
+    @Override
+    public final void run() {
+        try {
+            runTest();
+        } catch (Throwable e) {
+            if (e instanceof InterruptedException && shouldAbort()) {
+                abort();
+            } else {
+                fail(e + "\n" + Arrays.toString(e.getStackTrace()));
+            }
+
+            return;
+        }
+
+        success();
+    }
+
+    /**
+     * The test companion code.
+     *
+     * @throws Throwable  If this returns without an exception, the test companion succeeded.
+     */
+    protected abstract void runTest() throws Throwable;
+
+    /**
+     * Observe the state of this test companion
+     */
+    public interface TestObserver {
+        void onStatusUpdate(@NonNull CharSequence status);
+        void onSuccess();
+        void onFail(@NonNull CharSequence error);
+        void onAbort();
+    }
+
+    /**
+     * Serialize callbacks to main thread.
+     */
+    public static class TestHandler extends Handler {
+        static final int SUCCESS = 0;
+        static final int FAIL = 1;
+        static final int ABORT = 2;
+        static final int UPDATE_STATUS = 3;
+
+        private final @NonNull TestObserver mObserver;
+
+        TestHandler(@NonNull TestObserver observer) {
+            mObserver = observer;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SUCCESS:
+                    mObserver.onSuccess();
+                    break;
+                case FAIL:
+                    mObserver.onFail((CharSequence)msg.obj);
+                    break;
+                case ABORT:
+                    mObserver.onAbort();
+                    break;
+                case UPDATE_STATUS:
+                    mObserver.onStatusUpdate((CharSequence)msg.obj);
+                    break;
+            }
+        }
+    }
+}
diff --git a/apps/cts-usb-accessory/Android.mk b/apps/cts-usb-accessory/Android.mk
deleted file mode 100644
index 7699b1a..0000000
--- a/apps/cts-usb-accessory/Android.mk
+++ /dev/null
@@ -1,41 +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.
-#
-
-# Build for Linux (desktop) host
-ifeq ($(HOST_OS),linux)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := cts-usb-accessory.c
-
-LOCAL_MODULE := cts-usb-accessory
-
-LOCAL_C_INCLUDES += \
-	bionic/libc/kernel/uapi \
-	bionic/libc/kernel/android/uapi \
-	bionic/libc/kernel/uapi/asm-x86 \
-
-LOCAL_STATIC_LIBRARIES := libusbhost libcutils
-LOCAL_LDLIBS += -lpthread
-LOCAL_CFLAGS := -g -O0
-LOCAL_CXX_STL := none
-
-include $(BUILD_HOST_EXECUTABLE)
-
-endif
diff --git a/apps/cts-usb-accessory/cts-usb-accessory.c b/apps/cts-usb-accessory/cts-usb-accessory.c
deleted file mode 100644
index c5da3ef..0000000
--- a/apps/cts-usb-accessory/cts-usb-accessory.c
+++ /dev/null
@@ -1,221 +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.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <time.h>
-
-#include <usbhost/usbhost.h>
-#include <linux/usb/f_accessory.h>
-
-static struct usb_device *sDevice = NULL;
-static int sAfterUnplug = 0;
-static char* sDeviceSerial = NULL;
-
-static void* message_thread(void* arg) {
-    int *endpoints = (int *)arg;
-    int ret = 0;
-    int num = 0;
-    char message[50];
-
-    while (sDevice && ret >= 0) {
-        char buffer[16384];
-        ret = usb_device_bulk_transfer(sDevice, endpoints[0], buffer, sizeof(buffer), 1000);
-        if (ret < 0 && errno == ETIMEDOUT) {
-            ret = 0;
-        }
-        if (ret > 0) {
-            printf("[RECV] ");
-            fwrite(buffer, 1, ret, stdout);
-            printf("\n");
-
-            // Respond by sending a message back
-            sprintf(message, "Message from Android accessory #%d", num++);
-            printf("[SENT] %s\n", message);
-            fflush(stdout);
-            usb_device_bulk_transfer(sDevice, endpoints[1], message, strlen(message), 1000);
-        }
-    }
-
-    return NULL;
-}
-
-static void milli_sleep(int millis) {
-    struct timespec tm;
-
-    tm.tv_sec = 0;
-    tm.tv_nsec = millis * 1000000;
-    nanosleep(&tm, NULL);
-}
-
-static int send_string(struct usb_device *device, int index, const char* string) {
-    int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
-            ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 1000);
-
-    // some devices can't handle back-to-back requests, so delay a bit
-    milli_sleep(10);
-    return ret;
-}
-
-static int usb_device_added(const char *devname, void* client_data) {
-    struct usb_descriptor_header* desc;
-    struct usb_descriptor_iter iter;
-    uint16_t vendorId, productId;
-    int ret;
-    pthread_t th;
-
-    struct usb_device *device = usb_device_open(devname);
-    if (!device) {
-        fprintf(stderr, "usb_device_open failed\n");
-        return 0;
-    }
-
-    char* serial = usb_device_get_serial(device);
-    if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) {
-        free(serial);
-        return 0;
-    }
-    free(serial);
-
-    vendorId = usb_device_get_vendor_id(device);
-    productId = usb_device_get_product_id(device);
-
-    if (!sDevice && (vendorId == 0x18D1 && (productId == 0x2D00 || productId == 0x2D01))) {
-        struct usb_descriptor_header* desc;
-        struct usb_descriptor_iter iter;
-        struct usb_interface_descriptor *intf = NULL;
-        struct usb_endpoint_descriptor *ep1 = NULL;
-        struct usb_endpoint_descriptor *ep2 = NULL;
-
-        printf("Found Android device in accessory mode (%x:%x)...\n",
-               vendorId, productId);
-        sDevice = device;
-        sDeviceSerial = usb_device_get_serial(sDevice);
-
-        usb_descriptor_iter_init(device, &iter);
-        while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
-            if (desc->bDescriptorType == USB_DT_INTERFACE) {
-                intf = (struct usb_interface_descriptor *)desc;
-            } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
-                if (ep1)
-                    ep2 = (struct usb_endpoint_descriptor *)desc;
-                else
-                    ep1 = (struct usb_endpoint_descriptor *)desc;
-            }
-        }
-
-        if (!intf) {
-            fprintf(stderr, "Interface not found\n");
-            exit(1);
-        }
-        if (!ep1 || !ep2) {
-            fprintf(stderr, "Endpoints not found\n");
-            exit(1);
-        }
-
-        if (usb_device_claim_interface(device, intf->bInterfaceNumber)) {
-            fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno);
-            exit(1);
-        }
-
-        int endpoints[2];
-        if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-            endpoints[0] = ep1->bEndpointAddress;
-            endpoints[1] = ep2->bEndpointAddress;
-        } else {
-            endpoints[0] = ep2->bEndpointAddress;
-            endpoints[1] = ep1->bEndpointAddress;
-        }
-        pthread_create(&th, NULL, message_thread, (void *)endpoints);
-    } else {
-        printf("Found possible Android device (%x:%x) "
-                "- attempting to switch to accessory mode...\n", vendorId, productId);
-
-        uint16_t protocol = 0;
-        ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
-                ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000);
-        if (ret == 2) {
-            printf("Device supports protocol version %d\n", protocol);
-        } else {
-            fprintf(stderr, "Failed to read protocol version\n");
-        }
-
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_VERSION, "1.0");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_URI,
-                        "http://source.android.com/compatibility/cts-intro.html");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
-
-        ret = (ret < 0) ? ret :
-                usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
-                        ACCESSORY_START, 0, 0, 0, 0, 1000);
-        if (ret < 0) {
-            fprintf(stderr, "Failed to start accessory mode\n");
-        }
-        return 0;
-    }
-
-    if (device != sDevice)
-        usb_device_close(device);
-
-    return 0;
-}
-
-static int usb_device_removed(const char *devname, void* client_data) {
-    if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
-        usb_device_close(sDevice);
-        sDevice = NULL;
-        if (sAfterUnplug) {
-            // exit when we are disconnected the second time
-            free(sDeviceSerial);
-            return 1;
-        } else {
-            sAfterUnplug = 1;
-        }
-    }
-    return 0;
-}
-
-
-int main(int argc, char* argv[]) {
-    printf("CTS USB Accessory Tester\n");
-
-    struct usb_host_context* context = usb_host_init();
-    if (!context) {
-        fprintf(stderr, "usb_host_init failed");
-        return 1;
-    }
-
-    // this will never return so it is safe to pass thiz directly
-    usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL);
-    return 0;
-}
diff --git a/build/compatibility_test_suite.mk b/build/compatibility_test_suite.mk
index f109185..7cdd220 100644
--- a/build/compatibility_test_suite.mk
+++ b/build/compatibility_test_suite.mk
@@ -46,7 +46,7 @@
 LOCAL_GENERATED_SOURCES := $(suite_info_java)
 
 # Add the base libraries
-LOCAL_JAVA_LIBRARIES += tradefed-prebuilt hosttestlib compatibility-host-util
+LOCAL_JAVA_LIBRARIES += tradefed hosttestlib compatibility-host-util
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/TelephonyHelper.java b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/TelephonyHelper.java
new file mode 100644
index 0000000..d828e72
--- /dev/null
+++ b/common/device-side/preconditions/src/com/android/compatibility/common/preconditions/TelephonyHelper.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 com.android.compatibility.common.preconditions;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+/**
+ * TelephonyHelper is used to check whether the device has a SIM card with phone number.
+ */
+public class TelephonyHelper {
+    /*
+     * This helper returns false if the device doesn't have a SIM card with phone number.
+     */
+    public static boolean hasPhoneNumber(Context context) {
+        TelephonyManager telephony =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+
+        return TextUtils.isEmpty(telephony.getLine1Number());
+    }
+}
\ No newline at end of file
diff --git a/common/device-side/util/Android.mk b/common/device-side/util/Android.mk
index 350c2db..50a78be 100644
--- a/common/device-side/util/Android.mk
+++ b/common/device-side/util/Android.mk
@@ -18,7 +18,10 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-common-util-devicesidelib \
+    android-support-test \
+    mockito-target-minus-junit4
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/libs/deviceutil/jni/Android.mk b/common/device-side/util/jni/Android.mk
similarity index 100%
rename from libs/deviceutil/jni/Android.mk
rename to common/device-side/util/jni/Android.mk
diff --git a/libs/deviceutil/jni/CtsJniOnLoad.cpp b/common/device-side/util/jni/CtsJniOnLoad.cpp
similarity index 100%
rename from libs/deviceutil/jni/CtsJniOnLoad.cpp
rename to common/device-side/util/jni/CtsJniOnLoad.cpp
diff --git a/common/device-side/util/jni/android_cts_FileUtils.cpp b/common/device-side/util/jni/android_cts_FileUtils.cpp
new file mode 100644
index 0000000..c1b52af
--- /dev/null
+++ b/common/device-side/util/jni/android_cts_FileUtils.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#include <grp.h>
+#include <jni.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+static jclass gFileStatusClass;
+static jfieldID gFileStatusDevFieldID;
+static jfieldID gFileStatusInoFieldID;
+static jfieldID gFileStatusModeFieldID;
+static jfieldID gFileStatusNlinkFieldID;
+static jfieldID gFileStatusUidFieldID;
+static jfieldID gFileStatusGidFieldID;
+static jfieldID gFileStatusSizeFieldID;
+static jfieldID gFileStatusBlksizeFieldID;
+static jfieldID gFileStatusBlocksFieldID;
+static jfieldID gFileStatusAtimeFieldID;
+static jfieldID gFileStatusMtimeFieldID;
+static jfieldID gFileStatusCtimeFieldID;
+
+/*
+ * Native methods used by
+ * cts/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java
+ *
+ * Copied from hidden API: frameworks/base/core/jni/android_FileUtils.cpp
+ */
+
+jboolean android_cts_FileUtils_getFileStatus(JNIEnv* env, jobject thiz,
+        jstring path, jobject fileStatus, jboolean statLinks)
+{
+    const char* pathStr = env->GetStringUTFChars(path, NULL);
+    jboolean ret = false;
+    struct stat s;
+
+    int res = statLinks == true ? lstat(pathStr, &s) : stat(pathStr, &s);
+
+    if (res == 0) {
+        ret = true;
+        if (fileStatus != NULL) {
+            env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
+            env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
+            env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
+            env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
+            env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
+            env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
+            env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
+            env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
+            env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
+            env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
+            env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
+            env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
+        }
+    }
+
+    env->ReleaseStringUTFChars(path, pathStr);
+
+    return ret;
+}
+
+jstring android_cts_FileUtils_getUserName(JNIEnv* env, jobject thiz,
+        jint uid)
+{
+    struct passwd *pwd = getpwuid(uid);
+    return env->NewStringUTF(pwd->pw_name);
+}
+
+jstring android_cts_FileUtils_getGroupName(JNIEnv* env, jobject thiz,
+        jint gid)
+{
+    struct group *grp = getgrgid(gid);
+    return env->NewStringUTF(grp->gr_name);
+}
+
+jint android_cts_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
+        jstring file, jint mode)
+{
+    const char *fileStr = env->GetStringUTFChars(file, NULL);
+    if (fileStr == NULL) {
+        return -1;
+    }
+
+    if (strlen(fileStr) <= 0) {
+        env->ReleaseStringUTFChars(file, fileStr);
+        return ENOENT;
+    }
+
+    jint returnValue = chmod(fileStr, mode) == 0 ? 0 : errno;
+    env->ReleaseStringUTFChars(file, fileStr);
+    return returnValue;
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "getFileStatus",
+            "(Ljava/lang/String;Lcom/android/compatibility/common/util/FileUtils$FileStatus;Z)Z",
+            (void *) android_cts_FileUtils_getFileStatus  },
+    {  "getUserName", "(I)Ljava/lang/String;",
+            (void *) android_cts_FileUtils_getUserName  },
+    {  "getGroupName", "(I)Ljava/lang/String;",
+            (void *) android_cts_FileUtils_getGroupName  },
+    {  "setPermissions", "(Ljava/lang/String;I)I",
+            (void *) android_cts_FileUtils_setPermissions },
+};
+
+int register_android_cts_FileUtils(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("com/android/compatibility/common/util/FileUtils");
+    assert(clazz != null);
+
+    gFileStatusClass = env->FindClass(
+            "com/android/compatibility/common/util/FileUtils$FileStatus");
+    assert(gFileStatusClass != null);
+    gFileStatusDevFieldID = env->GetFieldID(gFileStatusClass, "dev", "I");
+    gFileStatusInoFieldID = env->GetFieldID(gFileStatusClass, "ino", "I");
+    gFileStatusModeFieldID = env->GetFieldID(gFileStatusClass, "mode", "I");
+    gFileStatusNlinkFieldID = env->GetFieldID(gFileStatusClass, "nlink", "I");
+    gFileStatusUidFieldID = env->GetFieldID(gFileStatusClass, "uid", "I");
+    gFileStatusGidFieldID = env->GetFieldID(gFileStatusClass, "gid", "I");
+    gFileStatusSizeFieldID = env->GetFieldID(gFileStatusClass, "size", "J");
+    gFileStatusBlksizeFieldID = env->GetFieldID(gFileStatusClass, "blksize", "I");
+    gFileStatusBlocksFieldID = env->GetFieldID(gFileStatusClass, "blocks", "J");
+    gFileStatusAtimeFieldID = env->GetFieldID(gFileStatusClass, "atime", "J");
+    gFileStatusMtimeFieldID = env->GetFieldID(gFileStatusClass, "mtime", "J");
+    gFileStatusCtimeFieldID = env->GetFieldID(gFileStatusClass, "ctime", "J");
+
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java
new file mode 100644
index 0000000..5799e70
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BitmapUtils.java
@@ -0,0 +1,92 @@
+/*
+ * 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.compatibility.common.util;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Color;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import java.util.Random;
+
+public class BitmapUtils {
+    private BitmapUtils() {}
+
+    // Compares two bitmaps by pixels.
+    public static boolean compareBitmaps(Bitmap bmp1, Bitmap bmp2) {
+        if (bmp1 == bmp2) {
+            return true;
+        }
+
+        if (bmp1 == null || bmp2 == null) {
+            return false;
+        }
+
+        if ((bmp1.getWidth() != bmp2.getWidth()) || (bmp1.getHeight() != bmp2.getHeight())) {
+            return false;
+        }
+
+        for (int i = 0; i < bmp1.getWidth(); i++) {
+            for (int j = 0; j < bmp1.getHeight(); j++) {
+                if (bmp1.getPixel(i, j) != bmp2.getPixel(i, j)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static Bitmap generateRandomBitmap(int width, int height) {
+        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        final Random generator = new Random();
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                bmp.setPixel(x, y, generator.nextInt(Integer.MAX_VALUE));
+            }
+        }
+        return bmp;
+    }
+
+    public static Bitmap generateWhiteBitmap(int width, int height) {
+        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                bmp.setPixel(x, y, Color.WHITE);
+            }
+        }
+        return bmp;
+    }
+
+    public static Bitmap getWallpaperBitmap(Context context) throws Exception {
+        WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
+        Class<?> noparams[] = {};
+        Class<?> wmClass = wallpaperManager.getClass();
+        Method methodGetBitmap = wmClass.getDeclaredMethod("getBitmap", noparams);
+        return (Bitmap) methodGetBitmap.invoke(wallpaperManager, null);
+    }
+
+    public static ByteArrayInputStream bitmapToInputStream(Bitmap bmp) {
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
+        byte[] bitmapData = bos.toByteArray();
+        return new ByteArrayInputStream(bitmapData);
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
new file mode 100644
index 0000000..bf5dc39
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
@@ -0,0 +1,123 @@
+/*
+ * 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.util;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BroadcastTestBase extends ActivityInstrumentationTestCase2<
+                                       BroadcastTestStartActivity> {
+    static final String TAG = "BroadcastTestBase";
+    protected static final int TIMEOUT_MS = 20 * 1000;
+
+    protected Context mContext;
+    protected Bundle mResultExtras;
+    private CountDownLatch mLatch;
+    protected ActivityDoneReceiver mActivityDoneReceiver = null;
+    private BroadcastTestStartActivity mActivity;
+    private BroadcastUtils.TestcaseType mTestCaseType;
+    protected boolean mHasFeature;
+
+    public BroadcastTestBase() {
+        super(BroadcastTestStartActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHasFeature = false;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mHasFeature && mActivityDoneReceiver != null) {
+            try {
+                mContext.unregisterReceiver(mActivityDoneReceiver);
+            } catch (IllegalArgumentException e) {
+                // This exception is thrown if mActivityDoneReceiver in
+                // the above call to unregisterReceiver is never registered.
+                // If so, no harm done by ignoring this exception.
+            }
+            mActivityDoneReceiver = null;
+        }
+        super.tearDown();
+    }
+
+    protected boolean isIntentSupported(String intentStr) {
+        Intent intent = new Intent(intentStr);
+        final PackageManager manager = mContext.getPackageManager();
+        assertNotNull(manager);
+        if (manager.resolveActivity(intent, 0) == null) {
+            Log.i(TAG, "No Activity found for the intent: " + intentStr);
+            return false;
+        }
+        return true;
+    }
+
+    protected void startTestActivity(String intentSuffix) {
+        Intent intent = new Intent();
+        intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
+        intent.setComponent(new ComponentName(getInstrumentation().getContext(),
+                BroadcastTestStartActivity.class));
+        setActivityIntent(intent);
+        mActivity = getActivity();
+    }
+
+    protected void registerBroadcastReceiver(BroadcastUtils.TestcaseType testCaseType) throws Exception {
+        mTestCaseType = testCaseType;
+        mLatch = new CountDownLatch(1);
+        mActivityDoneReceiver = new ActivityDoneReceiver();
+        mContext.registerReceiver(mActivityDoneReceiver,
+                new IntentFilter(BroadcastUtils.BROADCAST_INTENT + testCaseType.toString()));
+    }
+
+    protected boolean startTestAndWaitForBroadcast(BroadcastUtils.TestcaseType testCaseType,
+                                                   String pkg, String cls) throws Exception {
+        Log.i(TAG, "Begin Testing: " + testCaseType);
+        registerBroadcastReceiver(testCaseType);
+        mActivity.startTest(testCaseType.toString(), pkg, cls);
+        if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Failed to receive broadcast in " + TIMEOUT_MS + "msec");
+            return false;
+        }
+        return true;
+    }
+
+    class ActivityDoneReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(
+                    BroadcastUtils.BROADCAST_INTENT +
+                        BroadcastTestBase.this.mTestCaseType.toString())) {
+                Bundle extras = intent.getExtras();
+                Log.i(TAG, "received_broadcast for " + BroadcastUtils.toBundleString(extras));
+                BroadcastTestBase.this.mResultExtras = extras;
+                mLatch.countDown();
+            }
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java
new file mode 100644
index 0000000..4b3e85d
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestStartActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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.util;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.util.Log;
+
+public class BroadcastTestStartActivity extends Activity {
+    static final String TAG = "BroadcastTestStartActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, " in onCreate");
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Log.i(TAG, " in onResume");
+    }
+
+    void startTest(String testCaseType, String pkg, String cls) {
+        Intent intent = new Intent();
+        Log.i(TAG, "received_testcasetype = " + testCaseType);
+        intent.putExtra(BroadcastUtils.TESTCASE_TYPE, testCaseType);
+        intent.setAction("android.intent.action.VIMAIN_" + testCaseType);
+        intent.setComponent(new ComponentName(pkg, cls));
+        startActivity(intent);
+    }
+
+    @Override
+    protected void onPause() {
+        Log.i(TAG, " in onPause");
+        super.onPause();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        Log.i(TAG, " in onStart");
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+        Log.i(TAG, " in onRestart");
+    }
+
+    @Override
+    protected void onStop() {
+        Log.i(TAG, " in onStop");
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.i(TAG, " in onDestroy");
+        super.onDestroy();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java
new file mode 100644
index 0000000..a4661fc
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastUtils.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util;
+
+import android.os.Bundle;
+
+public class BroadcastUtils {
+    public enum TestcaseType {
+        ZEN_MODE_ON,
+        ZEN_MODE_OFF,
+        AIRPLANE_MODE_ON,
+        AIRPLANE_MODE_OFF,
+        BATTERYSAVER_MODE_ON,
+        BATTERYSAVER_MODE_OFF,
+        THEATER_MODE_ON,
+        THEATER_MODE_OFF
+    }
+    public static final String TESTCASE_TYPE = "Testcase_type";
+    public static final String BROADCAST_INTENT =
+            "android.intent.action.FROM_UTIL_CTS_TEST_";
+    public static final int NUM_MINUTES_FOR_ZENMODE = 10;
+
+    public static final String toBundleString(Bundle bundle) {
+        if (bundle == null) {
+            return "*** Bundle is null ****";
+        }
+        StringBuilder buf = new StringBuilder();
+        if (bundle != null) {
+            buf.append("extras: ");
+            for (String s : bundle.keySet()) {
+                buf.append("(" + s + " = " + bundle.get(s) + "), ");
+            }
+        }
+        return buf.toString();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java b/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java
new file mode 100644
index 0000000..d60155a
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/CTSResult.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package com.android.compatibility.common.util;
+
+public interface CTSResult {
+    public static final int RESULT_OK = 1;
+    public static final int RESULT_FAIL = 2;
+    public void setResult(int resultCode);
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java
new file mode 100644
index 0000000..1ffad1d
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/CtsAndroidTestCase.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+
+package com.android.compatibility.common.util;
+
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ *  This class emulates AndroidTestCase, but internally it is ActivityInstrumentationTestCase2
+ *  to access Instrumentation.
+ *  DummyActivity is not supposed to be accessed.
+ */
+public class CtsAndroidTestCase extends ActivityInstrumentationTestCase2<DummyActivity> {
+    public CtsAndroidTestCase() {
+        super(DummyActivity.class);
+    }
+
+    public Context getContext() {
+        return getInstrumentation().getContext();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsArrayUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsArrayUtils.java
new file mode 100644
index 0000000..6fc3d14
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/CtsArrayUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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.compatibility.common.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Assert;
+
+public class CtsArrayUtils {
+    private CtsArrayUtils() {}
+
+    /**
+     * Since {@link Assert} doesn't have an API to compare two arrays of floats, this method
+     * can be used in relevant CTS tests to do that.
+     *
+     * @param expected Array of expected values.
+     * @param actual Array of actual values.
+     * @param tolerance Tolerance for comparing the arrays' content
+     */
+    public static void verifyArrayEquals(float[] expected, float[] actual, float tolerance) {
+        if (expected == actual) {
+            return;
+        }
+
+        if (expected == null) {
+            fail("Expected array is null while actual is not");
+        }
+        if (actual == null) {
+            fail("Actual array is null while expected is not");
+        }
+
+        int expectedCount = expected.length;
+        int actualCount = actual.length;
+        assertEquals("Mismatch between sizes of arrays", expectedCount, actualCount);
+
+        for (int i = 0; i < expectedCount; i++) {
+            assertEquals("Mismatch at index " + i, expected[i], actual[i], tolerance);
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsKeyEventUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsKeyEventUtil.java
new file mode 100644
index 0000000..97e4310
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/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 com.android.compatibility.common.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/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java
new file mode 100644
index 0000000..54985dc
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/CtsMockitoUtils.java
@@ -0,0 +1,26 @@
+/*
+ * 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.compatibility.common.util;
+
+import org.mockito.verification.VerificationMode;
+
+public class CtsMockitoUtils {
+    private CtsMockitoUtils() {}
+
+    public static VerificationMode within(long timeout) {
+        return new Within(timeout);
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java
new file mode 100644
index 0000000..5b5dc81
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/CtsTouchUtils.java
@@ -0,0 +1,472 @@
+/*
+ * 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.compatibility.common.util;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.util.SparseArray;
+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) {
+        emulateTapOnView(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 emulateTapOnView(Instrumentation instrumentation, View anchorView,
+            int offsetX, int offsetY) {
+        final int touchSlop = ViewConfiguration.get(anchorView.getContext()).getScaledTouchSlop();
+        // Get anchor coordinates on the screen
+        final int[] viewOnScreenXY = new int[2];
+        anchorView.getLocationOnScreen(viewOnScreenXY);
+        int xOnScreen = viewOnScreenXY[0] + offsetX;
+        int yOnScreen = viewOnScreenXY[1] + offsetY;
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        final long downTime = SystemClock.uptimeMillis();
+
+        injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen);
+        injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
+        injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen);
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Emulates a double tap in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "double tap"
+     */
+    public static void emulateDoubleTapOnViewCenter(Instrumentation instrumentation, View view) {
+        emulateDoubleTapOnView(instrumentation, view, view.getWidth() / 2, view.getHeight() / 2);
+    }
+
+    /**
+     * Emulates a double 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 points.
+     *
+     * @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 taps
+     * @param offsetY extra Y offset for the taps
+     */
+    public static void emulateDoubleTapOnView(Instrumentation instrumentation, View anchorView,
+            int offsetX, int offsetY) {
+        final int touchSlop = ViewConfiguration.get(anchorView.getContext()).getScaledTouchSlop();
+        // Get anchor coordinates on the screen
+        final int[] viewOnScreenXY = new int[2];
+        anchorView.getLocationOnScreen(viewOnScreenXY);
+        int xOnScreen = viewOnScreenXY[0] + offsetX;
+        int yOnScreen = viewOnScreenXY[1] + offsetY;
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        final long downTime = SystemClock.uptimeMillis();
+
+        injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen);
+        injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
+        injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen);
+        injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen);
+        injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
+        injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen);
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Emulates a linear drag gesture between 2 points 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();
+        final long downTime = SystemClock.uptimeMillis();
+
+        injectDownEvent(uiAutomation, downTime, dragStartX, dragStartY);
+
+        // Inject a sequence of MOVE events that emulate the "move" part of the gesture
+        injectMoveEventsForDrag(uiAutomation, downTime, true, dragStartX, dragStartY,
+                dragStartX + dragAmountX, dragStartY + dragAmountY, moveEventCount, dragDurationMs);
+
+        injectUpEvent(uiAutomation, downTime, true, dragStartX + dragAmountX,
+                dragStartY + dragAmountY);
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Emulates a series of linear drag gestures across the screen between multiple points without
+     * lifting the finger. Note that this function does not support curve movements between the
+     * points.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param coordinates the ordered list of points for the drag gesture
+     */
+    public static void emulateDragGesture(Instrumentation instrumentation,
+            SparseArray<Point> coordinates) {
+        emulateDragGesture(instrumentation, coordinates, 2000, 20);
+    }
+
+    private static void emulateDragGesture(Instrumentation instrumentation,
+            SparseArray<Point> coordinates, int dragDurationMs, int moveEventCount) {
+        final int coordinatesSize = coordinates.size();
+        if (coordinatesSize < 2) {
+            throw new IllegalArgumentException("Need at least 2 points for emulating drag");
+        }
+        // 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();
+        final long downTime = SystemClock.uptimeMillis();
+
+        injectDownEvent(uiAutomation, downTime, coordinates.get(0).x, coordinates.get(0).y);
+
+        // Move to each coordinate.
+        for (int i = 0; i < coordinatesSize - 1; i++) {
+            // Inject a sequence of MOVE events that emulate the "move" part of the gesture.
+            injectMoveEventsForDrag(uiAutomation,
+                    downTime,
+                    true,
+                    coordinates.get(i).x,
+                    coordinates.get(i).y,
+                    coordinates.get(i + 1).x,
+                    coordinates.get(i + 1).y,
+                    moveEventCount,
+                    dragDurationMs);
+        }
+
+        injectUpEvent(uiAutomation,
+                downTime,
+                true,
+                coordinates.get(coordinatesSize - 1).x,
+                coordinates.get(coordinatesSize - 1).y);
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+
+    private static long injectDownEvent(UiAutomation uiAutomation, long downTime, int xOnScreen,
+            int yOnScreen) {
+        MotionEvent eventDown = MotionEvent.obtain(
+                downTime, downTime, MotionEvent.ACTION_DOWN, xOnScreen, yOnScreen, 1);
+        eventDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        uiAutomation.injectInputEvent(eventDown, true);
+        eventDown.recycle();
+        return downTime;
+    }
+
+    private static void injectMoveEventForTap(UiAutomation uiAutomation, long downTime,
+            int touchSlop, int xOnScreen, int yOnScreen) {
+        MotionEvent eventMove = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_MOVE,
+                xOnScreen + (touchSlop / 2.0f), yOnScreen + (touchSlop / 2.0f), 1);
+        eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        uiAutomation.injectInputEvent(eventMove, true);
+        eventMove.recycle();
+    }
+
+    private static void injectMoveEventsForDrag(UiAutomation uiAutomation, long downTime,
+            boolean useCurrentEventTime, int dragStartX, int dragStartY, int dragEndX, int dragEndY,
+            int moveEventCount, int dragDurationMs) {
+        final int dragAmountX = dragEndX - dragStartX;
+        final int dragAmountY = dragEndY - dragStartY;
+        final int sleepTime = dragDurationMs / moveEventCount;
+
+        // sleep for a bit to emulate the overall drag gesture.
+        long prevEventTime = downTime;
+        SystemClock.sleep(sleepTime);
+        for (int i = 0; i < moveEventCount; i++) {
+            // Note that the first MOVE event is generated "away" from the coordinates
+            // of the start / DOWN event, and the last MOVE event is generated
+            // at the same coordinates as the subsequent UP event.
+            final int moveX = dragStartX + dragAmountX * (i  + 1) / moveEventCount;
+            final int moveY = dragStartY + dragAmountY * (i  + 1) / moveEventCount;
+            long eventTime = useCurrentEventTime ? SystemClock.uptimeMillis() : downTime;
+
+            // If necessary, generate history for our next MOVE event. The history is generated
+            // to be spaced at 10 millisecond intervals, interpolating the coordinates from the
+            // last generated MOVE event to our current one.
+            int historyEventCount = (int) ((eventTime - prevEventTime) / 10);
+            MotionEvent eventMove = null;
+            if (historyEventCount == 0) {
+                eventMove = MotionEvent.obtain(
+                        downTime, eventTime, MotionEvent.ACTION_MOVE, moveX, moveY, 1);
+            } else {
+                final int prevMoveX = dragStartX + dragAmountX * i / moveEventCount;
+                final int prevMoveY = dragStartY + dragAmountY * i / moveEventCount;
+                final int deltaMoveX = moveX - prevMoveX;
+                final int deltaMoveY = moveY - prevMoveY;
+                final long deltaTime = (eventTime - prevEventTime);
+                for (int historyIndex = 0; historyIndex < historyEventCount; historyIndex++) {
+                    int stepMoveX = prevMoveX + deltaMoveX * (historyIndex + 1) / historyEventCount;
+                    int stepMoveY = prevMoveY + deltaMoveY * (historyIndex + 1) / historyEventCount;
+                    long stepEventTime = useCurrentEventTime
+                            ? prevEventTime + deltaTime * (historyIndex + 1) / historyEventCount
+                            : downTime;
+                    if (historyIndex == 0) {
+                        // Generate the first event in our sequence
+                        eventMove = MotionEvent.obtain(downTime, stepEventTime,
+                                MotionEvent.ACTION_MOVE, stepMoveX, stepMoveY, 1);
+                    } else {
+                        // and then add to it
+                        eventMove.addBatch(stepEventTime, stepMoveX, stepMoveY, 1.0f, 1.0f, 1);
+                    }
+                }
+            }
+
+            eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            uiAutomation.injectInputEvent(eventMove, true);
+            eventMove.recycle();
+            prevEventTime = eventTime;
+
+            // sleep for a bit to emulate the overall drag gesture.
+            SystemClock.sleep(sleepTime);
+        }
+    }
+
+    private static void injectUpEvent(UiAutomation uiAutomation, long downTime,
+            boolean useCurrentEventTime, int xOnScreen, int yOnScreen) {
+        long eventTime = useCurrentEventTime ? SystemClock.uptimeMillis() : downTime;
+        MotionEvent eventUp = MotionEvent.obtain(
+                downTime, eventTime, MotionEvent.ACTION_UP, xOnScreen, yOnScreen, 1);
+        eventUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        uiAutomation.injectInputEvent(eventUp, true);
+        eventUp.recycle();
+    }
+
+    /**
+     * 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, durationMs / 16);
+
+        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 press in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "long press"
+     */
+    public static void emulateLongPressOnViewCenter(Instrumentation instrumentation, View view) {
+        emulateLongPressOnViewCenter(instrumentation, view, 0);
+    }
+
+    /**
+     * Emulates a long press in the center of the passed {@link View}.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "long press"
+     * @param extraWaitMs the duration of emulated "long press" in milliseconds starting
+     *      after system-level long press timeout.
+     */
+    public static void emulateLongPressOnViewCenter(Instrumentation instrumentation, View view,
+            long extraWaitMs) {
+        final int touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        final int[] viewOnScreenXY = new int[2];
+        view.getLocationOnScreen(viewOnScreenXY);
+        int xOnScreen = viewOnScreenXY[0] + view.getWidth() / 2;
+        int yOnScreen = viewOnScreenXY[1] + view.getHeight() / 2;
+
+        emulateLongPressOnScreen(instrumentation, xOnScreen, yOnScreen, touchSlop, extraWaitMs);
+    }
+
+    /**
+     * Emulates a long press confirmed 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
+     * press point.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param view the view to "long press"
+     * @param offsetX extra X offset for the tap
+     * @param offsetY extra Y offset for the tap
+     */
+    public static void emulateLongPressOnView(Instrumentation instrumentation, View view,
+            int offsetX, int offsetY) {
+        final int touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
+        final int[] viewOnScreenXY = new int[2];
+        view.getLocationOnScreen(viewOnScreenXY);
+        int xOnScreen = viewOnScreenXY[0] + offsetX;
+        int yOnScreen = viewOnScreenXY[1] + offsetY;
+
+        emulateLongPressOnScreen(instrumentation, xOnScreen, yOnScreen, touchSlop, 0);
+    }
+
+    /**
+     * Emulates a long press on the screen.
+     *
+     * @param instrumentation the instrumentation used to run the test
+     * @param xOnScreen X position on screen for the "long press"
+     * @param yOnScreen Y position on screen for the "long press"
+     * @param extraWaitMs extra duration of emulated long press in milliseconds added
+     *        after the system-level "long press" timeout.
+     */
+    private static void emulateLongPressOnScreen(Instrumentation instrumentation,
+            int xOnScreen, int yOnScreen, int touchSlop, long extraWaitMs) {
+        final UiAutomation uiAutomation = instrumentation.getUiAutomation();
+        final long downTime = SystemClock.uptimeMillis();
+
+        injectDownEvent(uiAutomation, downTime, xOnScreen, yOnScreen);
+        injectMoveEventForTap(uiAutomation, downTime, touchSlop, xOnScreen, yOnScreen);
+        SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() * 1.5f) + extraWaitMs);
+        injectUpEvent(uiAutomation, downTime, false, xOnScreen, yOnScreen);
+
+        // Wait for the system to process all events in the queue
+        instrumentation.waitForIdleSync();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java b/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java
new file mode 100644
index 0000000..672106c
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DummyActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util;
+
+import android.app.Activity;
+
+public class DummyActivity extends Activity {
+
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java b/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
index 61f1bb8..073674a 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/EvaluateJsResultPollingCheck.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java b/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java
new file mode 100644
index 0000000..85e06ea
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/FakeKeys.java
@@ -0,0 +1,469 @@
+/*
+ * 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.compatibility.common.util;
+
+// Copied from cts/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+
+public class FakeKeys {
+    /*
+     * The keys and certificates below are generated with:
+     *
+     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
+     * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
+     * mkdir -p demoCA/newcerts
+     * touch demoCA/index.txt
+     * echo "01" > demoCA/serial
+     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
+     */
+    public static class FAKE_RSA_1 {
+        /**
+         * Generated from above and converted with:
+         *
+         * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+         */
+        public static final byte[] privateKey = {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
+            (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
+            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
+            (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
+            (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
+            (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
+            (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
+            (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
+            (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
+            (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
+            (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
+            (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
+            (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
+            (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
+            (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
+            (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
+            (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
+            (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
+            (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
+            (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
+            (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
+            (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
+            (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
+            (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
+            (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
+            (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
+            (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
+            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
+            (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
+            (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
+            (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
+            (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
+            (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
+            (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
+            (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
+            (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
+            (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
+            (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
+            (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
+            (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
+            (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
+            (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
+            (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
+            (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
+            (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
+            (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
+            (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
+            (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
+            (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
+            (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
+            (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
+            (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
+            (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
+            (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
+            (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
+            (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
+            (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
+            (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
+            (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
+            (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
+            (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
+            (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
+            (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
+            (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
+            (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
+            (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
+            (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
+            (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
+            (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
+            (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
+            (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
+            (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+            (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
+            (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
+            (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
+            (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
+            (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
+            (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
+            (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
+            (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
+            (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
+            (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
+            (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
+            (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
+            (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
+            (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
+            (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
+            (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
+            (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
+            (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
+            (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
+            (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
+            (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
+            (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
+            (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
+            (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
+            (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
+            (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
+            (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
+            (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
+            (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
+            (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
+            (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
+            (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
+            (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
+        };
+
+        /**
+         * Generated from above and converted with:
+         *
+         * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+         */
+        public static final byte[] caCertificate = {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82,
+            (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a,
+            (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a,
+            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31,
+            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53,
+            (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43,
+            (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d,
+            (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61,
+            (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
+            (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12,
+            (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69,
+            (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+            (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73,
+            (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32,
+            (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36,
+            (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17,
+            (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31,
+            (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34,
+            (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b,
+            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
+            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41,
+            (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d,
+            (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69,
+            (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77,
+            (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41,
+            (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64,
+            (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20,
+            (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30,
+            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
+            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72,
+            (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7,
+            (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c,
+            (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64,
+            (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42,
+            (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb,
+            (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01,
+            (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03,
+            (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7,
+            (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d,
+            (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00,
+            (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9,
+            (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41,
+            (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60,
+            (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56,
+            (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f,
+            (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92,
+            (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62,
+            (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6,
+            (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb,
+            (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f,
+            (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51,
+            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
+            (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30,
+            (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e,
+            (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05,
+            (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9,
+            (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d,
+            (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51,
+            (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+            (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80,
+            (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f,
+            (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73,
+            (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97,
+            (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4,
+            (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
+            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
+            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
+            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
+            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
+            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
+            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
+            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09,
+            (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e,
+            (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05,
+            (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30,
+            (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
+            (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+            (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
+            (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a,
+            (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2,
+            (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda,
+            (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe,
+            (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b,
+            (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19,
+            (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3,
+            (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85,
+            (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5,
+            (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80,
+            (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd,
+            (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38,
+            (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2,
+            (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50,
+            (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f,
+            (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12,
+            (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14,
+            (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb,
+            (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74,
+            (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0,
+            (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e,
+            (byte) 0xf1, (byte) 0x61
+        };
+    }
+
+    /*
+     * The keys and certificates below are generated with:
+     *
+     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
+     * openssl dsaparam -out dsaparam.pem 1024
+     * openssl req -newkey dsa:dsaparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req
+     * mkdir -p demoCA/newcerts
+     * touch demoCA/index.txt
+     * echo "01" > demoCA/serial
+     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
+     */
+    public static class FAKE_DSA_1 {
+        /**
+         * Generated from above and converted with: openssl pkcs8 -topk8 -outform d
+         * -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+         */
+        public static final byte[] privateKey = {
+            (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x4c, (byte) 0x02, (byte) 0x01,
+            (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2c, (byte) 0x06,
+            (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x38,
+            (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1f,
+            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xb3, (byte) 0x23,
+            (byte) 0xf7, (byte) 0x86, (byte) 0xbd, (byte) 0x3b, (byte) 0x86, (byte) 0xcc,
+            (byte) 0xc3, (byte) 0x91, (byte) 0xc0, (byte) 0x30, (byte) 0x32, (byte) 0x02,
+            (byte) 0x47, (byte) 0x35, (byte) 0x01, (byte) 0xef, (byte) 0xee, (byte) 0x98,
+            (byte) 0x13, (byte) 0x56, (byte) 0x49, (byte) 0x47, (byte) 0xb5, (byte) 0x20,
+            (byte) 0xa8, (byte) 0x60, (byte) 0xcb, (byte) 0xc0, (byte) 0xd5, (byte) 0x77,
+            (byte) 0xc1, (byte) 0x69, (byte) 0xcd, (byte) 0x18, (byte) 0x34, (byte) 0x92,
+            (byte) 0xf2, (byte) 0x6a, (byte) 0x2a, (byte) 0x10, (byte) 0x59, (byte) 0x1c,
+            (byte) 0x91, (byte) 0x20, (byte) 0x51, (byte) 0xca, (byte) 0x37, (byte) 0xb2,
+            (byte) 0x87, (byte) 0xa6, (byte) 0x8a, (byte) 0x02, (byte) 0xfd, (byte) 0x45,
+            (byte) 0x46, (byte) 0xf9, (byte) 0x76, (byte) 0xb1, (byte) 0x35, (byte) 0x38,
+            (byte) 0x8d, (byte) 0xff, (byte) 0x4c, (byte) 0x5d, (byte) 0x75, (byte) 0x8f,
+            (byte) 0x66, (byte) 0x15, (byte) 0x7d, (byte) 0x7b, (byte) 0xda, (byte) 0xdb,
+            (byte) 0x57, (byte) 0x39, (byte) 0xff, (byte) 0x91, (byte) 0x3f, (byte) 0xdd,
+            (byte) 0xe2, (byte) 0xb4, (byte) 0x22, (byte) 0x60, (byte) 0x4c, (byte) 0x32,
+            (byte) 0x3b, (byte) 0x9d, (byte) 0x34, (byte) 0x9f, (byte) 0xb9, (byte) 0x5d,
+            (byte) 0x75, (byte) 0xb9, (byte) 0xd3, (byte) 0x7f, (byte) 0x11, (byte) 0xba,
+            (byte) 0xb7, (byte) 0xc8, (byte) 0x32, (byte) 0xc6, (byte) 0xce, (byte) 0x71,
+            (byte) 0x91, (byte) 0xd3, (byte) 0x32, (byte) 0xaf, (byte) 0x4d, (byte) 0x7e,
+            (byte) 0x7c, (byte) 0x15, (byte) 0xf7, (byte) 0x71, (byte) 0x2c, (byte) 0x52,
+            (byte) 0x65, (byte) 0x4d, (byte) 0xa9, (byte) 0x81, (byte) 0x25, (byte) 0x35,
+            (byte) 0xce, (byte) 0x0b, (byte) 0x5b, (byte) 0x56, (byte) 0xfe, (byte) 0xf1,
+            (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xeb, (byte) 0x4e, (byte) 0x7f,
+            (byte) 0x7a, (byte) 0x31, (byte) 0xb3, (byte) 0x7d, (byte) 0x8d, (byte) 0xb2,
+            (byte) 0xf7, (byte) 0xaf, (byte) 0xad, (byte) 0xb1, (byte) 0x42, (byte) 0x92,
+            (byte) 0xf3, (byte) 0x6c, (byte) 0xe4, (byte) 0xed, (byte) 0x8b, (byte) 0x02,
+            (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x81, (byte) 0xc8, (byte) 0x36,
+            (byte) 0x48, (byte) 0xdb, (byte) 0x71, (byte) 0x2b, (byte) 0x91, (byte) 0xce,
+            (byte) 0x6d, (byte) 0xbc, (byte) 0xb8, (byte) 0xf9, (byte) 0xcb, (byte) 0x50,
+            (byte) 0x91, (byte) 0x10, (byte) 0x8a, (byte) 0xf8, (byte) 0x37, (byte) 0x50,
+            (byte) 0xda, (byte) 0x4f, (byte) 0xc8, (byte) 0x4d, (byte) 0x73, (byte) 0xcb,
+            (byte) 0x4d, (byte) 0xb0, (byte) 0x19, (byte) 0x54, (byte) 0x5a, (byte) 0xf3,
+            (byte) 0x6c, (byte) 0xc9, (byte) 0xd8, (byte) 0x96, (byte) 0xd9, (byte) 0xb0,
+            (byte) 0x54, (byte) 0x7e, (byte) 0x7d, (byte) 0xe2, (byte) 0x58, (byte) 0x0e,
+            (byte) 0x5f, (byte) 0xc0, (byte) 0xce, (byte) 0xb9, (byte) 0x5c, (byte) 0xe3,
+            (byte) 0xd3, (byte) 0xdf, (byte) 0xcf, (byte) 0x45, (byte) 0x74, (byte) 0xfb,
+            (byte) 0xe6, (byte) 0x20, (byte) 0xe7, (byte) 0xfc, (byte) 0x0f, (byte) 0xca,
+            (byte) 0xdb, (byte) 0xc0, (byte) 0x0b, (byte) 0xe1, (byte) 0x5a, (byte) 0x16,
+            (byte) 0x1d, (byte) 0xb3, (byte) 0x2e, (byte) 0xe5, (byte) 0x5f, (byte) 0x89,
+            (byte) 0x17, (byte) 0x73, (byte) 0x50, (byte) 0xd1, (byte) 0x4a, (byte) 0x60,
+            (byte) 0xb7, (byte) 0xaa, (byte) 0xf0, (byte) 0xc7, (byte) 0xc5, (byte) 0x03,
+            (byte) 0x4e, (byte) 0x36, (byte) 0x51, (byte) 0x9e, (byte) 0x2f, (byte) 0xfa,
+            (byte) 0xf3, (byte) 0xd6, (byte) 0x58, (byte) 0x14, (byte) 0x02, (byte) 0xb4,
+            (byte) 0x41, (byte) 0xd6, (byte) 0x72, (byte) 0x6f, (byte) 0x58, (byte) 0x5b,
+            (byte) 0x2d, (byte) 0x23, (byte) 0xc0, (byte) 0x75, (byte) 0x4f, (byte) 0x39,
+            (byte) 0xa8, (byte) 0x6a, (byte) 0xdf, (byte) 0x79, (byte) 0x21, (byte) 0xf2,
+            (byte) 0x77, (byte) 0x91, (byte) 0x3f, (byte) 0x1c, (byte) 0x4d, (byte) 0x48,
+            (byte) 0x78, (byte) 0xcd, (byte) 0xed, (byte) 0x79, (byte) 0x23, (byte) 0x04,
+            (byte) 0x17, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xc7, (byte) 0xe7,
+            (byte) 0xe2, (byte) 0x6b, (byte) 0x14, (byte) 0xe6, (byte) 0x31, (byte) 0x12,
+            (byte) 0xb2, (byte) 0x1e, (byte) 0xd4, (byte) 0xf2, (byte) 0x9b, (byte) 0x2c,
+            (byte) 0xf6, (byte) 0x54, (byte) 0x4c, (byte) 0x12, (byte) 0xe8, (byte) 0x22
+
+        };
+
+        /**
+         * Generated from above and converted with:
+         *
+         * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+         */
+        public static final byte[] caCertificate = new byte[] {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8a, (byte) 0x30, (byte) 0x82,
+            (byte) 0x01, (byte) 0xf3, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0x87, (byte) 0xc0,
+            (byte) 0x68, (byte) 0x7f, (byte) 0x42, (byte) 0x92, (byte) 0x0b, (byte) 0x7a,
+            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x5e, (byte) 0x31,
+            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
+            (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
+            (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
+            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
+            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
+            (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
+            (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
+            (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
+            (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
+            (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17, (byte) 0x30, (byte) 0x15,
+            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c,
+            (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
+            (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
+            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
+            (byte) 0x0d, (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32,
+            (byte) 0x37, (byte) 0x32, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x32,
+            (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33,
+            (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x32, (byte) 0x33,
+            (byte) 0x33, (byte) 0x31, (byte) 0x32, (byte) 0x39, (byte) 0x5a, (byte) 0x30,
+            (byte) 0x5e, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
+            (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
+            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c,
+            (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d,
+            (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
+            (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e,
+            (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74,
+            (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
+            (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
+            (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17,
+            (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x03, (byte) 0x0c, (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e,
+            (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c,
+            (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30,
+            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
+            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa4, (byte) 0xc7,
+            (byte) 0x06, (byte) 0xba, (byte) 0xdf, (byte) 0x2b, (byte) 0xee, (byte) 0xd2,
+            (byte) 0xb9, (byte) 0xe4, (byte) 0x52, (byte) 0x21, (byte) 0x68, (byte) 0x2b,
+            (byte) 0x83, (byte) 0xdf, (byte) 0xe3, (byte) 0x9c, (byte) 0x08, (byte) 0x73,
+            (byte) 0xdd, (byte) 0x90, (byte) 0xea, (byte) 0x97, (byte) 0x0c, (byte) 0x96,
+            (byte) 0x20, (byte) 0xb1, (byte) 0xee, (byte) 0x11, (byte) 0xd5, (byte) 0xd4,
+            (byte) 0x7c, (byte) 0x44, (byte) 0x96, (byte) 0x2e, (byte) 0x6e, (byte) 0xa2,
+            (byte) 0xb2, (byte) 0xa3, (byte) 0x4b, (byte) 0x0f, (byte) 0x32, (byte) 0x90,
+            (byte) 0xaf, (byte) 0x5c, (byte) 0x6f, (byte) 0x00, (byte) 0x88, (byte) 0x45,
+            (byte) 0x4e, (byte) 0x9b, (byte) 0x26, (byte) 0xc1, (byte) 0x94, (byte) 0x3c,
+            (byte) 0xfe, (byte) 0x10, (byte) 0xbd, (byte) 0xda, (byte) 0xf2, (byte) 0x8d,
+            (byte) 0x03, (byte) 0x52, (byte) 0x32, (byte) 0x11, (byte) 0xff, (byte) 0xf6,
+            (byte) 0xf9, (byte) 0x6e, (byte) 0x8f, (byte) 0x0f, (byte) 0xc8, (byte) 0x0a,
+            (byte) 0x48, (byte) 0x39, (byte) 0x33, (byte) 0xb9, (byte) 0x0c, (byte) 0xb3,
+            (byte) 0x2b, (byte) 0xab, (byte) 0x7d, (byte) 0x79, (byte) 0x6f, (byte) 0x57,
+            (byte) 0x5b, (byte) 0xb8, (byte) 0x84, (byte) 0xb6, (byte) 0xcc, (byte) 0xe8,
+            (byte) 0x30, (byte) 0x78, (byte) 0xff, (byte) 0x92, (byte) 0xe5, (byte) 0x43,
+            (byte) 0x2e, (byte) 0xef, (byte) 0x66, (byte) 0x98, (byte) 0xb4, (byte) 0xfe,
+            (byte) 0xa2, (byte) 0x40, (byte) 0xf2, (byte) 0x1f, (byte) 0xd0, (byte) 0x86,
+            (byte) 0x16, (byte) 0xc8, (byte) 0x45, (byte) 0xc4, (byte) 0x52, (byte) 0xcb,
+            (byte) 0x31, (byte) 0x5c, (byte) 0x9f, (byte) 0x32, (byte) 0x3b, (byte) 0xf7,
+            (byte) 0x19, (byte) 0x08, (byte) 0xc7, (byte) 0x00, (byte) 0x21, (byte) 0x7d,
+            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
+            (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16,
+            (byte) 0x04, (byte) 0x14, (byte) 0x47, (byte) 0x82, (byte) 0xa3, (byte) 0xf1,
+            (byte) 0xc2, (byte) 0x7e, (byte) 0x3a, (byte) 0xde, (byte) 0x4f, (byte) 0x30,
+            (byte) 0x4c, (byte) 0x7f, (byte) 0x72, (byte) 0x81, (byte) 0x15, (byte) 0x32,
+            (byte) 0xda, (byte) 0x7f, (byte) 0x58, (byte) 0x18, (byte) 0x30, (byte) 0x1f,
+            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04,
+            (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x47,
+            (byte) 0x82, (byte) 0xa3, (byte) 0xf1, (byte) 0xc2, (byte) 0x7e, (byte) 0x3a,
+            (byte) 0xde, (byte) 0x4f, (byte) 0x30, (byte) 0x4c, (byte) 0x7f, (byte) 0x72,
+            (byte) 0x81, (byte) 0x15, (byte) 0x32, (byte) 0xda, (byte) 0x7f, (byte) 0x58,
+            (byte) 0x18, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03,
+            (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
+            (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
+            (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00,
+            (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x08, (byte) 0x7f,
+            (byte) 0x6a, (byte) 0x48, (byte) 0x90, (byte) 0x7b, (byte) 0x9b, (byte) 0x72,
+            (byte) 0x13, (byte) 0xa7, (byte) 0xef, (byte) 0x6b, (byte) 0x0b, (byte) 0x59,
+            (byte) 0xe5, (byte) 0x49, (byte) 0x72, (byte) 0x3a, (byte) 0xc8, (byte) 0x84,
+            (byte) 0xcc, (byte) 0x23, (byte) 0x18, (byte) 0x4c, (byte) 0xec, (byte) 0xc7,
+            (byte) 0xef, (byte) 0xcb, (byte) 0xa7, (byte) 0xbe, (byte) 0xe4, (byte) 0xef,
+            (byte) 0x8f, (byte) 0xc6, (byte) 0x06, (byte) 0x8c, (byte) 0xc0, (byte) 0xe4,
+            (byte) 0x2f, (byte) 0x2a, (byte) 0xc0, (byte) 0x35, (byte) 0x7d, (byte) 0x5e,
+            (byte) 0x19, (byte) 0x29, (byte) 0x8c, (byte) 0xb9, (byte) 0xf1, (byte) 0x1e,
+            (byte) 0xaf, (byte) 0x82, (byte) 0xd8, (byte) 0xe3, (byte) 0x88, (byte) 0xe1,
+            (byte) 0x31, (byte) 0xc8, (byte) 0x82, (byte) 0x1f, (byte) 0x83, (byte) 0xa9,
+            (byte) 0xde, (byte) 0xfe, (byte) 0x4b, (byte) 0xe2, (byte) 0x78, (byte) 0x64,
+            (byte) 0xed, (byte) 0xa4, (byte) 0x7b, (byte) 0xee, (byte) 0x8d, (byte) 0x71,
+            (byte) 0x1b, (byte) 0x44, (byte) 0xe6, (byte) 0xb7, (byte) 0xe8, (byte) 0xc5,
+            (byte) 0x9a, (byte) 0x93, (byte) 0x92, (byte) 0x6f, (byte) 0x6f, (byte) 0xdb,
+            (byte) 0xbd, (byte) 0xd7, (byte) 0x03, (byte) 0x85, (byte) 0xa9, (byte) 0x5f,
+            (byte) 0x53, (byte) 0x5f, (byte) 0x5d, (byte) 0x30, (byte) 0xc6, (byte) 0xd9,
+            (byte) 0xce, (byte) 0x34, (byte) 0xa8, (byte) 0xbe, (byte) 0x31, (byte) 0x47,
+            (byte) 0x1c, (byte) 0xa4, (byte) 0x7f, (byte) 0xc0, (byte) 0x2c, (byte) 0xbc,
+            (byte) 0xfe, (byte) 0x1a, (byte) 0x31, (byte) 0xd8, (byte) 0x77, (byte) 0x4d,
+            (byte) 0xfc, (byte) 0x45, (byte) 0x84, (byte) 0xfc, (byte) 0x45, (byte) 0x12,
+            (byte) 0xab, (byte) 0x50, (byte) 0xe4, (byte) 0x45, (byte) 0xe5, (byte) 0x11
+        };
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java b/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java
index 02be372..f58dbd0 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/FileCopyHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -26,8 +26,8 @@
 import java.util.ArrayList;
 
 /**
- * FileCopyHelper is used to copy files from resources to the application directory and responsible
- * for deleting the files.
+ * FileCopyHelper is used to copy files from resources to the
+ * application directory and responsible for deleting the files.
  *
  * @see MediaStore_VideoTest
  * @see MediaStore_Images_MediaTest
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java
new file mode 100644
index 0000000..ceada01
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/FileUtils.java
@@ -0,0 +1,163 @@
+/*
+ * 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 com.android.compatibility.common.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Bits and pieces copied from hidden API of android.os.FileUtils. */
+public class FileUtils {
+
+    public static final int S_IFMT  = 0170000;
+    public static final int S_IFSOCK = 0140000;
+    public static final int S_IFLNK = 0120000;
+    public static final int S_IFREG = 0100000;
+    public static final int S_IFBLK = 0060000;
+    public static final int S_IFDIR = 0040000;
+    public static final int S_IFCHR = 0020000;
+    public static final int S_IFIFO = 0010000;
+
+    public static final int S_ISUID = 0004000;
+    public static final int S_ISGID = 0002000;
+    public static final int S_ISVTX = 0001000;
+
+    public static final int S_IRWXU = 00700;
+    public static final int S_IRUSR = 00400;
+    public static final int S_IWUSR = 00200;
+    public static final int S_IXUSR = 00100;
+
+    public static final int S_IRWXG = 00070;
+    public static final int S_IRGRP = 00040;
+    public static final int S_IWGRP = 00020;
+    public static final int S_IXGRP = 00010;
+
+    public static final int S_IRWXO = 00007;
+    public static final int S_IROTH = 00004;
+    public static final int S_IWOTH = 00002;
+    public static final int S_IXOTH = 00001;
+
+    static {
+        System.loadLibrary("cts_jni");
+    }
+
+    public static class FileStatus {
+
+        public int dev;
+        public int ino;
+        public int mode;
+        public int nlink;
+        public int uid;
+        public int gid;
+        public int rdev;
+        public long size;
+        public int blksize;
+        public long blocks;
+        public long atime;
+        public long mtime;
+        public long ctime;
+
+        public boolean hasModeFlag(int flag) {
+            if (((S_IRWXU | S_IRWXG | S_IRWXO) & flag) != flag) {
+                throw new IllegalArgumentException("Inappropriate flag " + flag);
+            }
+            return (mode & flag) == flag;
+        }
+
+        public boolean isOfType(int type) {
+            if ((type & S_IFMT) != type) {
+                throw new IllegalArgumentException("Unknown type " + type);
+            }
+            return (mode & S_IFMT) == type;
+        }
+    }
+
+    /**
+     * @param path of the file to stat
+     * @param status object to set the fields on
+     * @param statLinks or don't stat links (lstat vs stat)
+     * @return whether or not we were able to stat the file
+     */
+    public native static boolean getFileStatus(String path, FileStatus status, boolean statLinks);
+
+    public native static String getUserName(int uid);
+
+    public native static String getGroupName(int gid);
+
+    public native static int setPermissions(String file, int mode);
+
+    /**
+     * Copy data from a source stream to destFile.
+     * Return true if succeed, return false if failed.
+     */
+    public static boolean copyToFile(InputStream inputStream, File destFile) {
+        try {
+            if (destFile.exists()) {
+                destFile.delete();
+            }
+            FileOutputStream out = new FileOutputStream(destFile);
+            try {
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) >= 0) {
+                    out.write(buffer, 0, bytesRead);
+                }
+            } finally {
+                out.flush();
+                try {
+                    out.getFD().sync();
+                } catch (IOException e) {
+                }
+                out.close();
+            }
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    public static void createFile(File file, int numBytes) throws IOException {
+        File parentFile = file.getParentFile();
+        if (parentFile != null) {
+            parentFile.mkdirs();
+        }
+        byte[] buffer = new byte[numBytes];
+        FileOutputStream output = new FileOutputStream(file);
+        try {
+            output.write(buffer);
+        } finally {
+            output.close();
+        }
+    }
+
+    public static byte[] readInputStreamFully(InputStream is) {
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        byte[] buffer = new byte[32768];
+        int count;
+        try {
+            while ((count = is.read(buffer)) != -1) {
+                os.write(buffer, 0, count);
+            }
+            is.close();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return os.toByteArray();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java b/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java
new file mode 100644
index 0000000..f3c53fe
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/IBinderParcelable.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.compatibility.common.util;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class IBinderParcelable implements Parcelable {
+    public IBinder binder;
+
+    public IBinderParcelable(IBinder source) {
+        binder = source;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(binder);
+    }
+
+    public static final Parcelable.Creator<IBinderParcelable>
+        CREATOR = new Parcelable.Creator<IBinderParcelable>() {
+
+        public IBinderParcelable createFromParcel(Parcel source) {
+            return new IBinderParcelable(source);
+        }
+
+        public IBinderParcelable[] newArray(int size) {
+            return new IBinderParcelable[size];
+        }
+    };
+
+    private IBinderParcelable(Parcel source) {
+        binder = source.readStrongBinder();
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java
new file mode 100644
index 0000000..f233851
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/LocationUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util;
+
+import android.app.Instrumentation;
+import android.util.Log;
+
+import java.io.IOException;
+
+public class LocationUtils {
+    private static String TAG = "LocationUtils";
+
+    public static void registerMockLocationProvider(Instrumentation instrumentation,
+            boolean enable) {
+        StringBuilder command = new StringBuilder();
+        command.append("appops set ");
+        command.append(instrumentation.getContext().getPackageName());
+        command.append(" android:mock_location ");
+        command.append(enable ? "allow" : "deny");
+        try {
+            SystemUtil.runShellCommand(instrumentation, command.toString());
+        } catch (IOException e) {
+            Log.e(TAG, "Error managing mock location app. Command: " + command, e);
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java
new file mode 100644
index 0000000..469e99a
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+package com.android.compatibility.common.util;
+
+import android.media.MediaFormat;
+import android.util.Range;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import java.util.Arrays;
+import android.util.Log;
+
+public class MediaPerfUtils {
+    private static final String TAG = "MediaPerfUtils";
+
+    private static final int MOVING_AVERAGE_NUM_FRAMES = 10;
+    private static final int MOVING_AVERAGE_WINDOW_MS = 1000;
+
+    // allow a variance of 2x for measured frame rates (e.g. half of lower-limit to double of
+    // upper-limit of the published values). Also allow an extra 10% margin. This also acts as
+    // a limit for the size of the published rates (e.g. upper-limit / lower-limit <= tolerance).
+    private static final double FRAMERATE_TOLERANCE = 2.0 * 1.1;
+
+    /*
+     *  ------------------ HELPER METHODS FOR ACHIEVABLE FRAME RATES ------------------
+     */
+
+    /** removes brackets from format to be included in JSON. */
+    private static String formatForReport(MediaFormat format) {
+        String asString = "" + format;
+        return asString.substring(1, asString.length() - 1);
+    }
+
+    /**
+     * Adds performance header info to |log| for |codecName|, |round|, |configFormat|, |inputFormat|
+     * and |outputFormat|. Also appends same to |message| and returns the resulting base message
+     * for logging purposes.
+     */
+    public static String addPerformanceHeadersToLog(
+            DeviceReportLog log, String message, int round, String codecName,
+            MediaFormat configFormat, MediaFormat inputFormat, MediaFormat outputFormat) {
+        String mime = configFormat.getString(MediaFormat.KEY_MIME);
+        int width = configFormat.getInteger(MediaFormat.KEY_WIDTH);
+        int height = configFormat.getInteger(MediaFormat.KEY_HEIGHT);
+
+        log.addValue("round", round, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("codec_name", codecName, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("mime_type", mime, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("width", width, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("height", height, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("config_format", formatForReport(configFormat),
+                ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("input_format", formatForReport(inputFormat),
+                ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("output_format", formatForReport(outputFormat),
+                ResultType.NEUTRAL, ResultUnit.NONE);
+
+        message += " codec=" + codecName + " round=" + round + " configFormat=" + configFormat
+                + " inputFormat=" + inputFormat + " outputFormat=" + outputFormat;
+
+        Range<Double> reported =
+            MediaUtils.getVideoCapabilities(codecName, mime)
+                    .getAchievableFrameRatesFor(width, height);
+        if (reported != null) {
+            log.addValue("reported_low", reported.getLower(), ResultType.NEUTRAL, ResultUnit.FPS);
+            log.addValue("reported_high", reported.getUpper(), ResultType.NEUTRAL, ResultUnit.FPS);
+            message += " reported=" + reported.getLower() + "-" + reported.getUpper();
+        }
+
+        return message;
+    }
+
+    /**
+     * Adds performance statistics based on the raw |stats| to |log|. Also prints the same into
+     * logcat. Returns the "final fps" value.
+     */
+    public static double addPerformanceStatsToLog(
+            DeviceReportLog log, MediaUtils.Stats durationsUsStats, String message) {
+
+        MediaUtils.Stats frameAvgUsStats =
+            durationsUsStats.movingAverage(MOVING_AVERAGE_NUM_FRAMES);
+        log.addValue(
+                "window_frames", MOVING_AVERAGE_NUM_FRAMES, ResultType.NEUTRAL, ResultUnit.COUNT);
+        logPerformanceStats(log, frameAvgUsStats, "frame_avg_stats",
+                message + " window=" + MOVING_AVERAGE_NUM_FRAMES);
+
+        MediaUtils.Stats timeAvgUsStats =
+            durationsUsStats.movingAverageOverSum(MOVING_AVERAGE_WINDOW_MS * 1000);
+        log.addValue("window_time", MOVING_AVERAGE_WINDOW_MS, ResultType.NEUTRAL, ResultUnit.MS);
+        double fps = logPerformanceStats(log, timeAvgUsStats, "time_avg_stats",
+                message + " windowMs=" + MOVING_AVERAGE_WINDOW_MS);
+
+        log.setSummary("fps", fps, ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        return fps;
+    }
+
+    /**
+     * Adds performance statistics based on the processed |stats| to |log| using |prefix|.
+     * Also prints the same into logcat using |message| as the base message. Returns the fps value
+     * for |stats|. |prefix| must be lowercase alphanumeric underscored format.
+     */
+    private static double logPerformanceStats(
+            DeviceReportLog log, MediaUtils.Stats statsUs, String prefix, String message) {
+        final String[] labels = {
+            "min", "p5", "p10", "p20", "p30", "p40", "p50", "p60", "p70", "p80", "p90", "p95", "max"
+        };
+        final double[] points = {
+             0,     5,    10,    20,    30,    40,    50,    60,    70,    80,    90,    95,    100
+        };
+
+        int num = statsUs.getNum();
+        long avg = Math.round(statsUs.getAverage());
+        long stdev = Math.round(statsUs.getStdev());
+        log.addValue(prefix + "_num", num, ResultType.NEUTRAL, ResultUnit.COUNT);
+        log.addValue(prefix + "_avg", avg / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
+        log.addValue(prefix + "_stdev", stdev / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
+        message += " num=" + num + " avg=" + avg + " stdev=" + stdev;
+        final double[] percentiles = statsUs.getPercentiles(points);
+        for (int i = 0; i < labels.length; ++i) {
+            long p = Math.round(percentiles[i]);
+            message += " " + labels[i] + "=" + p;
+            log.addValue(prefix + "_" + labels[i], p / 1000., ResultType.NEUTRAL, ResultUnit.MS);
+        }
+
+        // print result to logcat in case test aborts before logs are written
+        Log.i(TAG, message);
+
+        return 1e6 / percentiles[points.length - 2];
+    }
+
+    /** Verifies |measuredFps| against reported achievable rates. Returns null if at least
+     *  one measurement falls within the margins of the reported range. Otherwise, returns
+     *  an error message to display.*/
+    public static String verifyAchievableFrameRates(
+            String name, String mime, int w, int h, double... measuredFps) {
+        Range<Double> reported =
+            MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
+        String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
+        if (reported == null) {
+            return "Failed to get " + kind;
+        }
+        double lowerBoundary1 = reported.getLower() / FRAMERATE_TOLERANCE;
+        double upperBoundary1 = reported.getUpper() * FRAMERATE_TOLERANCE;
+        double lowerBoundary2 = reported.getUpper() / Math.pow(FRAMERATE_TOLERANCE, 2);
+        double upperBoundary2 = reported.getLower() * Math.pow(FRAMERATE_TOLERANCE, 2);
+        Log.d(TAG, name + " " + mime + " " + w + "x" + h +
+                " lowerBoundary1 " + lowerBoundary1 + " upperBoundary1 " + upperBoundary1 +
+                " lowerBoundary2 " + lowerBoundary2 + " upperBoundary2 " + upperBoundary2 +
+                " measured " + Arrays.toString(measuredFps));
+
+        for (double measured : measuredFps) {
+            if (measured >= lowerBoundary1 && measured <= upperBoundary1
+                    && measured >= lowerBoundary2 && measured <= upperBoundary2) {
+                return null;
+            }
+        }
+
+        return "Expected " + kind + ": " + reported + ".\n"
+                + "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
new file mode 100644
index 0000000..013e2f8
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
@@ -0,0 +1,1013 @@
+/*
+ * 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.compatibility.common.util;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.util.Log;
+import android.util.Range;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import java.lang.reflect.Method;
+import static java.lang.reflect.Modifier.isPublic;
+import static java.lang.reflect.Modifier.isStatic;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+
+import static junit.framework.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+
+public class MediaUtils {
+    private static final String TAG = "MediaUtils";
+
+    /*
+     *  ----------------------- HELPER METHODS FOR SKIPPING TESTS -----------------------
+     */
+    private static final int ALL_AV_TRACKS = -1;
+
+    private static final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+
+    /**
+     * Returns the test name (heuristically).
+     *
+     * Since it uses heuristics, this method has only been verified for media
+     * tests. This centralizes the way to signal errors during a test.
+     */
+    public static String getTestName() {
+        return getTestName(false /* withClass */);
+    }
+
+    /**
+     * Returns the test name with the full class (heuristically).
+     *
+     * Since it uses heuristics, this method has only been verified for media
+     * tests. This centralizes the way to signal errors during a test.
+     */
+    public static String getTestNameWithClass() {
+        return getTestName(true /* withClass */);
+    }
+
+    private static String getTestName(boolean withClass) {
+        int bestScore = -1;
+        String testName = "test???";
+        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+        for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
+            StackTraceElement[] stack = entry.getValue();
+            for (int index = 0; index < stack.length; ++index) {
+                // method name must start with "test"
+                String methodName = stack[index].getMethodName();
+                if (!methodName.startsWith("test")) {
+                    continue;
+                }
+
+                int score = 0;
+                // see if there is a public non-static void method that takes no argument
+                Class<?> clazz;
+                try {
+                    clazz = Class.forName(stack[index].getClassName());
+                    ++score;
+                    for (final Method method : clazz.getDeclaredMethods()) {
+                        if (method.getName().equals(methodName)
+                                && isPublic(method.getModifiers())
+                                && !isStatic(method.getModifiers())
+                                && method.getParameterTypes().length == 0
+                                && method.getReturnType().equals(Void.TYPE)) {
+                            ++score;
+                            break;
+                        }
+                    }
+                    if (score == 1) {
+                        // if we could read the class, but method is not public void, it is
+                        // not a candidate
+                        continue;
+                    }
+                } catch (ClassNotFoundException e) {
+                }
+
+                // even if we cannot verify the method signature, there are signals in the stack
+
+                // usually test method is invoked by reflection
+                int depth = 1;
+                while (index + depth < stack.length
+                        && stack[index + depth].getMethodName().equals("invoke")
+                        && stack[index + depth].getClassName().equals(
+                                "java.lang.reflect.Method")) {
+                    ++depth;
+                }
+                if (depth > 1) {
+                    ++score;
+                    // and usually test method is run by runMethod method in android.test package
+                    if (index + depth < stack.length) {
+                        if (stack[index + depth].getClassName().startsWith("android.test.")) {
+                            ++score;
+                        }
+                        if (stack[index + depth].getMethodName().equals("runMethod")) {
+                            ++score;
+                        }
+                    }
+                }
+
+                if (score > bestScore) {
+                    bestScore = score;
+                    testName = methodName;
+                    if (withClass) {
+                        testName = stack[index].getClassName() + "." + testName;
+                    }
+                }
+            }
+        }
+        return testName;
+    }
+
+    /**
+     * Finds test name (heuristically) and prints out standard skip message.
+     *
+     * Since it uses heuristics, this method has only been verified for media
+     * tests. This centralizes the way to signal a skipped test.
+     */
+    public static void skipTest(String tag, String reason) {
+        Log.i(tag, "SKIPPING " + getTestName() + "(): " + reason);
+        DeviceReportLog log = new DeviceReportLog("CtsMediaSkippedTests", "test_skipped");
+        log.addValue("reason", reason, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue(
+                "test", getTestNameWithClass(), ResultType.NEUTRAL, ResultUnit.NONE);
+        // TODO: replace with submit() when it is added to DeviceReportLog
+        try {
+            log.submit(null);
+        } catch (NullPointerException e) { }
+    }
+
+    /**
+     * Finds test name (heuristically) and prints out standard skip message.
+     *
+     * Since it uses heuristics, this method has only been verified for media
+     * tests.  This centralizes the way to signal a skipped test.
+     */
+    public static void skipTest(String reason) {
+        skipTest(TAG, reason);
+    }
+
+    public static boolean check(boolean result, String message) {
+        if (!result) {
+            skipTest(message);
+        }
+        return result;
+    }
+
+    /*
+     *  ------------------- HELPER METHODS FOR CHECKING CODEC SUPPORT -------------------
+     */
+
+    // returns the list of codecs that support any one of the formats
+    private static String[] getCodecNames(
+            boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        ArrayList<String> result = new ArrayList<>();
+        for (MediaCodecInfo info : mcl.getCodecInfos()) {
+            if (info.isEncoder() != isEncoder) {
+                continue;
+            }
+            if (isGoog != null
+                    && info.getName().toLowerCase().startsWith("omx.google.") != isGoog) {
+                continue;
+            }
+
+            for (MediaFormat format : formats) {
+                String mime = format.getString(MediaFormat.KEY_MIME);
+
+                CodecCapabilities caps = null;
+                try {
+                    caps = info.getCapabilitiesForType(mime);
+                } catch (IllegalArgumentException e) {  // mime is not supported
+                    continue;
+                }
+                if (caps.isFormatSupported(format)) {
+                    result.add(info.getName());
+                    break;
+                }
+            }
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    /* Use isGoog = null to query all decoders */
+    public static String[] getDecoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
+        return getCodecNames(false /* isEncoder */, isGoog, formats);
+    }
+
+    public static String[] getDecoderNames(MediaFormat... formats) {
+        return getCodecNames(false /* isEncoder */, null /* isGoog */, formats);
+    }
+
+    /* Use isGoog = null to query all decoders */
+    public static String[] getEncoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
+        return getCodecNames(true /* isEncoder */, isGoog, formats);
+    }
+
+    public static String[] getEncoderNames(MediaFormat... formats) {
+        return getCodecNames(true /* isEncoder */, null /* isGoog */, formats);
+    }
+
+    public static void verifyNumCodecs(
+            int count, boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
+        String desc = (isEncoder ? "encoders" : "decoders") + " for "
+                + (formats.length == 1 ? formats[0].toString() : Arrays.toString(formats));
+        if (isGoog != null) {
+            desc = (isGoog ? "Google " : "non-Google ") + desc;
+        }
+
+        String[] codecs = getCodecNames(isEncoder, isGoog, formats);
+        assertTrue("test can only verify " + count + " " + desc + "; found " + codecs.length + ": "
+                + Arrays.toString(codecs), codecs.length <= count);
+    }
+
+    public static MediaCodec getDecoder(MediaFormat format) {
+        String decoder = sMCL.findDecoderForFormat(format);
+        if (decoder != null) {
+            try {
+                return MediaCodec.createByCodecName(decoder);
+            } catch (IOException e) {
+            }
+        }
+        return null;
+    }
+
+    public static boolean canEncode(MediaFormat format) {
+        if (sMCL.findEncoderForFormat(format) == null) {
+            Log.i(TAG, "no encoder for " + format);
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean canDecode(MediaFormat format) {
+        if (sMCL.findDecoderForFormat(format) == null) {
+            Log.i(TAG, "no decoder for " + format);
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean supports(String codecName, String mime, int w, int h) {
+        // While this could be simply written as such, give more graceful feedback.
+        // MediaFormat format = MediaFormat.createVideoFormat(mime, w, h);
+        // return supports(codecName, format);
+
+        VideoCapabilities vidCap = getVideoCapabilities(codecName, mime);
+        if (vidCap == null) {
+            return false;
+        } else if (vidCap.isSizeSupported(w, h)) {
+            return true;
+        }
+
+        Log.w(TAG, "unsupported size " + w + "x" + h);
+        return false;
+    }
+
+    public static boolean supports(String codecName, MediaFormat format) {
+        MediaCodec codec;
+        try {
+            codec = MediaCodec.createByCodecName(codecName);
+        } catch (IOException e) {
+            Log.w(TAG, "codec not found: " + codecName);
+            return false;
+        }
+
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        CodecCapabilities cap = null;
+        try {
+            cap = codec.getCodecInfo().getCapabilitiesForType(mime);
+            return cap.isFormatSupported(format);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "not supported mime: " + mime);
+            return false;
+        } finally {
+            codec.release();
+        }
+    }
+
+    public static boolean hasCodecForTrack(MediaExtractor ex, int track) {
+        int count = ex.getTrackCount();
+        if (track < 0 || track >= count) {
+            throw new IndexOutOfBoundsException(track + " not in [0.." + (count - 1) + "]");
+        }
+        return canDecode(ex.getTrackFormat(track));
+    }
+
+    /**
+     * return true iff all audio and video tracks are supported
+     */
+    public static boolean hasCodecsForMedia(MediaExtractor ex) {
+        for (int i = 0; i < ex.getTrackCount(); ++i) {
+            MediaFormat format = ex.getTrackFormat(i);
+            // only check for audio and video codecs
+            String mime = format.getString(MediaFormat.KEY_MIME).toLowerCase();
+            if (!mime.startsWith("audio/") && !mime.startsWith("video/")) {
+                continue;
+            }
+            if (!canDecode(format)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * return true iff any track starting with mimePrefix is supported
+     */
+    public static boolean hasCodecForMediaAndDomain(MediaExtractor ex, String mimePrefix) {
+        mimePrefix = mimePrefix.toLowerCase();
+        for (int i = 0; i < ex.getTrackCount(); ++i) {
+            MediaFormat format = ex.getTrackFormat(i);
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            if (mime.toLowerCase().startsWith(mimePrefix)) {
+                if (canDecode(format)) {
+                    return true;
+                }
+                Log.i(TAG, "no decoder for " + format);
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasCodecsForResourceCombo(
+            Context context, int resourceId, int track, String mimePrefix) {
+        try {
+            AssetFileDescriptor afd = null;
+            MediaExtractor ex = null;
+            try {
+                afd = context.getResources().openRawResourceFd(resourceId);
+                ex = new MediaExtractor();
+                ex.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+                if (mimePrefix != null) {
+                    return hasCodecForMediaAndDomain(ex, mimePrefix);
+                } else if (track == ALL_AV_TRACKS) {
+                    return hasCodecsForMedia(ex);
+                } else {
+                    return hasCodecForTrack(ex, track);
+                }
+            } finally {
+                if (ex != null) {
+                    ex.release();
+                }
+                if (afd != null) {
+                    afd.close();
+                }
+            }
+        } catch (IOException e) {
+            Log.i(TAG, "could not open resource");
+        }
+        return false;
+    }
+
+    /**
+     * return true iff all audio and video tracks are supported
+     */
+    public static boolean hasCodecsForResource(Context context, int resourceId) {
+        return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, null /* mimePrefix */);
+    }
+
+    public static boolean checkCodecsForResource(Context context, int resourceId) {
+        return check(hasCodecsForResource(context, resourceId), "no decoder found");
+    }
+
+    /**
+     * return true iff track is supported.
+     */
+    public static boolean hasCodecForResource(Context context, int resourceId, int track) {
+        return hasCodecsForResourceCombo(context, resourceId, track, null /* mimePrefix */);
+    }
+
+    public static boolean checkCodecForResource(Context context, int resourceId, int track) {
+        return check(hasCodecForResource(context, resourceId, track), "no decoder found");
+    }
+
+    /**
+     * return true iff any track starting with mimePrefix is supported
+     */
+    public static boolean hasCodecForResourceAndDomain(
+            Context context, int resourceId, String mimePrefix) {
+        return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, mimePrefix);
+    }
+
+    /**
+     * return true iff all audio and video tracks are supported
+     */
+    public static boolean hasCodecsForPath(Context context, String path) {
+        MediaExtractor ex = null;
+        try {
+            ex = new MediaExtractor();
+            Uri uri = Uri.parse(path);
+            String scheme = uri.getScheme();
+            if (scheme == null) { // file
+                ex.setDataSource(path);
+            } else if (scheme.equalsIgnoreCase("file")) {
+                ex.setDataSource(uri.getPath());
+            } else {
+                ex.setDataSource(context, uri, null);
+            }
+            return hasCodecsForMedia(ex);
+        } catch (IOException e) {
+            Log.i(TAG, "could not open path " + path);
+        } finally {
+            if (ex != null) {
+                ex.release();
+            }
+        }
+        return true;
+    }
+
+    public static boolean checkCodecsForPath(Context context, String path) {
+        return check(hasCodecsForPath(context, path), "no decoder found");
+    }
+
+    public static boolean hasCodecForDomain(boolean encoder, String domain) {
+        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+            if (encoder != info.isEncoder()) {
+                continue;
+            }
+
+            for (String type : info.getSupportedTypes()) {
+                if (type.toLowerCase().startsWith(domain.toLowerCase() + "/")) {
+                    Log.i(TAG, "found codec " + info.getName() + " for mime " + type);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean checkCodecForDomain(boolean encoder, String domain) {
+        return check(hasCodecForDomain(encoder, domain),
+                "no " + domain + (encoder ? " encoder" : " decoder") + " found");
+    }
+
+    private static boolean hasCodecForMime(boolean encoder, String mime) {
+        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+            if (encoder != info.isEncoder()) {
+                continue;
+            }
+
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mime)) {
+                    Log.i(TAG, "found codec " + info.getName() + " for mime " + mime);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasCodecForMimes(boolean encoder, String[] mimes) {
+        for (String mime : mimes) {
+            if (!hasCodecForMime(encoder, mime)) {
+                Log.i(TAG, "no " + (encoder ? "encoder" : "decoder") + " for mime " + mime);
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    public static boolean hasEncoder(String... mimes) {
+        return hasCodecForMimes(true /* encoder */, mimes);
+    }
+
+    public static boolean hasDecoder(String... mimes) {
+        return hasCodecForMimes(false /* encoder */, mimes);
+    }
+
+    public static boolean checkDecoder(String... mimes) {
+        return check(hasCodecForMimes(false /* encoder */, mimes), "no decoder found");
+    }
+
+    public static boolean checkEncoder(String... mimes) {
+        return check(hasCodecForMimes(true /* encoder */, mimes), "no encoder found");
+    }
+
+    public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
+        MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
+        format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
+        return canDecode(format);
+    }
+
+    public static boolean canDecodeVideo(
+            String mime, int width, int height, float rate,
+            Integer profile, Integer level, Integer bitrate) {
+        MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
+        format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
+        if (profile != null) {
+            format.setInteger(MediaFormat.KEY_PROFILE, profile);
+            if (level != null) {
+                format.setInteger(MediaFormat.KEY_LEVEL, level);
+            }
+        }
+        if (bitrate != null) {
+            format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+        }
+        return canDecode(format);
+    }
+
+    public static boolean checkEncoderForFormat(MediaFormat format) {
+        return check(canEncode(format), "no encoder for " + format);
+    }
+
+    public static boolean checkDecoderForFormat(MediaFormat format) {
+        return check(canDecode(format), "no decoder for " + format);
+    }
+
+    /*
+     *  ----------------------- HELPER METHODS FOR MEDIA HANDLING -----------------------
+     */
+
+    public static VideoCapabilities getVideoCapabilities(String codecName, String mime) {
+        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+            if (!info.getName().equalsIgnoreCase(codecName)) {
+                continue;
+            }
+            CodecCapabilities caps;
+            try {
+                caps = info.getCapabilitiesForType(mime);
+            } catch (IllegalArgumentException e) {
+                // mime is not supported
+                Log.w(TAG, "not supported mime: " + mime);
+                return null;
+            }
+            VideoCapabilities vidCaps = caps.getVideoCapabilities();
+            if (vidCaps == null) {
+                Log.w(TAG, "not a video codec: " + codecName);
+            }
+            return vidCaps;
+        }
+        Log.w(TAG, "codec not found: " + codecName);
+        return null;
+    }
+
+    public static MediaFormat getTrackFormatForResource(
+            Context context, int resourceId, String mimeTypePrefix)
+            throws IOException {
+        MediaFormat format = null;
+        MediaExtractor extractor = new MediaExtractor();
+        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
+        try {
+            extractor.setDataSource(
+                    afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        } finally {
+            afd.close();
+        }
+        int trackIndex;
+        for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
+            MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
+            if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
+                format = trackMediaFormat;
+                break;
+            }
+        }
+        extractor.release();
+        afd.close();
+        if (format == null) {
+            throw new RuntimeException("couldn't get a track for " + mimeTypePrefix);
+        }
+
+        return format;
+    }
+
+    public static MediaExtractor createMediaExtractorForMimeType(
+            Context context, int resourceId, String mimeTypePrefix)
+            throws IOException {
+        MediaExtractor extractor = new MediaExtractor();
+        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
+        try {
+            extractor.setDataSource(
+                    afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        } finally {
+            afd.close();
+        }
+        int trackIndex;
+        for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
+            MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
+            if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
+                extractor.selectTrack(trackIndex);
+                break;
+            }
+        }
+        if (trackIndex == extractor.getTrackCount()) {
+            extractor.release();
+            throw new IllegalStateException("couldn't get a track for " + mimeTypePrefix);
+        }
+
+        return extractor;
+    }
+
+    /*
+     *  ---------------------- HELPER METHODS FOR CODEC CONFIGURATION
+     */
+
+    /** Format must contain mime, width and height.
+     *  Throws Exception if encoder does not support this width and height */
+    public static void setMaxEncoderFrameAndBitrates(
+            MediaCodec encoder, MediaFormat format, int maxFps) {
+        String mime = format.getString(MediaFormat.KEY_MIME);
+
+        VideoCapabilities vidCaps =
+            encoder.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities();
+        setMaxEncoderFrameAndBitrates(vidCaps, format, maxFps);
+    }
+
+    public static void setMaxEncoderFrameAndBitrates(
+            VideoCapabilities vidCaps, MediaFormat format, int maxFps) {
+        int width = format.getInteger(MediaFormat.KEY_WIDTH);
+        int height = format.getInteger(MediaFormat.KEY_HEIGHT);
+
+        int maxWidth = vidCaps.getSupportedWidths().getUpper();
+        int maxHeight = vidCaps.getSupportedHeightsFor(maxWidth).getUpper();
+        int frameRate = Math.min(
+                maxFps, vidCaps.getSupportedFrameRatesFor(width, height).getUpper().intValue());
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+
+        int bitrate = vidCaps.getBitrateRange().clamp(
+            (int)(vidCaps.getBitrateRange().getUpper() /
+                  Math.sqrt((double)maxWidth * maxHeight / width / height)));
+        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+    }
+
+    /*
+     *  ------------------ HELPER METHODS FOR STATISTICS AND REPORTING ------------------
+     */
+
+    // TODO: migrate this into com.android.compatibility.common.util.Stat
+    public static class Stats {
+        /** does not support NaN or Inf in |data| */
+        public Stats(double[] data) {
+            mData = data;
+            if (mData != null) {
+                mNum = mData.length;
+            }
+        }
+
+        public int getNum() {
+            return mNum;
+        }
+
+        /** calculate mSumX and mSumXX */
+        private void analyze() {
+            if (mAnalyzed) {
+                return;
+            }
+
+            if (mData != null) {
+                for (double x : mData) {
+                    if (!(x >= mMinX)) { // mMinX may be NaN
+                        mMinX = x;
+                    }
+                    if (!(x <= mMaxX)) { // mMaxX may be NaN
+                        mMaxX = x;
+                    }
+                    mSumX += x;
+                    mSumXX += x * x;
+                }
+            }
+            mAnalyzed = true;
+        }
+
+        /** returns the maximum or NaN if it does not exist */
+        public double getMin() {
+            analyze();
+            return mMinX;
+        }
+
+        /** returns the minimum or NaN if it does not exist */
+        public double getMax() {
+            analyze();
+            return mMaxX;
+        }
+
+        /** returns the average or NaN if it does not exist. */
+        public double getAverage() {
+            analyze();
+            if (mNum == 0) {
+                return Double.NaN;
+            } else {
+                return mSumX / mNum;
+            }
+        }
+
+        /** returns the standard deviation or NaN if it does not exist. */
+        public double getStdev() {
+            analyze();
+            if (mNum == 0) {
+                return Double.NaN;
+            } else {
+                double average = mSumX / mNum;
+                return Math.sqrt(mSumXX / mNum - average * average);
+            }
+        }
+
+        /** returns the statistics for the moving average over n values */
+        public Stats movingAverage(int n) {
+            if (n < 1 || mNum < n) {
+                return new Stats(null);
+            } else if (n == 1) {
+                return this;
+            }
+
+            double[] avgs = new double[mNum - n + 1];
+            double sum = 0;
+            for (int i = 0; i < mNum; ++i) {
+                sum += mData[i];
+                if (i >= n - 1) {
+                    avgs[i - n + 1] = sum / n;
+                    sum -= mData[i - n + 1];
+                }
+            }
+            return new Stats(avgs);
+        }
+
+        /** returns the statistics for the moving average over a window over the
+         *  cumulative sum. Basically, moves a window from: [0, window] to
+         *  [sum - window, sum] over the cumulative sum, over ((sum - window) / average)
+         *  steps, and returns the average value over each window.
+         *  This method is used to average time-diff data over a window of a constant time.
+         */
+        public Stats movingAverageOverSum(double window) {
+            if (window <= 0 || mNum < 1) {
+                return new Stats(null);
+            }
+
+            analyze();
+            double average = mSumX / mNum;
+            if (window >= mSumX) {
+                return new Stats(new double[] { average });
+            }
+            int samples = (int)Math.ceil((mSumX - window) / average);
+            double[] avgs = new double[samples];
+
+            // A somewhat brute force approach to calculating the moving average.
+            // TODO: add support for weights in Stats, so we can do a more refined approach.
+            double sum = 0; // sum of elements in the window
+            int num = 0; // number of elements in the moving window
+            int bi = 0; // index of the first element in the moving window
+            int ei = 0; // index of the last element in the moving window
+            double space = window; // space at the end of the window
+            double foot = 0; // space at the beginning of the window
+
+            // invariants: foot + sum + space == window
+            //             bi + num == ei
+            //
+            //  window:             |-------------------------------|
+            //                      |    <-----sum------>           |
+            //                      <foot>               <---space-->
+            //                           |               |
+            //  intervals:   |-----------|-------|-------|--------------------|--------|
+            //                           ^bi             ^ei
+
+            int ix = 0; // index in the result
+            while (ix < samples) {
+                // add intervals while there is space in the window
+                while (ei < mData.length && mData[ei] <= space) {
+                    space -= mData[ei];
+                    sum += mData[ei];
+                    num++;
+                    ei++;
+                }
+
+                // calculate average over window and deal with odds and ends (e.g. if there are no
+                // intervals in the current window: pick whichever element overlaps the window
+                // most.
+                if (num > 0) {
+                    avgs[ix++] = sum / num;
+                } else if (bi > 0 && foot > space) {
+                    // consider previous
+                    avgs[ix++] = mData[bi - 1];
+                } else if (ei == mData.length) {
+                    break;
+                } else {
+                    avgs[ix++] = mData[ei];
+                }
+
+                // move the window to the next position
+                foot -= average;
+                space += average;
+
+                // remove intervals that are now partially or wholly outside of the window
+                while (bi < ei && foot < 0) {
+                    foot += mData[bi];
+                    sum -= mData[bi];
+                    num--;
+                    bi++;
+                }
+            }
+            return new Stats(Arrays.copyOf(avgs, ix));
+        }
+
+        /** calculate mSortedData */
+        private void sort() {
+            if (mSorted || mNum == 0) {
+                return;
+            }
+            mSortedData = Arrays.copyOf(mData, mNum);
+            Arrays.sort(mSortedData);
+            mSorted = true;
+        }
+
+        /** returns an array of percentiles for the points using nearest rank */
+        public double[] getPercentiles(double... points) {
+            sort();
+            double[] res = new double[points.length];
+            for (int i = 0; i < points.length; ++i) {
+                if (mNum < 1 || points[i] < 0 || points[i] > 100) {
+                    res[i] = Double.NaN;
+                } else {
+                    res[i] = mSortedData[(int)Math.round(points[i] / 100 * (mNum - 1))];
+                }
+            }
+            return res;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o instanceof Stats) {
+                Stats other = (Stats)o;
+                if (other.mNum != mNum) {
+                    return false;
+                } else if (mNum == 0) {
+                    return true;
+                }
+                return Arrays.equals(mData, other.mData);
+            }
+            return false;
+        }
+
+        private double[] mData;
+        private double mSumX = 0;
+        private double mSumXX = 0;
+        private double mMinX = Double.NaN;
+        private double mMaxX = Double.NaN;
+        private int mNum = 0;
+        private boolean mAnalyzed = false;
+        private double[] mSortedData;
+        private boolean mSorted = false;
+    }
+
+    /**
+     * Convert a forward lock .dm message stream to a .fl file
+     * @param context Context to use
+     * @param dmStream The .dm message
+     * @param flFile The output file to be written
+     * @return success
+     */
+    public static boolean convertDmToFl(
+            Context context,
+            InputStream dmStream,
+            RandomAccessFile flFile) {
+        final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+        byte[] dmData = new byte[10000];
+        int totalRead = 0;
+        int numRead;
+        while (true) {
+            try {
+                numRead = dmStream.read(dmData, totalRead, dmData.length - totalRead);
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to read from input file");
+                return false;
+            }
+            if (numRead == -1) {
+                break;
+            }
+            totalRead += numRead;
+            if (totalRead == dmData.length) {
+                // grow array
+                dmData = Arrays.copyOf(dmData, dmData.length + 10000);
+            }
+        }
+        byte[] fileData = Arrays.copyOf(dmData, totalRead);
+
+        DrmManagerClient drmClient = null;
+        try {
+            drmClient = new DrmManagerClient(context);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "DrmManagerClient instance could not be created, context is Illegal.");
+            return false;
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+            return false;
+        }
+
+        try {
+            int convertSessionId = -1;
+            try {
+                convertSessionId = drmClient.openConvertSession(MIMETYPE_DRM_MESSAGE);
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "Conversion of Mimetype: " + MIMETYPE_DRM_MESSAGE
+                        + " is not supported.", e);
+                return false;
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not access Open DrmFramework.", e);
+                return false;
+            }
+
+            if (convertSessionId < 0) {
+                Log.w(TAG, "Failed to open session.");
+                return false;
+            }
+
+            DrmConvertedStatus convertedStatus = null;
+            try {
+                convertedStatus = drmClient.convertData(convertSessionId, fileData);
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+                        + convertSessionId, e);
+                return false;
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not convert data. Convertsession: " + convertSessionId, e);
+                return false;
+            }
+
+            if (convertedStatus == null ||
+                    convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+                    convertedStatus.convertedData == null) {
+                Log.w(TAG, "Error in converting data. Convertsession: " + convertSessionId);
+                try {
+                    DrmConvertedStatus result = drmClient.closeConvertSession(convertSessionId);
+                    if (result.statusCode != DrmConvertedStatus.STATUS_OK) {
+                        Log.w(TAG, "Conversion failed with status: " + result.statusCode);
+                        return false;
+                    }
+                } catch (IllegalStateException e) {
+                    Log.w(TAG, "Could not close session. Convertsession: " +
+                           convertSessionId, e);
+                }
+                return false;
+            }
+
+            try {
+                flFile.write(convertedStatus.convertedData, 0, convertedStatus.convertedData.length);
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to write to output file: " + e);
+                return false;
+            }
+
+            try {
+                convertedStatus = drmClient.closeConvertSession(convertSessionId);
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not close convertsession. Convertsession: " +
+                        convertSessionId, e);
+                return false;
+            }
+
+            if (convertedStatus == null ||
+                    convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+                    convertedStatus.convertedData == null) {
+                Log.w(TAG, "Error in closing session. Convertsession: " + convertSessionId);
+                return false;
+            }
+
+            try {
+                flFile.seek(convertedStatus.offset);
+                flFile.write(convertedStatus.convertedData);
+            } catch (IOException e) {
+                Log.w(TAG, "Could not update file.", e);
+                return false;
+            }
+
+            return true;
+        } finally {
+            drmClient.close();
+        }
+    }
+
+
+    /*
+     *  -------------------------------------- END --------------------------------------
+     */
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java
new file mode 100644
index 0000000..3153adb
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/NullWebViewUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * Utilities to enable the android.webkit.* CTS tests (and others that rely on a functioning
+ * android.webkit.WebView implementation) to determine whether a functioning WebView is present
+ * on the device or not.
+ *
+ * Test cases that require android.webkit.* classes should wrap their first usage of WebView in a
+ * try catch block, and pass any exception that is thrown to
+ * NullWebViewUtils.determineIfWebViewAvailable. The return value of
+ * NullWebViewUtils.isWebViewAvailable will then determine if the test should expect to be able to
+ * use a WebView.
+ */
+public class NullWebViewUtils {
+
+    private static boolean sWebViewUnavailable;
+
+    /**
+     * @param context Current Activity context, used to query the PackageManager.
+     * @param t       An exception thrown by trying to invoke android.webkit.* APIs.
+     */
+    public static void determineIfWebViewAvailable(Context context, Throwable t) {
+        sWebViewUnavailable = !hasWebViewFeature(context) && checkCauseWasUnsupportedOperation(t);
+    }
+
+    /**
+     * After calling determineIfWebViewAvailable, this returns whether a WebView is available on the
+     * device and wheter the test can rely on it.
+     * @return True iff. PackageManager determined that there is no WebView on the device and the
+     *         exception thrown from android.webkit.* was UnsupportedOperationException.
+     */
+    public static boolean isWebViewAvailable() {
+        return !sWebViewUnavailable;
+    }
+
+    private static boolean hasWebViewFeature(Context context) {
+        // Query the system property that determins if there is a functional WebView on the device.
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
+    }
+
+    private static boolean checkCauseWasUnsupportedOperation(Throwable t) {
+        if (t == null) return false;
+        while (t.getCause() != null) {
+            t = t.getCause();
+        }
+        return t instanceof UnsupportedOperationException;
+    }
+
+    /**
+     * Some CTS tests (by design) first use android.webkit.* from a background thread. This helper
+     * allows the test to catch the UnsupportedOperationException from that background thread, and
+     * then query the result from the test main thread.
+     */
+    public static class NullWebViewFromThreadExceptionHandler
+            implements Thread.UncaughtExceptionHandler {
+        private Throwable mPendingException;
+
+        @Override
+        public void uncaughtException(Thread t, Throwable e) {
+            mPendingException = e;
+        }
+
+        public boolean isWebViewAvailable(Context context) {
+            return hasWebViewFeature(context) ||
+                    !checkCauseWasUnsupportedOperation(mPendingException);
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java b/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java
index a976a92..bcc3530 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/PollingCheck.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -21,15 +21,18 @@
 import junit.framework.Assert;
 
 public abstract class PollingCheck {
-
     private static final long TIME_SLICE = 50;
-    private long mTimeoutMs = 3000;
+    private long mTimeout = 3000;
+
+    public static interface PollingCheckCondition {
+        boolean canProceed();
+    }
 
     public PollingCheck() {
     }
 
-    public PollingCheck(long timeoutMs) {
-        mTimeoutMs = timeoutMs;
+    public PollingCheck(long timeout) {
+        mTimeout = timeout;
     }
 
     protected abstract boolean check();
@@ -39,8 +42,8 @@
             return;
         }
 
-        long timeoutMs = mTimeoutMs;
-        while (timeoutMs > 0) {
+        long timeout = mTimeout;
+        while (timeout > 0) {
             try {
                 Thread.sleep(TIME_SLICE);
             } catch (InterruptedException e) {
@@ -51,23 +54,41 @@
                 return;
             }
 
-            timeoutMs -= TIME_SLICE;
+            timeout -= TIME_SLICE;
         }
 
         Assert.fail("unexpected timeout");
     }
 
-    public static void check(CharSequence message, long timeoutMs, Callable<Boolean> condition)
+    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
             throws Exception {
-        while (timeoutMs > 0) {
+        while (timeout > 0) {
             if (condition.call()) {
                 return;
             }
 
             Thread.sleep(TIME_SLICE);
-            timeoutMs -= TIME_SLICE;
+            timeout -= TIME_SLICE;
         }
 
         Assert.fail(message.toString());
     }
+
+    public static void waitFor(final PollingCheckCondition condition) {
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+
+    public static void waitFor(long timeout, final PollingCheckCondition condition) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
 }
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java b/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java
new file mode 100644
index 0000000..feaa9cd
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/ReadElf.java
@@ -0,0 +1,494 @@
+/*
+ * 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 com.android.compatibility.common.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A poor man's implementation of the readelf command. This program is designed
+ * to parse ELF (Executable and Linkable Format) files.
+ */
+public class ReadElf implements AutoCloseable {
+    /** The magic values for the ELF identification. */
+    private static final byte[] ELFMAG = {
+            (byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F', };
+
+    private static final int EI_NIDENT = 16;
+
+    private static final int EI_CLASS = 4;
+    private static final int EI_DATA = 5;
+
+    private static final int EM_386 = 3;
+    private static final int EM_MIPS = 8;
+    private static final int EM_ARM = 40;
+    private static final int EM_X86_64 = 62;
+    // http://en.wikipedia.org/wiki/Qualcomm_Hexagon
+    private static final int EM_QDSP6 = 164;
+    private static final int EM_AARCH64 = 183;
+
+    private static final int ELFCLASS32 = 1;
+    private static final int ELFCLASS64 = 2;
+
+    private static final int ELFDATA2LSB = 1;
+    private static final int ELFDATA2MSB = 2;
+
+    private static final int EV_CURRENT = 1;
+
+    private static final long PT_LOAD = 1;
+
+    private static final int SHT_SYMTAB = 2;
+    private static final int SHT_STRTAB = 3;
+    private static final int SHT_DYNAMIC = 6;
+    private static final int SHT_DYNSYM = 11;
+
+    public static class Symbol {
+        public static final int STB_LOCAL = 0;
+        public static final int STB_GLOBAL = 1;
+        public static final int STB_WEAK = 2;
+        public static final int STB_LOPROC = 13;
+        public static final int STB_HIPROC = 15;
+
+        public static final int STT_NOTYPE = 0;
+        public static final int STT_OBJECT = 1;
+        public static final int STT_FUNC = 2;
+        public static final int STT_SECTION = 3;
+        public static final int STT_FILE = 4;
+        public static final int STT_COMMON = 5;
+        public static final int STT_TLS = 6;
+
+        public final String name;
+        public final int bind;
+        public final int type;
+
+        Symbol(String name, int st_info) {
+            this.name = name;
+            this.bind = (st_info >> 4) & 0x0F;
+            this.type = st_info & 0x0F;
+        }
+
+        @Override
+        public String toString() {
+            return "Symbol[" + name + "," + toBind() + "," + toType() + "]";
+        }
+
+        private String toBind() {
+            switch (bind) {
+                case STB_LOCAL:
+                    return "LOCAL";
+                case STB_GLOBAL:
+                    return "GLOBAL";
+                case STB_WEAK:
+                    return "WEAK";
+            }
+            return "STB_??? (" + bind + ")";
+        }
+
+        private String toType() {
+            switch (type) {
+                case STT_NOTYPE:
+                    return "NOTYPE";
+                case STT_OBJECT:
+                    return "OBJECT";
+                case STT_FUNC:
+                    return "FUNC";
+                case STT_SECTION:
+                    return "SECTION";
+                case STT_FILE:
+                    return "FILE";
+                case STT_COMMON:
+                    return "COMMON";
+                case STT_TLS:
+                    return "TLS";
+            }
+            return "STT_??? (" + type + ")";
+        }
+    }
+
+    private final String mPath;
+    private final RandomAccessFile mFile;
+    private final byte[] mBuffer = new byte[512];
+    private int mEndian;
+    private boolean mIsDynamic;
+    private boolean mIsPIE;
+    private int mType;
+    private int mAddrSize;
+
+    /** Symbol Table offset */
+    private long mSymTabOffset;
+
+    /** Symbol Table size */
+    private long mSymTabSize;
+
+    /** Dynamic Symbol Table offset */
+    private long mDynSymOffset;
+
+    /** Dynamic Symbol Table size */
+    private long mDynSymSize;
+
+    /** Section Header String Table offset */
+    private long mShStrTabOffset;
+
+    /** Section Header String Table size */
+    private long mShStrTabSize;
+
+    /** String Table offset */
+    private long mStrTabOffset;
+
+    /** String Table size */
+    private long mStrTabSize;
+
+    /** Dynamic String Table offset */
+    private long mDynStrOffset;
+
+    /** Dynamic String Table size */
+    private long mDynStrSize;
+
+    /** Symbol Table symbol names */
+    private Map<String, Symbol> mSymbols;
+
+    /** Dynamic Symbol Table symbol names */
+    private Map<String, Symbol> mDynamicSymbols;
+
+    public static ReadElf read(File file) throws IOException {
+        return new ReadElf(file);
+    }
+
+    public static void main(String[] args) throws IOException {
+        for (String arg : args) {
+            ReadElf re = new ReadElf(new File(arg));
+            re.getSymbol("x");
+            re.getDynamicSymbol("x");
+            re.close();
+        }
+    }
+
+    public boolean isDynamic() {
+        return mIsDynamic;
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public boolean isPIE() {
+        return mIsPIE;
+    }
+
+    private ReadElf(File file) throws IOException {
+        mPath = file.getPath();
+        mFile = new RandomAccessFile(file, "r");
+
+        if (mFile.length() < EI_NIDENT) {
+            throw new IllegalArgumentException("Too small to be an ELF file: " + file);
+        }
+
+        readHeader();
+    }
+
+    @Override
+    public void close() {
+        try {
+            mFile.close();
+        } catch (IOException ignored) {
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void readHeader() throws IOException {
+        mFile.seek(0);
+        mFile.readFully(mBuffer, 0, EI_NIDENT);
+
+        if (mBuffer[0] != ELFMAG[0] || mBuffer[1] != ELFMAG[1] ||
+                mBuffer[2] != ELFMAG[2] || mBuffer[3] != ELFMAG[3]) {
+            throw new IllegalArgumentException("Invalid ELF file: " + mPath);
+        }
+
+        int elfClass = mBuffer[EI_CLASS];
+        if (elfClass == ELFCLASS32) {
+            mAddrSize = 4;
+        } else if (elfClass == ELFCLASS64) {
+            mAddrSize = 8;
+        } else {
+            throw new IOException("Invalid ELF EI_CLASS: " + elfClass + ": " + mPath);
+        }
+
+        mEndian = mBuffer[EI_DATA];
+        if (mEndian == ELFDATA2LSB) {
+        } else if (mEndian == ELFDATA2MSB) {
+            throw new IOException("Unsupported ELFDATA2MSB file: " + mPath);
+        } else {
+            throw new IOException("Invalid ELF EI_DATA: " + mEndian + ": " + mPath);
+        }
+
+        mType = readHalf();
+
+        int e_machine = readHalf();
+        if (e_machine != EM_386 && e_machine != EM_X86_64 &&
+                e_machine != EM_AARCH64 && e_machine != EM_ARM &&
+                e_machine != EM_MIPS &&
+                e_machine != EM_QDSP6) {
+            throw new IOException("Invalid ELF e_machine: " + e_machine + ": " + mPath);
+        }
+
+        // AbiTest relies on us rejecting any unsupported combinations.
+        if ((e_machine == EM_386 && elfClass != ELFCLASS32) ||
+                (e_machine == EM_X86_64 && elfClass != ELFCLASS64) ||
+                (e_machine == EM_AARCH64 && elfClass != ELFCLASS64) ||
+                (e_machine == EM_ARM && elfClass != ELFCLASS32) ||
+                (e_machine == EM_QDSP6 && elfClass != ELFCLASS32)) {
+            throw new IOException("Invalid e_machine/EI_CLASS ELF combination: " +
+                    e_machine + "/" + elfClass + ": " + mPath);
+        }
+
+        long e_version = readWord();
+        if (e_version != EV_CURRENT) {
+            throw new IOException("Invalid e_version: " + e_version + ": " + mPath);
+        }
+
+        long e_entry = readAddr();
+
+        long ph_off = readOff();
+        long sh_off = readOff();
+
+        long e_flags = readWord();
+        int e_ehsize = readHalf();
+        int e_phentsize = readHalf();
+        int e_phnum = readHalf();
+        int e_shentsize = readHalf();
+        int e_shnum = readHalf();
+        int e_shstrndx = readHalf();
+
+        readSectionHeaders(sh_off, e_shnum, e_shentsize, e_shstrndx);
+        readProgramHeaders(ph_off, e_phnum, e_phentsize);
+    }
+
+    private void readSectionHeaders(long sh_off, int e_shnum, int e_shentsize, int e_shstrndx)
+            throws IOException {
+        // Read the Section Header String Table offset first.
+        {
+            mFile.seek(sh_off + e_shstrndx * e_shentsize);
+
+            long sh_name = readWord();
+            long sh_type = readWord();
+            long sh_flags = readX(mAddrSize);
+            long sh_addr = readAddr();
+            long sh_offset = readOff();
+            long sh_size = readX(mAddrSize);
+            // ...
+
+            if (sh_type == SHT_STRTAB) {
+                mShStrTabOffset = sh_offset;
+                mShStrTabSize = sh_size;
+            }
+        }
+
+        for (int i = 0; i < e_shnum; ++i) {
+            // Don't bother to re-read the Section Header StrTab.
+            if (i == e_shstrndx) {
+                continue;
+            }
+
+            mFile.seek(sh_off + i * e_shentsize);
+
+            long sh_name = readWord();
+            long sh_type = readWord();
+            long sh_flags = readX(mAddrSize);
+            long sh_addr = readAddr();
+            long sh_offset = readOff();
+            long sh_size = readX(mAddrSize);
+
+            if (sh_type == SHT_SYMTAB || sh_type == SHT_DYNSYM) {
+                final String symTabName = readShStrTabEntry(sh_name);
+                if (".symtab".equals(symTabName)) {
+                    mSymTabOffset = sh_offset;
+                    mSymTabSize = sh_size;
+                } else if (".dynsym".equals(symTabName)) {
+                    mDynSymOffset = sh_offset;
+                    mDynSymSize = sh_size;
+                }
+            } else if (sh_type == SHT_STRTAB) {
+                final String strTabName = readShStrTabEntry(sh_name);
+                if (".strtab".equals(strTabName)) {
+                    mStrTabOffset = sh_offset;
+                    mStrTabSize = sh_size;
+                } else if (".dynstr".equals(strTabName)) {
+                    mDynStrOffset = sh_offset;
+                    mDynStrSize = sh_size;
+                }
+            } else if (sh_type == SHT_DYNAMIC) {
+                mIsDynamic = true;
+            }
+        }
+    }
+
+    private void readProgramHeaders(long ph_off, int e_phnum, int e_phentsize) throws IOException {
+        for (int i = 0; i < e_phnum; ++i) {
+            mFile.seek(ph_off + i * e_phentsize);
+
+            long p_type = readWord();
+            if (p_type == PT_LOAD) {
+                if (mAddrSize == 8) {
+                    // Only in Elf64_phdr; in Elf32_phdr p_flags is at the end.
+                    long p_flags = readWord();
+                }
+                long p_offset = readOff();
+                long p_vaddr = readAddr();
+                // ...
+
+                if (p_vaddr == 0) {
+                    mIsPIE = true;
+                }
+            }
+        }
+    }
+
+    private HashMap<String, Symbol> readSymbolTable(long symStrOffset, long symStrSize,
+            long tableOffset, long tableSize) throws IOException {
+        HashMap<String, Symbol> result = new HashMap<String, Symbol>();
+        mFile.seek(tableOffset);
+        while (mFile.getFilePointer() < tableOffset + tableSize) {
+            long st_name = readWord();
+            int st_info;
+            if (mAddrSize == 8) {
+                st_info = readByte();
+                int st_other = readByte();
+                int st_shndx = readHalf();
+                long st_value = readAddr();
+                long st_size = readX(mAddrSize);
+            } else {
+                long st_value = readAddr();
+                long st_size = readWord();
+                st_info = readByte();
+                int st_other = readByte();
+                int st_shndx = readHalf();
+            }
+            if (st_name == 0) {
+                continue;
+            }
+
+            final String symName = readStrTabEntry(symStrOffset, symStrSize, st_name);
+            if (symName != null) {
+                Symbol s = new Symbol(symName, st_info);
+                result.put(symName, s);
+            }
+        }
+        return result;
+    }
+
+    private String readShStrTabEntry(long strOffset) throws IOException {
+        if (mShStrTabOffset == 0 || strOffset < 0 || strOffset >= mShStrTabSize) {
+            return null;
+        }
+        return readString(mShStrTabOffset + strOffset);
+    }
+
+    private String readStrTabEntry(long tableOffset, long tableSize, long strOffset)
+            throws IOException {
+        if (tableOffset == 0 || strOffset < 0 || strOffset >= tableSize) {
+            return null;
+        }
+        return readString(tableOffset + strOffset);
+    }
+
+    private int readHalf() throws IOException {
+        return (int) readX(2);
+    }
+
+    private long readWord() throws IOException {
+        return readX(4);
+    }
+
+    private long readOff() throws IOException {
+        return readX(mAddrSize);
+    }
+
+    private long readAddr() throws IOException {
+        return readX(mAddrSize);
+    }
+
+    private long readX(int byteCount) throws IOException {
+        mFile.readFully(mBuffer, 0, byteCount);
+
+        int answer = 0;
+        if (mEndian == ELFDATA2LSB) {
+            for (int i = byteCount - 1; i >= 0; i--) {
+                answer = (answer << 8) | (mBuffer[i] & 0xff);
+            }
+        } else {
+            final int N = byteCount - 1;
+            for (int i = 0; i <= N; ++i) {
+                answer = (answer << 8) | (mBuffer[i] & 0xff);
+            }
+        }
+
+        return answer;
+    }
+
+    private String readString(long offset) throws IOException {
+        long originalOffset = mFile.getFilePointer();
+        mFile.seek(offset);
+        mFile.readFully(mBuffer, 0, (int) Math.min(mBuffer.length, mFile.length() - offset));
+        mFile.seek(originalOffset);
+
+        for (int i = 0; i < mBuffer.length; ++i) {
+            if (mBuffer[i] == 0) {
+                return new String(mBuffer, 0, i);
+            }
+        }
+
+        return null;
+    }
+
+    private int readByte() throws IOException {
+        return mFile.read() & 0xff;
+    }
+
+    public Symbol getSymbol(String name) {
+        if (mSymbols == null) {
+            try {
+                mSymbols = readSymbolTable(mStrTabOffset, mStrTabSize, mSymTabOffset, mSymTabSize);
+            } catch (IOException e) {
+                return null;
+            }
+        }
+        return mSymbols.get(name);
+    }
+
+    public Symbol getDynamicSymbol(String name) {
+        if (mDynamicSymbols == null) {
+            try {
+                mDynamicSymbols = readSymbolTable(
+                        mDynStrOffset, mDynStrSize, mDynSymOffset, mDynSymSize);
+            } catch (IOException e) {
+                return null;
+            }
+        }
+        return mDynamicSymbols.get(name);
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SynchronousPixelCopy.java b/common/device-side/util/src/com/android/compatibility/common/util/SynchronousPixelCopy.java
new file mode 100644
index 0000000..7ba8646
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/SynchronousPixelCopy.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 com.android.compatibility.common.util;
+
+import static org.junit.Assert.fail;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.PixelCopy;
+import android.view.Surface;
+import android.view.Window;
+import android.view.PixelCopy.OnPixelCopyFinishedListener;
+import android.view.SurfaceView;
+
+public class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
+    private static Handler sHandler;
+    static {
+        HandlerThread thread = new HandlerThread("PixelCopyHelper");
+        thread.start();
+        sHandler = new Handler(thread.getLooper());
+    }
+
+    private int mStatus = -1;
+
+    public int request(Surface source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Surface source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(SurfaceView source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(SurfaceView source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Window source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Window source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    private int getResultLocked() {
+        try {
+            this.wait(250);
+        } catch (InterruptedException e) {
+            fail("PixelCopy request didn't complete within 250ms");
+        }
+        return mStatus;
+    }
+
+    @Override
+    public void onPixelCopyFinished(int copyResult) {
+        synchronized (this) {
+            mStatus = copyResult;
+            this.notify();
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java
index 2ec9bef..20b4625 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/SystemUtil.java
@@ -18,9 +18,14 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.MemoryInfo;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+
 public class SystemUtil {
     public static long getFreeDiskSize(Context context) {
         final StatFs statFs = new StatFs(context.getFilesDir().getAbsolutePath());
@@ -38,4 +43,27 @@
         ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(info);
         return info.totalMem;
     }
+
+    /**
+     * Executes a shell command using shell user identity, and return the standard output in string
+     * <p>Note: calling this function requires API level 21 or above
+     * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
+     * instrumentation framework
+     * @param cmd the command to run
+     * @return the standard output of the command
+     * @throws Exception
+     */
+    public static String runShellCommand(Instrumentation instrumentation, String cmd)
+            throws IOException {
+        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+        byte[] buf = new byte[512];
+        int bytesRead;
+        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        StringBuffer stdout = new StringBuffer();
+        while ((bytesRead = fis.read(buf)) != -1) {
+            stdout.append(new String(buf, 0, bytesRead));
+        }
+        fis.close();
+        return stdout.toString();
+    }
 }
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java b/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java
new file mode 100644
index 0000000..894b9c8
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/TestThread.java
@@ -0,0 +1,93 @@
+/*
+ * 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 com.android.compatibility.common.util;
+
+/**
+ * Thread class for executing a Runnable containing assertions in a separate thread.
+ * Uncaught exceptions in the Runnable are rethrown in the context of the the thread
+ * calling the <code>runTest()</code> method.
+ */
+public final class TestThread extends Thread {
+    private Throwable mThrowable;
+    private Runnable mTarget;
+
+    public TestThread(Runnable target) {
+        mTarget = target;
+    }
+
+    @Override
+    public final void run() {
+        try {
+            mTarget.run();
+        } catch (Throwable t) {
+            mThrowable = t;
+        }
+    }
+
+    /**
+     * Run the target Runnable object and wait until the test finish or throw
+     * out Exception if test fail.
+     *
+     * @param runTime
+     * @throws Throwable
+     */
+    public void runTest(long runTime) throws Throwable {
+        start();
+        joinAndCheck(runTime);
+    }
+
+    /**
+     * Get the Throwable object which is thrown when test running
+     * @return  The Throwable object
+     */
+    public Throwable getThrowable() {
+        return mThrowable;
+    }
+
+    /**
+     * Set the Throwable object which is thrown when test running
+     * @param t The Throwable object
+     */
+    public void setThrowable(Throwable t) {
+        mThrowable = t;
+    }
+
+    /**
+     * Wait for the test thread to complete and throw the stored exception if there is one.
+     *
+     * @param runTime The time to wait for the test thread to complete.
+     * @throws Throwable
+     */
+    public void joinAndCheck(long runTime) throws Throwable {
+        this.join(runTime);
+        if (this.isAlive()) {
+            this.interrupt();
+            this.join(runTime);
+            throw new Exception("Thread did not finish within allotted time.");
+        }
+        checkException();
+    }
+
+    /**
+     * Check whether there is an exception when running Runnable object.
+     * @throws Throwable
+     */
+    public void checkException() throws Throwable {
+        if (mThrowable != null) {
+            throw mThrowable;
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java b/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java
index 4862323..efcc693 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/WatchDog.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -23,10 +23,11 @@
 import junit.framework.Assert;
 
 /**
- * Used to fail a test if a function takes more than a certain amount of time.
+ * class for checking if rendering function is alive or not.
+ * panic if watch-dog is not reset over certain amount of time
  */
 public class WatchDog implements Runnable {
-    private static final String TAG = WatchDog.class.getSimpleName();
+    private static final String TAG = "WatchDog";
     private Thread mThread;
     private Semaphore mSemaphore;
     private volatile boolean mStopRequested;
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java
new file mode 100644
index 0000000..d155d7f
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/WidgetTestUtils.java
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.rule.ActivityTestRule;
+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 have identical content (same dimensions, same configuration,
+     * same pixel content).
+     *
+     * @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) {
+            return;
+        }
+
+        if (b1 == null || b2 == null) {
+            Assert.fail("the bitmaps are not equal");
+        }
+
+        // b1 and b2 are all not null.
+        if (b1.getWidth() != b2.getWidth() || b1.getHeight() != b2.getHeight()
+            || b1.getConfig() != b2.getConfig()) {
+            Assert.fail("the bitmaps are not equal");
+        }
+
+        int w = b1.getWidth();
+        int h = b1.getHeight();
+        int s = w * h;
+        int[] pixels1 = new int[s];
+        int[] pixels2 = new int[s];
+
+        b1.getPixels(pixels1, 0, w, 0, 0, w, h);
+        b2.getPixels(pixels2, 0, w, 0, 0, w, h);
+
+        for (int i = 0; i < s; i++) {
+            if (pixels1[i] != pixels2[i]) {
+                Assert.fail("the bitmaps are not equal");
+            }
+        }
+    }
+
+    /**
+     * Find beginning of the special element.
+     * @param parser XmlPullParser will be parsed.
+     * @param firstElementName the target element name.
+     *
+     * @throws XmlPullParserException if XML Pull Parser related faults occur.
+     * @throws IOException if I/O-related error occur when parsing.
+     */
+    public static final void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        Assert.assertNotNull(parser);
+        Assert.assertNotNull(firstElementName);
+
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            ;
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+                    + ", expected " + firstElementName);
+        }
+    }
+
+    /**
+     * Compare the expected pixels with actual, scaling for the target context density
+     *
+     * @throws AssertionFailedError
+     */
+    public static void assertScaledPixels(int expected, int actual, Context context) {
+        Assert.assertEquals(expected * context.getResources().getDisplayMetrics().density,
+                actual, 3);
+    }
+
+    /** Converts dips into pixels using the {@link Context}'s density. */
+    public static int convertDipToPixels(Context context, int dip) {
+      float density = context.getResources().getDisplayMetrics().density;
+      return Math.round(density * dip);
+    }
+
+    /**
+     * Retrieve a bitmap that can be used for comparison on any density
+     * @param resources
+     * @return the {@link Bitmap} or <code>null</code>
+     */
+    public static Bitmap getUnscaledBitmap(Resources resources, int resId) {
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inScaled = false;
+        return BitmapFactory.decodeResource(resources, resId, options);
+    }
+
+    /**
+     * Retrieve a dithered bitmap that can be used for comparison on any density
+     * @param resources
+     * @param config the preferred config for the returning bitmap
+     * @return the {@link Bitmap} or <code>null</code>
+     */
+    public static Bitmap getUnscaledAndDitheredBitmap(Resources resources,
+            int resId, Bitmap.Config config) {
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inDither = true;
+        options.inScaled = false;
+        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 activityTestRule the activity test rule 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 final ActivityTestRule activityTestRule,
+            @NonNull final View view, @Nullable final Runnable runner) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        activityTestRule.runOnUiThread(() -> {
+            final OnDrawListener listener = new OnDrawListener() {
+                @Override
+                public void onDraw() {
+                    // posting so that the sync happens after the draw that's about to happen
+                    view.post(() -> {
+                        activityTestRule.getActivity().getWindow().getDecorView().
+                                getViewTreeObserver().removeOnDrawListener(this);
+                        latch.countDown();
+                    });
+                }
+            };
+
+            activityTestRule.getActivity().getWindow().getDecorView().
+                    getViewTreeObserver().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);
+        }
+    }
+
+    /**
+     * Runs the specified Runnable on the main thread and ensures that the activity's view tree is
+     * laid out before returning.
+     *
+     * @param activityTestRule the activity test rule used to run the test
+     * @param runner the runnable to run on the main thread. {@code null} is
+     * allowed, and simply means that there no runnable is required.
+     * @param forceLayout true if there should be an explicit call to requestLayout(),
+     * false otherwise
+     */
+    public static void runOnMainAndLayoutSync(@NonNull final ActivityTestRule activityTestRule,
+            @Nullable final Runnable runner, boolean forceLayout)
+            throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        activityTestRule.runOnUiThread(() -> {
+            final OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
+                @Override
+                public void onGlobalLayout() {
+                    activityTestRule.getActivity().getWindow().getDecorView().
+                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    // countdown immediately since the layout we were waiting on has happened
+                    latch.countDown();
+                }
+            };
+
+            activityTestRule.getActivity().getWindow().getDecorView().
+                    getViewTreeObserver().addOnGlobalLayoutListener(listener);
+
+            if (runner != null) {
+                runner.run();
+            }
+
+            if (forceLayout) {
+                activityTestRule.getActivity().getWindow().getDecorView().requestLayout();
+            }
+        });
+
+        try {
+            Assert.assertTrue("Expected layout pass within 5 seconds",
+                    latch.await(5, TimeUnit.SECONDS));
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/Within.java b/common/device-side/util/src/com/android/compatibility/common/util/Within.java
new file mode 100644
index 0000000..9faf9e4
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/Within.java
@@ -0,0 +1,83 @@
+/*
+ * 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.compatibility.common.util;
+
+import android.os.SystemClock;
+
+import org.mockito.Mockito;
+import org.mockito.exceptions.base.MockitoAssertionError;
+import org.mockito.internal.verification.api.VerificationData;
+import org.mockito.invocation.Invocation;
+import org.mockito.verification.VerificationMode;
+
+import java.util.List;
+
+/**
+ * Custom verification mode that allows waiting for the specific invocation to happen within
+ * a certain time interval. Not that unlike {@link Mockito#timeout(int)}, this mode will not
+ * return early and throw exception if the expected method was called with a different set of
+ * parameters before the call that we're waiting for.
+ */
+public class Within implements VerificationMode {
+    private static final long TIME_SLICE = 50;
+    private final long mTimeout;
+
+    public Within(long timeout) {
+        mTimeout = timeout;
+    }
+
+    @Override
+    public void verify(VerificationData data) {
+        long timeout = mTimeout;
+        MockitoAssertionError errorToRethrow = null;
+        // Loop in the same way we do in PollingCheck, sleeping and then testing for the target
+        // invocation
+        while (timeout > 0) {
+            SystemClock.sleep(TIME_SLICE);
+
+            try {
+                final List<Invocation> actualInvocations = data.getAllInvocations();
+                // Iterate over all invocations so far to see if we have a match
+                for (Invocation invocation : actualInvocations) {
+                    if (data.getWanted().matches(invocation)) {
+                        // Found our match within our timeout. Mark all invocations as verified
+                        markAllInvocationsAsVerified(data);
+                        // and return
+                        return;
+                    }
+                }
+            } catch (MockitoAssertionError assertionError) {
+                errorToRethrow = assertionError;
+            }
+
+            timeout -= TIME_SLICE;
+        }
+
+        if (errorToRethrow != null) {
+            throw errorToRethrow;
+        }
+
+        throw new MockitoAssertionError(
+                "Timed out while waiting " + mTimeout + "ms for " + data.getWanted().toString());
+    }
+
+    private void markAllInvocationsAsVerified(VerificationData data) {
+        for (Invocation invocation : data.getAllInvocations()) {
+            invocation.markVerified();
+            data.getWanted().captureArgumentsFrom(invocation);
+        }
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java
new file mode 100644
index 0000000..7c53921
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/transition/TargetTracking.java
@@ -0,0 +1,27 @@
+/*
+ * 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.compatibility.common.util.transition;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public interface TargetTracking {
+    ArrayList<View> getTrackedTargets();
+    void clearTargets();
+    Rect getCapturedEpicenter();
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java
new file mode 100644
index 0000000..55b235d
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingTransition.java
@@ -0,0 +1,91 @@
+/*
+ * 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.compatibility.common.util.transition;
+
+import android.animation.Animator;
+import android.graphics.Rect;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * A transition that tracks which targets are applied to it.
+ * It will assume any target that it applies to will have differences
+ * between the start and end state, regardless of the differences
+ * that actually exist. In other words, it doesn't actually check
+ * any size or position differences or any other property of the view.
+ * It just records the difference.
+ * <p>
+ * Both start and end value Views are recorded, but no actual animation
+ * is created.
+ */
+public class TrackingTransition extends Transition implements TargetTracking {
+    public final ArrayList<View> targets = new ArrayList<>();
+    private final Rect[] mEpicenter = new Rect[1];
+    private static String PROP = "tracking:prop";
+    private static String[] PROPS = { PROP };
+
+    @Override
+    public String[] getTransitionProperties() {
+        return PROPS;
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROP, 0);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROP, 1);
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues != null) {
+            targets.add(startValues.view);
+        }
+        if (endValues != null) {
+            targets.add(endValues.view);
+        }
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public ArrayList<View> getTrackedTargets() {
+        return targets;
+    }
+
+    @Override
+    public void clearTargets() {
+        targets.clear();
+    }
+
+    @Override
+    public Rect getCapturedEpicenter() {
+        return mEpicenter[0];
+    }
+}
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.java b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.java
new file mode 100644
index 0000000..8a5a19e
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/transition/TrackingVisibility.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.compatibility.common.util.transition;
+
+import android.animation.Animator;
+import android.graphics.Rect;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * Visibility transition that tracks which targets are applied to it.
+ * This transition does no animation.
+ */
+public class TrackingVisibility extends Visibility implements TargetTracking {
+    public final ArrayList<View> targets = new ArrayList<>();
+    private final Rect[] mEpicenter = new Rect[1];
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        targets.add(endValues.view);
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        targets.add(startValues.view);
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public ArrayList<View> getTrackedTargets() {
+        return targets;
+    }
+
+    @Override
+    public void clearTargets() {
+        targets.clear();
+    }
+
+    @Override
+    public Rect getCapturedEpicenter() {
+        return mEpicenter[0];
+    }
+}
diff --git a/common/host-side/tradefed/res/config/cts-unit-tests.xml b/common/host-side/tradefed/res/config/cts-unit-tests.xml
new file mode 100644
index 0000000..4bec93e
--- /dev/null
+++ b/common/host-side/tradefed/res/config/cts-unit-tests.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.
+-->
+<configuration description="Executes the CTS unit tests">
+    <option name="null-device" value="true" />
+    <build_provider class="com.android.tradefed.build.StubBuildProvider" />
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="class" value="com.android.compatibility.common.tradefed.UnitTests" />
+        <option name="class" value="com.android.compatibility.common.util.HostUnitTests" />
+        <option name="class" value="com.android.compatibility.common.util.UnitTests" />
+        <option name="class" value="com.android.compatibility.tradefed.CtsTradefedTest" />
+        <option name="class" value="com.drawelements.deqp.runner.DeqpTestRunnerTest" />
+    </test>
+    <logger class="com.android.tradefed.log.FileLogger" />
+
+    <result_reporter class="com.android.tradefed.result.ConsoleResultReporter" />
+    <template-include name="reporters" default="empty" />
+</configuration>
diff --git a/common/host-side/tradefed/res/config/everything.xml b/common/host-side/tradefed/res/config/everything.xml
index d1ac900..a38aa8a 100644
--- a/common/host-side/tradefed/res/config/everything.xml
+++ b/common/host-side/tradefed/res/config/everything.xml
@@ -16,6 +16,6 @@
 <configuration description="Common config for Compatibility suites to run all modules">
 
     <include name="common-compatibility-config" />
-    <option name="compatibility:plan" value="everything" />
+    <option name="plan" value="everything" />
 
 </configuration>
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index 156f3c6..b8c1245 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -150,10 +150,10 @@
                                     <xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(TestCase/Test[@result = 'not_executed'])"/>
+                                    <xsl:value-of select="@not_executed"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(TestCase/Test)"/>
+                                    <xsl:value-of select="count(TestCase/Test) + @not_executed"/>
                                 </td>
                             </tr>
                         </xsl:for-each> <!-- end Module -->
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index ed9150e..c1087a1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -15,7 +15,6 @@
  */
 package com.android.compatibility.common.tradefed.build;
 
-import com.android.compatibility.SuiteInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IFolderBuildInfo;
 
@@ -40,14 +39,12 @@
     private static final String SUITE_FULL_NAME = "SUITE_FULL_NAME";
     private static final String SUITE_VERSION = "SUITE_VERSION";
     private static final String SUITE_PLAN = "SUITE_PLAN";
-    private static final String RESULT_DIR = "RESULT_DIR";
     private static final String START_TIME_MS = "START_TIME_MS";
     private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
     private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
     private static final String COMMAND_LINE_ARGS = "command_line_args";
     private static final String RETRY_COMMAND_LINE_ARGS = "retry_command_line_args";
     private final IBuildInfo mBuildInfo;
-    private boolean mInitialized = false;
 
     /**
      * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IBuildInfo}.
@@ -56,53 +53,6 @@
         mBuildInfo = buildInfo;
     }
 
-    /**
-     * Initializes the {@link IBuildInfo} from the manifest with the current time
-     * as the start time.
-     */
-    public void init(String suitePlan, String dynamicConfigUrl) {
-        init(suitePlan, dynamicConfigUrl, System.currentTimeMillis());
-    }
-
-    /**
-     * Initializes the {@link IBuildInfo} from the manifest.
-     */
-    public void init(String suitePlan, String dynamicConfigUrl, long startTimeMs) {
-        if (mInitialized) {
-            return;
-        }
-        mInitialized = true;
-        mBuildInfo.addBuildAttribute(SUITE_BUILD, SuiteInfo.BUILD_NUMBER);
-        mBuildInfo.addBuildAttribute(SUITE_NAME, SuiteInfo.NAME);
-        mBuildInfo.addBuildAttribute(SUITE_FULL_NAME, SuiteInfo.FULLNAME);
-        mBuildInfo.addBuildAttribute(SUITE_VERSION, SuiteInfo.VERSION);
-        mBuildInfo.addBuildAttribute(SUITE_PLAN, suitePlan);
-        mBuildInfo.addBuildAttribute(START_TIME_MS, Long.toString(startTimeMs));
-        mBuildInfo.addBuildAttribute(RESULT_DIR, getDirSuffix(startTimeMs));
-        String rootDirPath = null;
-        if (mBuildInfo instanceof IFolderBuildInfo) {
-            File rootDir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
-            if (rootDir != null) {
-                rootDirPath = rootDir.getAbsolutePath();
-            }
-        }
-        rootDirPath = System.getProperty(String.format("%s_ROOT", SuiteInfo.NAME), rootDirPath);
-        if (rootDirPath == null || rootDirPath.trim().equals("")) {
-            throw new IllegalArgumentException(
-                    String.format("Missing install path property %s_ROOT", SuiteInfo.NAME));
-        }
-        File rootDir = new File(rootDirPath);
-        if (!rootDir.exists()) {
-            throw new IllegalArgumentException(
-                    String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath()));
-        }
-        mBuildInfo.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath());
-        if (dynamicConfigUrl != null && !dynamicConfigUrl.isEmpty()) {
-            mBuildInfo.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL,
-                    dynamicConfigUrl.replace("{suite-name}", getSuiteName()));
-        }
-    }
-
     public IBuildInfo getBuildInfo() {
         return mBuildInfo;
     }
@@ -258,6 +208,19 @@
     }
 
     /**
+     * @return a {@link File} representing the test file in the test modules directory.
+     * @throws FileNotFoundException if the test file cannot be found
+     */
+    public File getTestFile(String filename) throws FileNotFoundException {
+        File testFile = new File(getTestsDir(), filename);
+        if (!testFile.exists()) {
+            throw new FileNotFoundException(String.format(
+                    "Compatibility test file %s does not exist", filename));
+        }
+        return testFile;
+    }
+
+    /**
      * @return a {@link File} in the resultDir for logging invocation failures
      */
     public File getInvocationFailureFile() throws FileNotFoundException {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index ee6d7db..df3cfbc 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -22,11 +22,16 @@
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IBuildProvider;
 import com.android.tradefed.build.IDeviceBuildProvider;
+import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.regex.Pattern;
 /**
  * A simple {@link IBuildProvider} that uses a pre-existing Compatibility install.
@@ -35,6 +40,18 @@
 public class CompatibilityBuildProvider implements IDeviceBuildProvider {
 
     private static final Pattern RELEASE_BUILD = Pattern.compile("^[A-Z]{3}\\d{2}[A-Z]{0,1}$");
+    private static final String ROOT_DIR = "ROOT_DIR";
+    private static final String SUITE_BUILD = "SUITE_BUILD";
+    private static final String SUITE_NAME = "SUITE_NAME";
+    private static final String SUITE_FULL_NAME = "SUITE_FULL_NAME";
+    private static final String SUITE_VERSION = "SUITE_VERSION";
+    private static final String SUITE_PLAN = "SUITE_PLAN";
+    private static final String RESULT_DIR = "RESULT_DIR";
+    private static final String START_TIME_MS = "START_TIME_MS";
+    private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
+
+    /* API Key for compatibility test project, used for dynamic configuration */
+    private static final String API_KEY = "AIzaSyAbwX5JRlmsLeygY2WWihpIJPXFLueOQ3U";
 
     @Option(name="branch", description="build branch name to supply.")
     private String mBranch = null;
@@ -45,13 +62,23 @@
     @Option(name="test-tag", description="test tag name to supply.")
     private String mTestTag = "cts";
 
+    @Option(name = "dynamic-config-url",
+            description = "Specify the url for override config")
+    private String mURL = "https://androidpartner.googleapis.com/v1/dynamicconfig/"
+            + "suites/{suite-name}/modules/{module}/version/{version}?key=" + API_KEY;
+
+    @Option(name = "plan",
+            description = "the test suite plan to run, such as \"everything\" or \"cts\"",
+            importance = Importance.ALWAYS)
+    private String mSuitePlan;
+
     /**
      * {@inheritDoc}
      */
     @Override
     public IBuildInfo getBuild() {
         // Create a blank BuildInfo which will get populated later.
-        String version = SuiteInfo.BUILD_NUMBER;
+        String version = getSuiteInfoBuildNumber();
         if (version == null) {
             version = IBuildInfo.UNKNOWN_BUILD_ID;
         }
@@ -59,7 +86,7 @@
         if (mBranch  != null) {
             ctsBuild.setBuildBranch(mBranch);
         }
-
+        addCompatibilitySuiteInfo(ctsBuild);
         return ctsBuild;
     }
 
@@ -92,6 +119,7 @@
             if (RELEASE_BUILD.matcher(buildAlias).matches()) {
                 info.addBuildAttribute("build_alias", buildAlias);
             }
+            addCompatibilitySuiteInfo(info);
             return info;
         }
     }
@@ -111,4 +139,72 @@
     public void cleanUp(IBuildInfo info) {
         // ignore
     }
+
+    private void addCompatibilitySuiteInfo(IBuildInfo info) {
+        long startTimeMs = System.currentTimeMillis();
+        info.addBuildAttribute(SUITE_BUILD, getSuiteInfoBuildNumber());
+        info.addBuildAttribute(SUITE_NAME, getSuiteInfoName());
+        info.addBuildAttribute(SUITE_FULL_NAME, getSuiteInfoFullname());
+        info.addBuildAttribute(SUITE_VERSION, getSuiteInfoVersion());
+        info.addBuildAttribute(SUITE_PLAN, mSuitePlan);
+        info.addBuildAttribute(START_TIME_MS, Long.toString(startTimeMs));
+        info.addBuildAttribute(RESULT_DIR, getDirSuffix(startTimeMs));
+        String rootDirPath = null;
+        if (info instanceof IFolderBuildInfo) {
+            File rootDir = ((IFolderBuildInfo) info).getRootDir();
+            if (rootDir != null) {
+                rootDirPath = rootDir.getAbsolutePath();
+            }
+        }
+        rootDirPath = System.getProperty(String.format("%s_ROOT", getSuiteInfoName()), rootDirPath);
+        if (rootDirPath == null || rootDirPath.trim().equals("")) {
+            throw new IllegalArgumentException(
+                    String.format("Missing install path property %s_ROOT", getSuiteInfoName()));
+        }
+        File rootDir = new File(rootDirPath);
+        if (!rootDir.exists()) {
+            throw new IllegalArgumentException(
+                    String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath()));
+        }
+        info.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath());
+        if (mURL != null && !mURL.isEmpty()) {
+            info.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL,
+                    mURL.replace("{suite-name}", getSuiteInfoName()));
+        }
+    }
+
+    /**
+     * Return the SuiteInfo name generated at build time. Exposed for testing.
+     */
+    protected String getSuiteInfoName() {
+        return SuiteInfo.NAME;
+    }
+
+    /**
+     * Return the SuiteInfo build number generated at build time. Exposed for testing.
+     */
+    protected String getSuiteInfoBuildNumber() {
+        return SuiteInfo.BUILD_NUMBER;
+    }
+
+    /**
+     * Return the SuiteInfo fullname generated at build time. Exposed for testing.
+     */
+    protected String getSuiteInfoFullname() {
+        return SuiteInfo.FULLNAME;
+    }
+
+    /**
+     * Return the SuiteInfo version generated at build time. Exposed for testing.
+     */
+    protected String getSuiteInfoVersion() {
+        return SuiteInfo.VERSION;
+    }
+
+    /**
+     * @return a {@link String} to use for directory suffixes created from the given time.
+     */
+    private String getDirSuffix(long millis) {
+        return new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss").format(new Date(millis));
+    }
 }
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 eecb15c..702f224 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
@@ -66,6 +66,7 @@
     static {
         MODULE_SPLIT_EXCLUSIONS.add("CtsDeqpTestCases");
     }
+    private final static String ADD_PATTERN = "a(?:dd)?";
     private CompatibilityBuildHelper mBuildHelper;
 
     /**
@@ -75,6 +76,7 @@
     public void run() {
         printLine(String.format("Android %s %s (%s)", SuiteInfo.FULLNAME, SuiteInfo.VERSION,
                 SuiteInfo.BUILD_NUMBER));
+        printLine("Use \"help\" or \"help all\" to get more information on running commands.");
         super.run();
     }
 
@@ -84,6 +86,13 @@
     @Override
     protected void setCustomCommands(RegexTrie<Runnable> trie, List<String> genericHelp,
             Map<String, String> commandHelp) {
+
+        genericHelp.add("Enter 'help add'        for help with 'add subplan' commands");
+        genericHelp.add("\t----- " + SuiteInfo.FULLNAME + " usage ----- ");
+        genericHelp.add("Usage: run <plan> [--module <module name>] [ options ]");
+        genericHelp.add("Example: run cts --module CtsGestureTestCases --bugreport-on-failure");
+        genericHelp.add("");
+
         trie.put(new Runnable() {
             @Override
             public void run() {
@@ -131,7 +140,13 @@
                 }
                 addSubPlan(flatArgs);
             }
-        }, "a(?:dd)?", "s(?:ubplan)?", null);
+        }, ADD_PATTERN, "s(?:ubplan)?", null);
+        trie.put(new ArgRunnable<CaptureList>() {
+            @Override
+            public void run(CaptureList args) {
+                printLine("'add subplan' requires parameters, use 'help add' to get more details");
+            }
+        }, ADD_PATTERN, "s(?:ubplan)?");
         trie.put(new Runnable() {
             @Override
             public void run() {
@@ -147,10 +162,48 @@
             listHelp = new String();
         }
         String combinedHelp = listHelp +
-                "\tp[lans]\tList all plans" + LINE_SEPARATOR +
-                "\tm[odules]\tList all modules" + LINE_SEPARATOR +
-                "\tr[esults]\tList all results" + LINE_SEPARATOR;
+                LINE_SEPARATOR +
+                "\t----- " + SuiteInfo.FULLNAME + " specific options ----- " + LINE_SEPARATOR +
+                "\tp[lans]               List all plans available" + LINE_SEPARATOR +
+                "\tm[odules]             List all modules available" + LINE_SEPARATOR +
+                "\tr[esults]             List all results" + LINE_SEPARATOR;
         commandHelp.put(LIST_PATTERN, combinedHelp);
+
+        // Update existing RUN_PATTERN with CTS specific extra run possibilities.
+        String runHelp = commandHelp.get(RUN_PATTERN);
+        if (runHelp == null) {
+            runHelp = new String();
+        }
+        String combinedRunHelp = runHelp +
+                LINE_SEPARATOR +
+                "\t----- " + SuiteInfo.FULLNAME + " specific options ----- " + LINE_SEPARATOR +
+                "\t<plan> --module/-m <module>       Run a test module" + LINE_SEPARATOR +
+                "\t<plan> --module/-m <module> --test/-t <test_name>    Run a specific test from" +
+                " the module. Test name can be <package>.<class>, <package>.<class>#<method> or "
+                + "<native_binary_name>" + LINE_SEPARATOR +
+                "\t\tAvailable Options:" + LINE_SEPARATOR +
+                "\t\t\t--serial/-s <device_id>: The device to run the test on" + LINE_SEPARATOR +
+                "\t\t\t--abi/-a <abi>         : The ABI to run the test against" + LINE_SEPARATOR +
+                "\t\t\t--logcat-on-failure    : Capture logcat when a test fails"
+                + LINE_SEPARATOR +
+                "\t\t\t--bugreport-on-failure : Capture a bugreport when a test fails"
+                + LINE_SEPARATOR +
+                "\t\t\t--screenshot-on-failure: Capture a screenshot when a test fails"
+                + LINE_SEPARATOR +
+                "\t\t\t--shards <shards>: Shards a run into the given number of independent " +
+                "chunks, to run on multiple devices in parallel." + LINE_SEPARATOR;
+        commandHelp.put(RUN_PATTERN, combinedRunHelp);
+
+        commandHelp.put(ADD_PATTERN, String.format(
+                "%s help:" + LINE_SEPARATOR +
+                "\tadd s[ubplan]: create a subplan from a previous session" + LINE_SEPARATOR +
+                "\t\tAvailable Options:" + LINE_SEPARATOR +
+                "\t\t\t--session <session_id>: The session used to create a subplan"
+                + LINE_SEPARATOR +
+                "\t\t\t--name/-n <subplan_name>: The name of the new subplan" + LINE_SEPARATOR +
+                "\t\t\t--result-type <status>: Which results to include in the subplan. "
+                + "One of passed, failed, not_executed. Repeatable" + LINE_SEPARATOR,
+                ADD_PATTERN));
     }
 
     /**
@@ -161,67 +214,6 @@
         return String.format("%s-tf > ", SuiteInfo.NAME.toLowerCase());
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected String getGenericHelpString(List<String> genericHelp) {
-        StringBuilder helpBuilder = new StringBuilder();
-        helpBuilder.append(SuiteInfo.FULLNAME);
-        helpBuilder.append("\n\n");
-        helpBuilder.append(SuiteInfo.NAME);
-        helpBuilder.append(" is the test harness for running the Android Compatibility Suite, ");
-        helpBuilder.append("built on top of Trade Federation.\n\n");
-        helpBuilder.append("Available commands and options\n");
-        helpBuilder.append("Host:\n");
-        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("invocations have completed.\n");
-        helpBuilder.append("Run:\n");
-        final String runPrompt = "  run <plan> ";
-        helpBuilder.append(runPrompt);
-        helpBuilder.append("--module/-m <module>: run a test module.\n");
-        helpBuilder.append(runPrompt);
-        helpBuilder.append("--module/-m <module> --test/-t <test_name>: run a specific test from");
-        helpBuilder.append(" the module. Test name can be <package>.<class>, ");
-        helpBuilder.append("<package>.<class>#<method> or <native_name>.\n");
-        helpBuilder.append(runPrompt);
-        helpBuilder.append("--retry <session_id>: run all failed tests from a previous session.\n");
-        helpBuilder.append(runPrompt);
-        helpBuilder.append("--help/--help-all: get help for ");
-        helpBuilder.append(SuiteInfo.FULLNAME);
-        helpBuilder.append(".\n");
-        helpBuilder.append("Options:\n");
-        helpBuilder.append("  --serial/-s <device_id>: The device to run the test on.\n");
-        helpBuilder.append("  --abi/-a <abi>: The ABI to run the test against.\n");
-        helpBuilder.append("  --shards <shards>: Shards a run into the given number of independent");
-        helpBuilder.append(" chunks, to run on multiple devices in parallel.\n");
-        helpBuilder.append("  --logcat-on-failure: Capture logcat when a test fails.\n");
-        helpBuilder.append("  --bugreport-on-failure: Capture a bugreport when a test fails.\n");
-        helpBuilder.append("  --screenshot-on-failure: Capture a screenshot when a test fails.\n");
-        helpBuilder.append("List:\n");
-        helpBuilder.append("  l/list d/devices: list connected devices and their state\n");
-        helpBuilder.append("  l/list m/modules: list test modules\n");
-        helpBuilder.append("  l/list i/invocations: list invocations aka test runs currently in ");
-        helpBuilder.append("progress\n");
-        helpBuilder.append("  l/list c/commands: list commands aka test run commands currently");
-        helpBuilder.append(" in the queue waiting to be allocated devices\n");
-        helpBuilder.append("  l/list r/results: list results currently in the repository\n");
-        helpBuilder.append("Dump:\n");
-        helpBuilder.append("  d/dump l/logs: dump the tradefed logs for all running invocations\n");
-        helpBuilder.append("Add:\n");
-        helpBuilder.append("  a/add s/subplan: create a subplan from a previous session\n");
-        helpBuilder.append("Options:\n");
-        helpBuilder.append("  --session <session_id>: The session used to create a subplan.\n");
-        helpBuilder.append("  --name/-n <subplan_name>: The name of the new subplan.\n");
-        helpBuilder.append("  --result-type <status>: Which results to include in the");
-        helpBuilder.append(" subplan. One of passed, failed, not_executed. Repeatable.\n");
-
-        return helpBuilder.toString();
-    }
-
     private void listModules() {
         File[] files = null;
         try {
@@ -433,8 +425,6 @@
         if (mBuildHelper == null) {
             CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
             mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
-            mBuildHelper.init(
-                "" /* suite plan */, "" /* dynamic config url */, -1 /*startTimeMs*/);
         }
         return mBuildHelper;
     }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
index 47c13e1..cea6953 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ConsoleReporter.java
@@ -16,16 +16,13 @@
 
 package com.android.compatibility.common.tradefed.result;
 
-import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
-import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.config.OptionCopier;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.IShardableListener;
-import com.android.tradefed.result.StubTestInvocationListener;
 import com.android.tradefed.util.TimeUtil;
 
 import java.util.Map;
@@ -33,7 +30,7 @@
 /**
  * Write test progress to the test console.
  */
-public class ConsoleReporter extends StubTestInvocationListener implements IShardableListener {
+public class ConsoleReporter implements IShardableListener {
 
     private static final String UNKNOWN_DEVICE = "unknown_device";
 
@@ -122,7 +119,7 @@
      */
     @Override
     public void testAssumptionFailure(TestIdentifier test, String trace) {
-        logProgress("%s failed assumption: %s", test, trace);
+        logProgress("%s skip", test);
     }
 
     /**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java
index e588fbb..dffe3ba 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java
@@ -42,7 +42,7 @@
             return (f.exists() && f.length() != 0);
         } catch (FileNotFoundException e) {
             CLog.e("Could not find invocation failure file for session %s",
-                buildHelper.getDirSuffix(buildHelper.getStartTime()));
+                CompatibilityBuildHelper.getDirSuffix(buildHelper.getStartTime()));
             CLog.e(e);
             return false;
         }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index fa8d8ad..966aa54 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -28,7 +28,6 @@
 import com.android.compatibility.common.util.ResultHandler;
 import com.android.compatibility.common.util.ResultUploader;
 import com.android.compatibility.common.util.TestStatus;
-import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
@@ -59,13 +58,10 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.text.SimpleDateFormat;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 
 /**
@@ -191,7 +187,7 @@
      * Create directory structure where results and logs will be written.
      */
     private void initializeResultDirectories() {
-        info("Initializing result directory");
+        debug("Initializing result directory");
 
         try {
             // Initialize the result directory. Either a new directory or reusing
@@ -217,7 +213,7 @@
                     mResultDir.getAbsolutePath());
         }
 
-        info("Results Directory: " + mResultDir.getAbsolutePath());
+        debug("Results Directory: " + mResultDir.getAbsolutePath());
 
         mUploader = new ResultUploader(mResultServer, mBuildHelper.getSuiteName());
         try {
@@ -227,7 +223,7 @@
             e.printStackTrace();
         }
         if (mLogDir != null && mLogDir.mkdirs()) {
-            info("Created log dir %s", mLogDir.getAbsolutePath());
+            debug("Created log dir %s", mLogDir.getAbsolutePath());
         }
         if (mLogDir == null || !mLogDir.exists()) {
             throw new IllegalArgumentException(String.format("Could not create log dir %s",
@@ -450,13 +446,6 @@
         String moduleProgress = String.format("%d of %d",
                 mResult.getModuleCompleteCount(), mResult.getModules().size());
 
-        info("Invocation finished in %s. PASSED: %d, FAILED: %d, NOT EXECUTED: %d, MODULES: %s",
-                TimeUtil.formatElapsedTime(elapsedTime),
-                mResult.countResults(TestStatus.PASS),
-                mResult.countResults(TestStatus.FAIL),
-                mResult.getNotExecuted(),
-                moduleProgress);
-
         long startTime = mResult.getStartTime();
         try {
             // Zip the full test results directory.
@@ -470,7 +459,7 @@
                     mBuildHelper.getCommandLineArgs());
             info("Test Result: %s", resultFile.getCanonicalPath());
             File zippedResults = zipResults(mResultDir);
-            info("Full Result: %s", zippedResults.getCanonicalPath());
+            debug("Full Result: %s", zippedResults.getCanonicalPath());
 
             saveLog(resultFile, zippedResults);
 
@@ -480,6 +469,13 @@
             CLog.e("[%s] Exception while saving result XML.", mDeviceSerial);
             CLog.e(e);
         }
+        // print the run results last.
+        info("Invocation finished in %s. PASSED: %d, FAILED: %d, NOT EXECUTED: %d, MODULES: %s",
+                TimeUtil.formatElapsedTime(elapsedTime),
+                mResult.countResults(TestStatus.PASS),
+                mResult.countResults(TestStatus.FAIL),
+                mResult.getNotExecuted(),
+                moduleProgress);
     }
 
     /**
@@ -505,7 +501,7 @@
         try {
             LogFileSaver saver = new LogFileSaver(mLogDir);
             File logFile = saver.saveAndZipLogData(name, type, stream.createInputStream());
-            info("Saved logs for %s in %s", name, logFile.getAbsolutePath());
+            debug("Saved logs for %s in %s", name, logFile.getAbsolutePath());
         } catch (IOException e) {
             warn("Failed to write log for %s", name);
             e.printStackTrace();
@@ -601,10 +597,10 @@
     /**
      * When enabled, upload the result to a server.
      */
-    private void uploadResult(File resultFile) throws IOException {
+    private void uploadResult(File resultFile) {
         if (mResultServer != null && !mResultServer.trim().isEmpty() && !mDisableResultPosting) {
             try {
-                info("Result Server: %d", mUploader.uploadResult(resultFile, mReferenceUrl));
+                debug("Result Server: %d", mUploader.uploadResult(resultFile, mReferenceUrl));
             } catch (IOException ioe) {
                 CLog.e("[%s] IOException while uploading result.", mDeviceSerial);
                 CLog.e(ioe);
@@ -682,6 +678,13 @@
     }
 
     /**
+     *  Log debug to the console.
+     */
+    private static void debug(String format, Object... args) {
+        CLog.d(format, args);
+    }
+
+    /**
      *  Log a warning to the console.
      */
     private static void warn(String format, Object... args) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
index 7773d7d..9d7248a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
@@ -18,6 +18,7 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.targetprep.TargetSetupError;
 import com.android.tradefed.targetprep.TestAppInstallSetup;
 
@@ -43,8 +44,8 @@
      * {@inheritDoc}
      */
     @Override
-    protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName)
-            throws TargetSetupError {
+    protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName,
+            ITestDevice device) throws TargetSetupError {
         File apkFile = null;
         try {
             apkFile = new File(getTestsDir(buildInfo), apkFileName);
@@ -52,7 +53,8 @@
                 throw new FileNotFoundException();
             }
         } catch (FileNotFoundException e) {
-            throw new TargetSetupError(String.format("%s not found", apkFileName), e);
+            throw new TargetSetupError(String.format("%s not found", apkFileName), e,
+                    device.getDeviceDescriptor());
         }
         return apkFile;
     }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
index 6b87977..2069cb8 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -17,14 +17,13 @@
 package com.android.compatibility.common.tradefed.targetprep;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
-import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.ITargetCleaner;
@@ -33,8 +32,6 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -72,12 +69,14 @@
         }
         try {
             if (instrument(device, buildInfo)) {
-                logInfo("Target preparation successful");
+                CLog.d("Target preparation successful");
             } else {
-                throw new TargetSetupError("Not all target preparation steps completed");
+                throw new TargetSetupError("Not all target preparation steps completed",
+                        device.getDeviceDescriptor());
             }
         } catch (FileNotFoundException e) {
-            throw new TargetSetupError("Couldn't find apk to instrument", e);
+            throw new TargetSetupError("Couldn't find apk to instrument", e,
+                    device.getDeviceDescriptor());
         }
     }
 
@@ -117,7 +116,7 @@
             device.uninstallPackage(mPackageName);
         }
 
-        logInfo("Instrumenting package %s:", mPackageName);
+        logInfo("Instrumenting package: %s", mPackageName);
         AndroidJUnitTest instrTest = new AndroidJUnitTest();
         instrTest.setDevice(device);
         instrTest.setInstallFile(apkFile);
@@ -134,7 +133,7 @@
         return success;
     }
 
-    public class TargetPreparerListener extends NoOpTestInvocationListener {
+    private class TargetPreparerListener implements ITestInvocationListener {
 
         @Override
         public void testEnded(TestIdentifier test, Map<String, String> metrics) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
index 08055a3..c35d1da 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
@@ -19,6 +19,7 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
 import com.android.compatibility.common.tradefed.util.CollectorUtil;
+import com.android.compatibility.common.util.DevicePropertyInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -40,30 +41,29 @@
  */
 public class DeviceInfoCollector extends ApkInstrumentationPreparer {
 
-    private static final Map<String, String> BUILD_KEYS = new HashMap<>();
-    static {
-        BUILD_KEYS.put("cts:build_id", "ro.build.id");
-        BUILD_KEYS.put("cts:build_product", "ro.product.name");
-        BUILD_KEYS.put("cts:build_device", "ro.product.device");
-        BUILD_KEYS.put("cts:build_board", "ro.product.board");
-        BUILD_KEYS.put("cts:build_manufacturer", "ro.product.manufacturer");
-        BUILD_KEYS.put("cts:build_brand", "ro.product.brand");
-        BUILD_KEYS.put("cts:build_model", "ro.product.model");
-        BUILD_KEYS.put("cts:build_type", "ro.build.type");
-        BUILD_KEYS.put("cts:build_tags", "ro.build.tags");
-        BUILD_KEYS.put("cts:build_fingerprint", "ro.build.fingerprint");
-        BUILD_KEYS.put("cts:build_abi", "ro.product.cpu.abi");
-        BUILD_KEYS.put("cts:build_abi2", "ro.product.cpu.abi2");
-        BUILD_KEYS.put("cts:build_abis", "ro.product.cpu.abilist");
-        BUILD_KEYS.put("cts:build_abis_32", "ro.product.cpu.abilist32");
-        BUILD_KEYS.put("cts:build_abis_64", "ro.product.cpu.abilist64");
-        BUILD_KEYS.put("cts:build_serial", "ro.serialno");
-        BUILD_KEYS.put("cts:build_version_release", "ro.build.version.release");
-        BUILD_KEYS.put("cts:build_version_sdk", "ro.build.version.sdk");
-        BUILD_KEYS.put("cts:build_version_base_os", "ro.build.version.base_os");
-        BUILD_KEYS.put("cts:build_version_security_patch", "ro.build.version.security_patch");
-        BUILD_KEYS.put("cts:build_reference_fingerprint", "ro.build.reference.fingerprint");
-    }
+    private static final String ABI = "ro.product.cpu.abi";
+    private static final String ABI2 = "ro.product.cpu.abi2";
+    private static final String ABIS = "ro.product.cpu.abilist";
+    private static final String ABIS_32 = "ro.product.cpu.abilist32";
+    private static final String ABIS_64 = "ro.product.cpu.abilist64";
+    private static final String BOARD = "ro.product.board";
+    private static final String BRAND = "ro.product.brand";
+    private static final String DEVICE = "ro.product.device";
+    private static final String FINGERPRINT = "ro.build.fingerprint";
+    private static final String ID = "ro.build.id";
+    private static final String MANUFACTURER = "ro.product.manufacturer";
+    private static final String MODEL = "ro.product.model";
+    private static final String PRODUCT = "ro.product.name";
+    private static final String REFERENCE_FINGERPRINT = "ro.build.reference.fingerprint";
+    private static final String SERIAL = "ro.serialno";
+    private static final String TAGS = "ro.build.tags";
+    private static final String TYPE = "ro.build.type";
+    private static final String VERSION_BASE_OS = "ro.build.version.base_os";
+    private static final String VERSION_RELEASE = "ro.build.version.release";
+    private static final String VERSION_SDK = "ro.build.version.sdk";
+    private static final String VERSION_SECURITY_PATCH = "ro.build.version.security_patch";
+
+    private static final String PREFIX_TAG = "cts:build_";
 
     @Option(name = CompatibilityTest.SKIP_DEVICE_INFO_OPTION,
             shortName = 'd',
@@ -92,7 +92,14 @@
     @Override
     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
             BuildError, DeviceNotAvailableException {
-        for (Entry<String, String> entry : BUILD_KEYS.entrySet()) {
+        DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(ABI, ABI2, ABIS, ABIS_32,
+                ABIS_64, BOARD, BRAND, DEVICE, FINGERPRINT, ID, MANUFACTURER, MODEL, PRODUCT,
+                REFERENCE_FINGERPRINT, SERIAL, TAGS, TYPE, VERSION_BASE_OS, VERSION_RELEASE,
+                VERSION_SDK, VERSION_SECURITY_PATCH);
+
+        // add device properties to the result with a prefix tag for each key
+        for (Entry<String, String> entry :
+                devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) {
             buildInfo.addBuildAttribute(entry.getKey(),
                     ArrayUtil.join(",", device.getProperty(entry.getValue())));
         }
@@ -112,7 +119,7 @@
             return;
         }
         if (mHostDir != null && mHostDir.isDirectory() &&
-                    mResultDir != null && mResultDir.isDirectory()) {
+                mResultDir != null && mResultDir.isDirectory()) {
             CollectorUtil.pullFromHost(mHostDir, mResultDir);
         }
     }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
index a422525..c1f2d4b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
@@ -87,8 +87,8 @@
         try {
             localConfigFile = DynamicConfig.getConfigFile(buildHelper.getTestsDir(), mModuleName);
         } catch (FileNotFoundException e) {
-            throw new TargetSetupError(
-                    "Cannot get local dynamic config file from test directory", e);
+            throw new TargetSetupError("Cannot get local dynamic config file from test directory",
+                    e, device.getDeviceDescriptor());
         }
 
         if (mVersion == null) {
@@ -119,7 +119,8 @@
             src = DynamicConfigHandler.getMergedDynamicConfigFile(
                     localConfigFile, apfeConfigInJson, mModuleName);
         } catch (IOException | XmlPullParserException | JSONException e) {
-            throw new TargetSetupError("Cannot get merged dynamic config file", e);
+            throw new TargetSetupError("Cannot get merged dynamic config file", e,
+                    device.getDeviceDescriptor());
         }
 
         switch (mTarget) {
@@ -128,7 +129,7 @@
                 if (!device.pushFile(src, deviceDest)) {
                     throw new TargetSetupError(String.format(
                             "Failed to push local '%s' to remote '%s'",
-                            src.getAbsolutePath(), deviceDest));
+                            src.getAbsolutePath(), deviceDest), device.getDeviceDescriptor());
                 } else {
                     mFilePushed = deviceDest;
                     buildHelper.addDynamicConfigFile(mModuleName, src);
@@ -145,7 +146,8 @@
                     FileUtil.copyFile(src, hostDest);
                 } catch (IOException e) {
                     throw new TargetSetupError(String.format("Failed to copy file from %s to %s",
-                            src.getAbsolutePath(), hostDest.getAbsolutePath()), e);
+                            src.getAbsolutePath(), hostDest.getAbsolutePath()), e,
+                            device.getDeviceDescriptor());
                 }
                 mFilePushed = hostDest.getAbsolutePath();
                 buildHelper.addDynamicConfigFile(mModuleName, src);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
index 94bc64f..548dd6f 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
@@ -16,7 +16,6 @@
 package com.android.compatibility.common.tradefed.targetprep;
 
 import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.Option;
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
index 79f19d0..192c095 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
@@ -41,8 +41,6 @@
             description = "Whether to throw an error for an unexpected property value")
     protected boolean mThrowError = false;
 
-    private static final String LOG_TAG = PropertyCheck.class.getSimpleName();
-
     @Override
     public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
             BuildError, DeviceNotAvailableException {
@@ -59,7 +57,7 @@
                     mExpectedPropertyValue, propertyValue, mPropertyName);
             // Handle unexpected property value with either exception or warning
             if(mThrowError) {
-                throw new TargetSetupError(msg);
+                throw new TargetSetupError(msg, device.getDeviceDescriptor());
             } else {
                 logWarning(msg);
             }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
index ccb9faf..7ea48c2 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
@@ -50,14 +50,10 @@
 
     @Override
     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
-        BuildError, DeviceNotAvailableException {
+            BuildError, DeviceNotAvailableException {
         prepareReportLogContainers(device, buildInfo);
     }
 
-    private void addBuildInfo(ITestDevice device, IBuildInfo buildInfo, String key, String value)
-        throws DeviceNotAvailableException {
-    }
-
     private void prepareReportLogContainers(ITestDevice device, IBuildInfo buildInfo) {
         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
         try {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
index d4c9d54..79151f5 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
@@ -20,6 +20,7 @@
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.TargetSetupError;
 
@@ -64,18 +65,18 @@
 
         if (mSettingName == null) {
             throw new TargetSetupError("The \"device-setting\" option must be defined for the " +
-                    "SettingsPreparer class");
+                    "SettingsPreparer class", device.getDeviceDescriptor());
         }
 
         if (mSettingType == null) {
             throw new TargetSetupError("The \"setting-type\" option must be defined for the " +
-                    "SettingsPreparer class");
+                    "SettingsPreparer class", device.getDeviceDescriptor());
         }
 
         /* At least one of the options "set-value" and "expected-values" must be set */
         if (mSetValue == null && mExpectedSettingValues.isEmpty()) {
             throw new TargetSetupError("At least one of the options \"set-value\" and " +
-                    "\"expected-values\" must be set");
+                    "\"expected-values\" must be set", device.getDeviceDescriptor());
         }
 
         String shellCmdGet = (!mExpectedSettingValues.isEmpty()) ?
@@ -90,12 +91,13 @@
             if (!mExpectedSettingValues.contains(mSetValue)) {
                 throw new TargetSetupError(String.format(
                         "set-value for %s is %s, but value not found in expected-values: %s",
-                        mSettingName, mSetValue, mExpectedSettingValues.toString()));
+                        mSettingName, mSetValue, mExpectedSettingValues.toString()),
+                        device.getDeviceDescriptor());
             }
             String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
             // only change unexpected setting value
             if (!mExpectedSettingValues.contains(currentSettingValue)) {
-                logInfo("Changing value for %s from %s to %s",
+                CLog.d("Changing value for %s from %s to %s",
                         mSettingName, currentSettingValue, mSetValue);
                 device.executeShellCommand(shellCmdPut);
             }
@@ -104,7 +106,7 @@
 
         /* Case 2: Only set-value given */
         if (mSetValue != null) {
-            logInfo("Setting %s to value %s", mSettingName, mSetValue);
+            CLog.d("Setting %s to value %s", mSettingName, mSetValue);
             device.executeShellCommand(shellCmdPut);
             return;
         }
@@ -117,7 +119,7 @@
                         "Device setting \"%s\" returned \"%s\", not found in %s",
                         mSettingName, currentSettingValue, mExpectedSettingValues.toString());
             }
-            throw new TargetSetupError(mFailureMessage);
+            throw new TargetSetupError(mFailureMessage, device.getDeviceDescriptor());
         }
     }
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
index d804146..ca9bdcf 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
@@ -22,8 +22,6 @@
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.TargetSetupError;
 
-import java.util.Arrays;
-
 /**
  * Modifies the 'Stay Awake' setting of the device, so that the device's screen stays on
  * whenever charging via USB
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SystemStatusChecker.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SystemStatusChecker.java
index 41ab510..45992ac 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SystemStatusChecker.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SystemStatusChecker.java
@@ -100,8 +100,7 @@
     }
 
     /**
-     * Returns failure message set by the failed system status check
-     * @return
+     * Returns failure message set by the failed system status check.
      */
     public String getFailureMessage() {
         return mFailureMessage;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
index 54b6bc0..102d9c8 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
@@ -45,7 +45,8 @@
     @Override
     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
             BuildError, DeviceNotAvailableException {
-        throw new TargetSetupError("TokenRequirement is not expected to run");
+        throw new TargetSetupError("TokenRequirement is not expected to run",
+                device.getDeviceDescriptor());
     }
 
     /**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
index cfc4d7c..5b53ba4 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
@@ -23,9 +23,6 @@
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.TargetSetupError;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * This preparer ensures that the device is connected to a network.
  * The options "wifi-ssid" and "wifi-psk" allow users of the preparer to attempt connection
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/CompatibilityHostTestBase.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java
new file mode 100644
index 0000000..b2e2a33
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBase.java
@@ -0,0 +1,238 @@
+/*
+ * 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.compatibility.common.tradefed.testtype;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.annotations.Nullable;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.util.AbiUtils;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.internal.AssumptionViolatedException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Compatibility host test base class for JUnit4 tests. Enables host-side tests written in JUnit4
+ * to access build and ABI information, as well as a reference to the testing device. The class
+ * includes methods to install and uninstall test packages, as well as methods to run device-side
+ * tests and retrieve their results.
+ */
+public class CompatibilityHostTestBase implements IAbiReceiver, IBuildReceiver, IDeviceTest {
+
+    protected static final String AJUR = "android.support.test.runner.AndroidJUnitRunner";
+
+    /** The build will be used. */
+    protected IBuildInfo mBuild;
+
+    /** The ABI to use. */
+    protected IAbi mAbi;
+
+    /** A reference to the device under test. */
+    protected ITestDevice mDevice;
+
+    /** The test runner used for test apps */
+    private String mRunner;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        // Get the build, this is used to access the APK.
+        mBuild = buildInfo;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    @Before
+    public void baseSetUp() throws Exception {
+        mRunner = AJUR;
+    }
+
+    /**
+     * Set the runner name
+     * @param runner of the device test runner
+     */
+    protected void setRunner(String runner) {
+        mRunner = runner;
+    }
+
+    /**
+     * Get the runner name
+     * @return name of the device test runner
+     */
+    protected String getRunner() {
+        return mRunner;
+    }
+
+    /**
+     * Installs a package on the device
+     * @param fileName the name of the file to install
+     * @param options optional extra arguments to pass. See 'adb shell pm install --help' for
+     * available options
+     * @throws FileNotFoundException if file with filename cannot be found
+     * @throws DeviceNotAvailableException
+     */
+    protected void installPackage(String fileName, String... options)
+            throws FileNotFoundException, DeviceNotAvailableException {
+
+        final List<String> optList = new ArrayList<>(Arrays.asList(options));
+        optList.add(AbiUtils.createAbiFlag(mAbi.getName()));
+        options = optList.toArray(new String[optList.size()]);
+
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        File testFile = new File(buildHelper.getTestsDir(), fileName);
+        // Install the APK on the device.
+        String installResult = mDevice.installPackage(testFile, true, options);
+
+        assertNull(String.format("Failed to install %s, Reason: %s", fileName, installResult),
+                installResult);
+    }
+
+    /**
+     * Uninstalls a package on the device
+     * @param pkgName the Android package to uninstall
+     * @return a {@link String} with an error code, or <code>null</code> if success
+     * @throws DeviceNotAvailableException
+     */
+    protected String uninstallPackage(String pkgName) throws DeviceNotAvailableException {
+        return mDevice.uninstallPackage(pkgName);
+    }
+
+    /**
+     * Checks if a package of a given name is installed on the device
+     * @param pkg the name of the package
+     * @return true if the package is found on the device
+     * @throws DeviceNotAvailableException
+     */
+    protected boolean isPackageInstalled(String pkg) throws DeviceNotAvailableException {
+        for (String installedPackage : mDevice.getInstalledPackageNames()) {
+            if (pkg.equals(installedPackage)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void printTestResult(TestRunResult runResult) {
+        for (Map.Entry<TestIdentifier, TestResult> testEntry :
+                     runResult.getTestResults().entrySet()) {
+            TestResult testResult = testEntry.getValue();
+            TestStatus testStatus = testResult.getStatus();
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Test " + testEntry.getKey() + ": " + testStatus);
+            if (testStatus != TestStatus.PASSED && testStatus != TestStatus.ASSUMPTION_FAILURE) {
+                CLog.logAndDisplay(LogLevel.WARN, testResult.getStackTrace());
+            }
+        }
+    }
+
+    /**
+     * Runs tests of a given package on the device and reports success.
+     * @param pkgName the name of the package containing tests
+     * @param testClassName the class from which tests should be collected. Tests are collected
+     * from all test classes in the package if null
+     * @return true if at least once test runs and there are no failures
+     * @throws AssertionError if device fails to run instrumentation tests
+     * @throws AssumptionViolatedException if each device test fails an assumption
+     * @throws DeviceNotAvailableException
+     */
+    protected boolean runDeviceTests(String pkgName, @Nullable String testClassName)
+            throws DeviceNotAvailableException {
+        return runDeviceTests(pkgName, testClassName, null /*testMethodName*/);
+    }
+
+    /**
+     * Runs tests of a given package on the device and reports success.
+     * @param pkgName the name of the package containing tests
+     * @param testClassName the class from which tests should be collected. Tests are collected
+     * from all test classes in the package if null
+     * @param testMethodName the test method to run. All tests from the class or package are run
+     * if null
+     * @return true if at least once test runs and there are no failures
+     * @throws AssertionError if device fails to run instrumentation tests
+     * @throws AssumptionViolatedException if each device test fails an assumption
+     * @throws DeviceNotAvailableException
+     */
+    protected boolean runDeviceTests(String pkgName, @Nullable String testClassName,
+            @Nullable String testMethodName)
+            throws DeviceNotAvailableException {
+        TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
+        printTestResult(runResult);
+        // assume not all tests have skipped (and rethrow AssumptionViolatedException if so)
+        Assume.assumeTrue(runResult.getNumTests() != runResult.getNumTestsInState(
+                TestStatus.ASSUMPTION_FAILURE));
+        return !runResult.hasFailedTests() && runResult.getNumTests() > 0;
+    }
+
+    /** Helper method to run tests and return the listener that collected the results. */
+    private TestRunResult doRunTests(
+        String pkgName, String testClassName,
+        String testMethodName) throws DeviceNotAvailableException {
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+            pkgName, mRunner, mDevice.getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        CollectingTestListener listener = new CollectingTestListener();
+        assertTrue(mDevice.runInstrumentationTests(testRunner, listener));
+        return listener.getCurrentRunResults();
+    }
+}
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 0397a42..f43249f 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
@@ -23,14 +23,9 @@
 import com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker;
 import com.android.compatibility.common.tradefed.targetprep.SystemStatusChecker;
 import com.android.compatibility.common.tradefed.util.OptionHelper;
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.compatibility.common.util.ICaseResult;
 import com.android.compatibility.common.util.IInvocationResult;
-import com.android.compatibility.common.util.IModuleResult;
-import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.ResultHandler;
 import com.android.compatibility.common.util.TestFilter;
-import com.android.compatibility.common.util.TestStatus;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ArgsOptionParser;
@@ -51,12 +46,15 @@
 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;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.IStrictShardableTest;
 import com.android.tradefed.util.AbiFormatter;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.ArrayUtil;
 import com.android.tradefed.util.TimeUtil;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
@@ -65,55 +63,48 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
  * A Test for running Compatibility Suites
  */
 @OptionClass(alias = "compatibility")
-public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver {
-
+public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver,
+        IStrictShardableTest {
     public static final String INCLUDE_FILTER_OPTION = "include-filter";
     public static final String EXCLUDE_FILTER_OPTION = "exclude-filter";
-    private static final String PLAN_OPTION = "plan";
-    private static final String SUBPLAN_OPTION = "subplan";
+    public static final String SUBPLAN_OPTION = "subplan";
     public static final String MODULE_OPTION = "module";
     public static final String TEST_OPTION = "test";
-    private static final String MODULE_ARG_OPTION = "module-arg";
-    private static final String TEST_ARG_OPTION = "test-arg";
+    public static final String MODULE_ARG_OPTION = "module-arg";
+    public static final String TEST_ARG_OPTION = "test-arg";
     public static final String RETRY_OPTION = "retry";
     public static final String RETRY_TYPE_OPTION = "retry-type";
     public static final String ABI_OPTION = "abi";
-    private static final String SHARD_OPTION = "shards";
+    public static final String SHARD_OPTION = "shards";
     public static final String SKIP_DEVICE_INFO_OPTION = "skip-device-info";
     public static final String SKIP_PRECONDITIONS_OPTION = "skip-preconditions";
+    public static final String SKIP_HOST_ARCH_CHECK = "skip-host-arch-check";
     public static final String PRIMARY_ABI_RUN = "primary-abi-only";
     public static final String DEVICE_TOKEN_OPTION = "device-token";
     public static final String LOGCAT_ON_FAILURE_SIZE_OPTION = "logcat-on-failure-size";
-    private static final String URL = "dynamic-config-url";
 
     // Constants for checking invocation or preconditions preparation failure
     private static final int NUM_PREP_ATTEMPTS = 10;
     private static final int MINUTES_PER_PREP_ATTEMPT = 2;
 
-    /* API Key for compatibility test project, used for dynamic configuration */
-    private static final String API_KEY = "AIzaSyAbwX5JRlmsLeygY2WWihpIJPXFLueOQ3U";
-
-
-    @Option(name = PLAN_OPTION,
-            description = "the test suite plan to run, such as \"everything\" or \"cts\"",
-            importance = Importance.ALWAYS)
-    private String mSuitePlan;
-
     @Option(name = SUBPLAN_OPTION,
             description = "the subplan to run",
             importance = Importance.IF_UNSET)
@@ -179,16 +170,15 @@
             description = "split the modules up to run on multiple devices concurrently.")
     private int mShards = 1;
 
-    @Option(name = URL,
-            description = "Specify the url for override config")
-    private String mURL = "https://androidpartner.googleapis.com/v1/dynamicconfig/"
-            + "suites/{suite-name}/modules/{module}/version/{version}?key=" + API_KEY;
-
     @Option(name = SKIP_DEVICE_INFO_OPTION,
             shortName = 'd',
             description = "Whether device info collection should be skipped")
     private boolean mSkipDeviceInfo = false;
 
+    @Option(name = SKIP_HOST_ARCH_CHECK,
+            description = "Whether host architecture check should be skipped")
+    private boolean mSkipHostArchCheck = false;
+
     @Option(name = SKIP_PRECONDITIONS_OPTION,
             shortName = 'o',
             description = "Whether preconditions should be skipped")
@@ -269,29 +259,35 @@
     private String mSystemStatusCheckerConfig = "system-status-checkers";
 
     private int mTotalShards;
+    private Integer mShardIndex = null;
     private IModuleRepo mModuleRepo;
     private ITestDevice mDevice;
     private CompatibilityBuildHelper mBuildHelper;
 
+    // variables used for local sharding scenario
+    private static CountDownLatch sPreparedLatch;
+    private boolean mIsLocalSharding = false;
+
     /**
      * Create a new {@link CompatibilityTest} that will run the default list of
      * modules.
      */
     public CompatibilityTest() {
-        this(1 /* totalShards */, new ModuleRepo());
+        this(1 /* totalShards */, new ModuleRepo(), 0);
     }
 
     /**
      * Create a new {@link CompatibilityTest} that will run a sublist of
      * modules.
      */
-    public CompatibilityTest(int totalShards, IModuleRepo moduleRepo) {
+    public CompatibilityTest(int totalShards, IModuleRepo moduleRepo, Integer shardIndex) {
         if (totalShards < 1) {
             throw new IllegalArgumentException(
                     "Must be at least 1 shard. Given:" + totalShards);
         }
         mTotalShards = totalShards;
         mModuleRepo = moduleRepo;
+        mShardIndex = shardIndex;
     }
 
     /**
@@ -316,11 +312,6 @@
     @Override
     public void setBuild(IBuildInfo buildInfo) {
         mBuildHelper = new CompatibilityBuildHelper(buildInfo);
-        // Initializing the mBuildHelper also updates properties in buildInfo.
-        // TODO(nicksauer): Keeping invocation properties around via buildInfo
-        // is confusing and would be better done in an "InvocationInfo".
-        // Note, the current time is used to generated the result directory.
-        mBuildHelper.init(mSuitePlan, mURL, System.currentTimeMillis());
     }
 
     /**
@@ -329,24 +320,26 @@
     @Override
     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
         try {
-            // Synchronized so only one shard enters and sets up the moduleRepo. When the other
-            // shards enter after this, moduleRepo is already initialized so they dont do anything
+            // FIXME: Each shard will do a full initialization which is not optimal. Need a way
+            // to be more specific on what to initialize.
+            List<IModuleDef> modules;
             synchronized (mModuleRepo) {
                 if (!mModuleRepo.isInitialized()) {
                     setupFilters();
                     // Initialize the repository, {@link CompatibilityBuildHelper#getTestsDir} can
                     // throw a {@link FileNotFoundException}
-                    mModuleRepo.initialize(mTotalShards, mBuildHelper.getTestsDir(), getAbis(),
-                            mDeviceTokens, mTestArgs, mModuleArgs, mIncludeFilters,
+                    mModuleRepo.initialize(mTotalShards, mShardIndex, mBuildHelper.getTestsDir(),
+                            getAbis(), mDeviceTokens, mTestArgs, mModuleArgs, mIncludeFilters,
                             mExcludeFilters, mBuildHelper.getBuildInfo());
 
                     // Add the entire list of modules to the CompatibilityBuildHelper for reporting
                     mBuildHelper.setModuleIds(mModuleRepo.getModuleIds());
+                } else {
+                    CLog.d("ModuleRepo already initialized.");
                 }
-
+                // Get the tests to run in this shard
+                modules = mModuleRepo.getModules(getDevice().getSerialNumber(), mShardIndex);
             }
-            // Get the tests to run in this shard
-            List<IModuleDef> modules = mModuleRepo.getModules(getDevice().getSerialNumber());
 
             listener = new FailureListener(listener, getDevice(), mBugReportOnFailure,
                     mLogcatOnFailure, mScreenshotOnFailure, mRebootOnFailure, mMaxLogcatBytes);
@@ -384,26 +377,32 @@
                 module.setPreparerWhitelist(mPreparerWhitelist);
                 isPrepared &= (module.prepare(mSkipPreconditions));
             }
-            mModuleRepo.setPrepared(isPrepared);
-
-            int prepAttempt = 1;
-            while (!mModuleRepo.isPrepared(MINUTES_PER_PREP_ATTEMPT, TimeUnit.MINUTES)) {
-                if (prepAttempt >= NUM_PREP_ATTEMPTS
-                        || InvocationFailureHandler.hasFailed(mBuildHelper)) {
-                    CLog.logAndDisplay(LogLevel.ERROR,
-                            "Incorrect preparation detected, exiting test run from %s",
-                            mDevice.getSerialNumber());
-                    return;
-                } else {
-                    CLog.logAndDisplay(LogLevel.INFO,
-                            "Device %s on standby while all shards complete preparation",
-                            mDevice.getSerialNumber());
-                }
-                prepAttempt++;
+            if (!isPrepared) {
+                throw new RuntimeException(String.format("Failed preconditions on %s",
+                        mDevice.getSerialNumber()));
             }
-
+            if (mIsLocalSharding) {
+                try {
+                    sPreparedLatch.countDown();
+                    int attempt = 1;
+                    while(!sPreparedLatch.await(MINUTES_PER_PREP_ATTEMPT, TimeUnit.MINUTES)) {
+                        if (attempt > NUM_PREP_ATTEMPTS ||
+                                InvocationFailureHandler.hasFailed(mBuildHelper)) {
+                            CLog.logAndDisplay(LogLevel.ERROR,
+                                    "Incorrect preparation detected, exiting test run from %s",
+                                    mDevice.getSerialNumber());
+                            return;
+                        }
+                        CLog.logAndDisplay(LogLevel.WARN, "waiting on preconditions");
+                        attempt++;
+                    }
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
             // Run the tests
             for (int i = 0; i < moduleCount; i++) {
+
                 IModuleDef module = modules.get(i);
                 long start = System.currentTimeMillis();
 
@@ -423,6 +422,9 @@
                     runPreModuleCheck(module.getName(), checkers, mDevice, listener);
                 }
                 try {
+                    if (module.getTest() instanceof IBuildReceiver) {
+                        ((IBuildReceiver)module.getTest()).setBuild(mBuildHelper.getBuildInfo());
+                    }
                     module.run(listener);
                 } catch (DeviceUnresponsiveException due) {
                     // being able to catch a DeviceUnresponsiveException here implies that recovery
@@ -467,8 +469,8 @@
      * @throws DeviceNotAvailableException
      */
     Set<IAbi> getAbis() throws DeviceNotAvailableException {
-        Set<IAbi> abis = new HashSet<>();
-        Set<String> archAbis = AbiUtils.getAbisForArch(SuiteInfo.TARGET_ARCH);
+        Set<IAbi> abis = new LinkedHashSet<>();
+        Set<String> archAbis = getAbisForBuildTargetArch();
         if (mPrimaryAbiRun) {
             if (mAbiName == null) {
                 // Get the primary from the device and make it the --abi to run.
@@ -478,23 +480,44 @@
                         PRIMARY_ABI_RUN, mAbiName);
             }
         }
-        for (String abi : AbiFormatter.getSupportedAbis(mDevice, "")) {
-            // Only test against ABIs supported by Compatibility, and if the
-            // --abi option was given, it must match.
-            if (AbiUtils.isAbiSupportedByCompatibility(abi) && archAbis.contains(abi)
-                    && (mAbiName == null || mAbiName.equals(abi))) {
-                abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
-            }
-        }
-        if (abis.isEmpty()) {
-            if (mAbiName == null) {
-                throw new IllegalArgumentException("Could not get device's ABIs");
+        if (mAbiName != null) {
+            // A particular abi was requested, it still need to be supported by the build.
+            if ((!mSkipHostArchCheck && !archAbis.contains(mAbiName)) ||
+                    !AbiUtils.isAbiSupportedByCompatibility(mAbiName)) {
+                throw new IllegalArgumentException(String.format("Your CTS hasn't been built with "
+                        + "abi '%s' support, this CTS currently supports '%s'.",
+                        mAbiName, archAbis));
             } else {
-                throw new IllegalArgumentException(String.format(
-                        "Device %s doesn't support %s", mDevice.getSerialNumber(), mAbiName));
+                abis.add(new Abi(mAbiName, AbiUtils.getBitness(mAbiName)));
+                return abis;
             }
+        } else {
+            // Run on all abi in common between the device and CTS.
+            List<String> deviceAbis = Arrays.asList(AbiFormatter.getSupportedAbis(mDevice, ""));
+            for (String abi : deviceAbis) {
+                if ((mSkipHostArchCheck || archAbis.contains(abi)) &&
+                        AbiUtils.isAbiSupportedByCompatibility(abi)) {
+                    abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
+                } else {
+                    CLog.d("abi '%s' is supported by device but not by this CTS build (%s), tests "
+                            + "will not run against it.", abi, archAbis);
+                }
+            }
+            if (abis.isEmpty()) {
+                throw new IllegalArgumentException(String.format("None of the abi supported by this"
+                       + " CTS build ('%s') are supported by the device ('%s').",
+                       archAbis, deviceAbis));
+            }
+            return abis;
         }
-        return abis;
+    }
+
+    /**
+     * Return the abis supported by the Host build target architecture.
+     * Exposed for testing.
+     */
+    protected Set<String> getAbisForBuildTargetArch() {
+        return AbiUtils.getAbisForArch(SuiteInfo.TARGET_ARCH);
     }
 
     private List<SystemStatusChecker> initSystemStatusCheckers() throws ConfigurationException {
@@ -526,7 +549,7 @@
      * Resolve the inclusion and exclusion logic of system status checkers
      *
      * @param s the {@link SystemStatusChecker} to perform filtering logic on
-     * @return
+     * @return True if the {@link SystemStatusChecker} should be included, false otherwise.
      */
     private boolean shouldIncludeSystemStatusChecker(SystemStatusChecker s) {
         String clazz = s.getClass().getCanonicalName();
@@ -716,18 +739,27 @@
         if (mShards <= 1) {
             return null;
         }
-
+        mIsLocalSharding = true;
         List<IRemoteTest> shardQueue = new LinkedList<>();
         for (int i = 0; i < mShards; i++) {
-            CompatibilityTest test = new CompatibilityTest(mShards, mModuleRepo);
-            OptionCopier.copyOptionsNoThrow(this, test);
-            // Set the shard count because the copy option on the previous line
-            // copies over the mShard value
-            test.mShards = 0;
+            CompatibilityTest test = (CompatibilityTest) getTestShard(mShards, i);
+            test.mIsLocalSharding = true;
             shardQueue.add(test);
         }
-
+        sPreparedLatch = new CountDownLatch(shardQueue.size());
         return shardQueue;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IRemoteTest getTestShard(int shardCount, int shardIndex) {
+        CompatibilityTest test = new CompatibilityTest(shardCount, mModuleRepo, shardIndex);
+        OptionCopier.copyOptionsNoThrow(this, test);
+        // Set the shard count because the copy option on the previous line
+        // copies over the mShard value
+        test.mShards = 0;
+        return test;
+    }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java
index cd0e54f..758be95 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/FailureListener.java
@@ -68,6 +68,18 @@
     public void testFailed(TestIdentifier test, String trace) {
         super.testFailed(test, trace);
         CLog.i("FailureListener.testFailed %s %b %b %b", test.toString(), mBugReportOnFailure, mLogcatOnFailure, mScreenshotOnFailure);
+        if (mScreenshotOnFailure) {
+            try {
+                InputStreamSource screenSource = mDevice.getScreenshot();
+                super.testLog(String.format("%s-screenshot", test.toString()), LogDataType.PNG,
+                    screenSource);
+                screenSource.cancel();
+            } catch (DeviceNotAvailableException e) {
+                CLog.e(e);
+                CLog.e("Device %s became unavailable while capturing screenshot",
+                    mDevice.getSerialNumber());
+            }
+        }
         if (mBugReportOnFailure) {
            InputStreamSource bugSource = mDevice.getBugreport();
            super.testLog(String.format("%s-bugreport", test.toString()), LogDataType.BUGREPORT,
@@ -82,18 +94,6 @@
                     logSource);
             logSource.cancel();
         }
-        if (mScreenshotOnFailure) {
-            try {
-                InputStreamSource screenSource = mDevice.getScreenshot();
-                super.testLog(String.format("%s-screenshot", test.toString()), LogDataType.PNG,
-                        screenSource);
-                screenSource.cancel();
-            } catch (DeviceNotAvailableException e) {
-                CLog.e(e);
-                CLog.e("Device %s became unavailable while capturing screenshot",
-                        mDevice.getSerialNumber());
-            }
-        }
         if (mRebootOnFailure) {
             try {
                 // Rebooting on all failures can hide legitimate issues and platform instabilities,
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
index 931f2d2..e7a7039 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -22,7 +22,6 @@
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IRuntimeHintProvider;
 
-import java.io.File;
 import java.util.Set;
 
 /**
@@ -60,7 +59,7 @@
      * Set a list of preparers to allow to run before or after a test.
      * If this list is empty, then all configured preparers will run.
      *
-     * @param a list containing the simple name of the preparer to run.
+     * @param preparerWhitelist list containing the simple name of the preparer to run.
      */
     void setPreparerWhitelist(Set<String> preparerWhitelist);
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
index e689a99..1f6a53e 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
@@ -22,7 +22,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Interface for accessing tests from the Compatibility repository.
@@ -30,16 +29,6 @@
 public interface IModuleRepo {
 
     /**
-     * @return true after each shard has prepared successfully.
-     */
-    boolean isPrepared(long timeout, TimeUnit unit);
-
-    /**
-     * Indicates to the repo whether a shard is prepared to run.
-     */
-    void setPrepared(boolean isPrepared);
-
-    /**
      * @return true if this repository has been initialized.
      */
     boolean isInitialized();
@@ -47,14 +36,14 @@
     /**
      * Initializes the repository.
      */
-    void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
-            List<String> testArgs, List<String> moduleArgs, Set<String> mIncludeFilters,
-            Set<String> mExcludeFilters, IBuildInfo buildInfo);
+    void initialize(int shards, Integer shardIndex, File testsDir, Set<IAbi> abis,
+            List<String> deviceTokens, List<String> testArgs, List<String> moduleArgs,
+            Set<String> mIncludeFilters, Set<String> mExcludeFilters, IBuildInfo buildInfo);
 
     /**
      * @return a {@link Map} of all modules to run on the device referenced by the given serial.
      */
-    List<IModuleDef> getModules(String serial);
+    List<IModuleDef> getModules(String serial, int shardIndex);
 
     /**
      * @return the number of shards this repo is initialized for.
@@ -62,34 +51,9 @@
     int getNumberOfShards();
 
     /**
-     * @return the maximum number of modules a shard will run.
+     * @return the modules which do not have token and have not been assigned to a device.
      */
-    int getModulesPerShard();
-
-    /**
-     * @return the {@link Map} of device serials to tokens.
-     */
-    Map<String, Set<String>> getDeviceTokens();
-
-    /**
-     * @return the {@link Set} of device serials that have taken their workload.
-     */
-    Set<String> getSerials();
-
-    /**
-     * @return the small modules that don't have tokens but have not been assigned to a device.
-     */
-    List<IModuleDef> getSmallModules();
-
-    /**
-     * @return the medium modules that don't have tokens but have not been assigned to a device.
-     */
-    List<IModuleDef> getMediumModules();
-
-    /**
-     * @return the large modules that don't have tokens but have not been assigned to a device.
-     */
-    List<IModuleDef> getLargeModules();
+    List<IModuleDef> getNonTokenModules();
 
     /**
      * @return the modules which have token and have not been assigned to a device.
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
index ba4c6c3..e683de2 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
@@ -19,13 +19,17 @@
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionCopier;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.ResultForwarder;
 import com.android.tradefed.testtype.HostTest;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IRuntimeHintProvider;
-import com.android.tradefed.util.TimeVal;
+import com.android.tradefed.util.StreamUtil;
+
+import com.google.common.annotations.VisibleForTesting;
 
 import junit.framework.Test;
 
@@ -34,9 +38,11 @@
 import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
@@ -44,8 +50,7 @@
 /**
  * Test runner for host-side JUnit tests.
  */
-public class JarHostTest extends HostTest implements IAbiReceiver, IBuildReceiver,
-        IRuntimeHintProvider {
+public class JarHostTest extends HostTest implements IRuntimeHintProvider {
 
     @Option(name="jar", description="The jars containing the JUnit test class to run.",
             importance = Importance.IF_UNSET)
@@ -56,27 +61,6 @@
             description="The hint about the test's runtime.")
     private long mRuntimeHint = 60000;// 1 minute
 
-    private IAbi mAbi;
-    private IBuildInfo mBuild;
-    private CompatibilityBuildHelper mHelper;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setBuild(IBuildInfo build) {
-        mBuild = build;
-        mHelper = new CompatibilityBuildHelper(build);
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -89,12 +73,32 @@
      * {@inheritDoc}
      */
     @Override
+    protected HostTest createHostTest(Class<?> classObj) {
+        JarHostTest test = new JarHostTest();
+        OptionCopier.copyOptionsNoThrow(this, test);
+        test.setClassName(classObj.getName());
+        return test;
+    }
+
+    /**
+     * Create a {@link CompatibilityBuildHelper} from the build info provided.
+     */
+    @VisibleForTesting
+    CompatibilityBuildHelper createBuildHelper(IBuildInfo info) {
+        return new CompatibilityBuildHelper(info);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     protected List<Class<?>> getClasses() throws IllegalArgumentException  {
         List<Class<?>> classes = super.getClasses();
+        CompatibilityBuildHelper helper = createBuildHelper(getBuild());
         for (String jarName : mJars) {
             JarFile jarFile = null;
             try {
-                File file = new File(mHelper.getTestsDir(), jarName);
+                File file = new File(helper.getTestsDir(), jarName);
                 jarFile = new JarFile(file);
                 Enumeration<JarEntry> e = jarFile.entries();
                 URL[] urls = {
@@ -113,7 +117,8 @@
                         Class<?> cls = cl.loadClass(className);
                         int modifiers = cls.getModifiers();
                         if ((IRemoteTest.class.isAssignableFrom(cls)
-                                || Test.class.isAssignableFrom(cls))
+                                || Test.class.isAssignableFrom(cls)
+                                || hasJUnit4Annotation(cls))
                                 && !Modifier.isStatic(modifiers)
                                 && !Modifier.isPrivate(modifiers)
                                 && !Modifier.isProtected(modifiers)
@@ -127,15 +132,10 @@
                     }
                 }
             } catch (IOException e) {
-                e.printStackTrace();
+                CLog.e(e);
+                throw new RuntimeException(e);
             } finally {
-                if (jarFile != null) {
-                    try {
-                        jarFile.close();
-                    } catch (IOException e) {
-                        // Ignored
-                    }
-                }
+                StreamUtil.close(jarFile);
             }
         }
         return classes;
@@ -150,14 +150,39 @@
      * {@inheritDoc}
      */
     @Override
-    protected Object loadObject(Class<?> classObj) throws IllegalArgumentException {
-        Object object = super.loadObject(classObj);
-        if (object instanceof IAbiReceiver) {
-            ((IAbiReceiver) object).setAbi(mAbi);
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        int numTests = countTestCases();
+        long startTime = System.currentTimeMillis();
+        listener.testRunStarted(getClass().getName(), numTests);
+        super.run(new HostTestListener(listener));
+        listener.testRunEnded(System.currentTimeMillis() - startTime, Collections.emptyMap());
+    }
+
+    /**
+     * Wrapper listener that forwards all events except testRunStarted() and testRunEnded() to
+     * the embedded listener. Each test class in the jar will invoke these events, which
+     * HostTestListener withholds from listeners for console logging and result reporting.
+     */
+    public class HostTestListener extends ResultForwarder {
+
+        public HostTestListener(ITestInvocationListener listener) {
+            super(listener);
         }
-        if (object instanceof IBuildReceiver) {
-            ((IBuildReceiver) object).setBuild(mBuild);
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void testRunStarted(String name, int numTests) {
+            CLog.d("HostTestListener.testRunStarted(%s, %d)", name, numTests);
         }
-        return object;
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
+            CLog.d("HostTestListener.testRunEnded(%d, %s)", elapsedTime, metrics.toString());
+        }
     }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
index 4678909..035b9ea 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -20,7 +20,6 @@
 import com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher;
 import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
 import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
-import com.android.compatibility.common.util.AbiUtils;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ConfigurationException;
 import com.android.tradefed.config.OptionSetter;
@@ -40,8 +39,8 @@
 import com.android.tradefed.testtype.IRuntimeHintProvider;
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -220,6 +219,8 @@
     @Override
     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
         IModuleListener moduleListener = new ModuleListener(this, listener);
+
+        CLog.d("Running module %s", toString());
         // Run DynamicConfigPusher setup once more, in case cleaner has previously
         // removed dynamic config file from the target (see b/32877809)
         for (ITargetPreparer preparer : mDynamicConfigPreparers) {
@@ -302,7 +303,7 @@
             OptionSetter setter = new OptionSetter(target);
             setter.setOptionValue(option, value);
         } catch (ConfigurationException e) {
-            e.printStackTrace();
+            CLog.e(e);
         }
     }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index a2287d4..c7b6999 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -15,9 +15,8 @@
  */
 package com.android.compatibility.common.tradefed.testtype;
 
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.tradefed.util.LinearPartition;
 import com.android.compatibility.common.util.TestFilter;
-import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ConfigurationException;
 import com.android.tradefed.config.ConfigurationFactory;
@@ -27,9 +26,10 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IRemoteTest;
-import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.IStrictShardableTest;
 import com.android.tradefed.testtype.ITestFileFilterReceiver;
 import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.TimeUtil;
 
@@ -47,8 +47,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Retrieves Compatibility test module definitions from the repository.
@@ -60,60 +58,40 @@
     static {
         ENDING_MODULES.put("CtsMonkeyTestCases", 1);
     }
-    private static final long SMALL_TEST = TimeUnit.MINUTES.toMillis(2); // Small tests < 2mins
-    private static final long MEDIUM_TEST = TimeUnit.MINUTES.toMillis(10); // Medium tests < 10mins
+    // Synchronization objects for Token Modules.
+    private static int mInitCount = 0;
+    private static Set<IModuleDef> mTokenModuleScheduled;
+    private static Object lock = new Object();
 
-    private int mShards;
-    private int mModulesPerShard;
-    private int mSmallModulesPerShard;
-    private int mMediumModulesPerShard;
-    private int mLargeModulesPerShard;
-    private int mModuleCount = 0;
-    private Set<String> mSerials = new HashSet<>();
+    private int mTotalShards;
+    private Integer mShardIndex;
+
     private Map<String, Set<String>> mDeviceTokens = new HashMap<>();
-    private Map<String, Map<String, String>> mTestArgs = new HashMap<>();
-    private Map<String, Map<String, String>> mModuleArgs = new HashMap<>();
+    private Map<String, Map<String, List<String>>> mTestArgs = new HashMap<>();
+    private Map<String, Map<String, List<String>>> mModuleArgs = new HashMap<>();
     private boolean mIncludeAll;
     private Map<String, List<TestFilter>> mIncludeFilters = new HashMap<>();
     private Map<String, List<TestFilter>> mExcludeFilters = new HashMap<>();
     private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();
 
     private volatile boolean mInitialized = false;
-    // Whether the modules in this repo are ready to run on their assigned devices.
-    // True until explicitly set false in setPrepared().
-    private volatile boolean mPrepared = true;
-    private CountDownLatch mPreparedLatch;
 
-    // Holds all the small tests waiting to be run.
-    private List<IModuleDef> mSmallModules = new ArrayList<>();
-    // Holds all the medium tests waiting to be run.
-    private List<IModuleDef> mMediumModules = new ArrayList<>();
-    // Holds all the large tests waiting to be run.
-    private List<IModuleDef> mLargeModules = new ArrayList<>();
     // Holds all the tests with tokens waiting to be run. Meaning the DUT must have a specific token.
     private List<IModuleDef> mTokenModules = new ArrayList<>();
+    private List<IModuleDef> mNonTokenModules = new ArrayList<>();
 
     /**
      * {@inheritDoc}
      */
     @Override
     public int getNumberOfShards() {
-        return mShards;
+        return mTotalShards;
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the device tokens of this module repo. Exposed for testing.
      */
-    @Override
-    public int getModulesPerShard() {
-        return mModulesPerShard;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Map<String, Set<String>> getDeviceTokens() {
+    protected Map<String, Set<String>> getDeviceTokens() {
         return mDeviceTokens;
     }
 
@@ -141,32 +119,8 @@
      * {@inheritDoc}
      */
     @Override
-    public Set<String> getSerials() {
-        return mSerials;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<IModuleDef> getSmallModules() {
-        return mSmallModules;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<IModuleDef> getMediumModules() {
-        return mMediumModules;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<IModuleDef> getLargeModules() {
-        return mLargeModules;
+    public List<IModuleDef> getNonTokenModules() {
+        return mNonTokenModules;
     }
 
     /**
@@ -183,13 +137,7 @@
     @Override
     public String[] getModuleIds() {
         Set<String> moduleIdSet = new HashSet<>();
-        for (IModuleDef moduleDef : mSmallModules) {
-            moduleIdSet.add(moduleDef.getId());
-        }
-        for (IModuleDef moduleDef : mMediumModules) {
-            moduleIdSet.add(moduleDef.getId());
-        }
-        for (IModuleDef moduleDef : mLargeModules) {
+        for (IModuleDef moduleDef : mNonTokenModules) {
             moduleIdSet.add(moduleDef.getId());
         }
         for (IModuleDef moduleDef : mTokenModules) {
@@ -202,28 +150,6 @@
      * {@inheritDoc}
      */
     @Override
-    public boolean isPrepared(long timeout, TimeUnit unit) {
-        // returns true only if CountDownLatch reaches zero && no shards have setPrepared to false
-        try {
-            return (mPreparedLatch.await(timeout, unit)) ? mPrepared : false;
-        } catch (InterruptedException e) {
-            return false;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setPrepared(boolean isPrepared) {
-        mPrepared &= isPrepared;
-        mPreparedLatch.countDown();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public boolean isInitialized() {
         return mInitialized;
     }
@@ -232,16 +158,23 @@
      * {@inheritDoc}
      */
     @Override
-    public void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
-            List<String> testArgs, List<String> moduleArgs, Set<String> includeFilters,
-            Set<String> excludeFilters, IBuildInfo buildInfo) {
+    public void initialize(int totalShards, Integer shardIndex, File testsDir, Set<IAbi> abis,
+            List<String> deviceTokens, List<String> testArgs, List<String> moduleArgs,
+            Set<String> includeFilters, Set<String> excludeFilters, IBuildInfo buildInfo) {
         CLog.d("Initializing ModuleRepo\nShards:%d\nTests Dir:%s\nABIs:%s\nDevice Tokens:%s\n" +
                 "Test Args:%s\nModule Args:%s\nIncludes:%s\nExcludes:%s",
-                shards, testsDir.getAbsolutePath(), abis, deviceTokens, testArgs, moduleArgs,
+                totalShards, testsDir.getAbsolutePath(), abis, deviceTokens, testArgs, moduleArgs,
                 includeFilters, excludeFilters);
         mInitialized = true;
-        mShards = shards;
-        mPreparedLatch = new CountDownLatch(shards);
+        mTotalShards = totalShards;
+        mShardIndex = shardIndex;
+        synchronized (lock) {
+            mInitCount++;
+            if (mTokenModuleScheduled == null) {
+                mTokenModuleScheduled = new HashSet<>();
+            }
+        }
+
         for (String line : deviceTokens) {
             String[] parts = line.split(":");
             if (parts.length == 2) {
@@ -287,7 +220,7 @@
                         continue;
                     }
                     {
-                        Map<String, String> args = new HashMap<>();
+                        Map<String, List<String>> args = new HashMap<>();
                         if (mModuleArgs.containsKey(name)) {
                             args.putAll(mModuleArgs.get(name));
                         }
@@ -295,33 +228,35 @@
                             args.putAll(mModuleArgs.get(id));
                         }
                         if (args != null && args.size() > 0) {
-                            for (Entry<String, String> entry : args.entrySet()) {
-                                config.injectOptionValue(entry.getKey(), entry.getValue());
+                            for (Entry<String, List<String>> entry : args.entrySet()) {
+                                for (String value : entry.getValue()) {
+                                    // Collection-type options can be injected with multiple values
+                                    config.injectOptionValue(entry.getKey(), value);
+                                }
                             }
                         }
                     }
                     List<IRemoteTest> tests = config.getTests();
                     for (IRemoteTest test : tests) {
                         String className = test.getClass().getName();
-                        Map<String, String> args = new HashMap<>();
+                        Map<String, List<String>> args = new HashMap<>();
                         if (mTestArgs.containsKey(className)) {
                             args.putAll(mTestArgs.get(className));
                         }
                         if (args != null && args.size() > 0) {
-                            for (Entry<String, String> entry : args.entrySet()) {
-                                config.injectOptionValue(entry.getKey(), entry.getValue());
+                            for (Entry<String, List<String>> entry : args.entrySet()) {
+                                for (String value : entry.getValue()) {
+                                    config.injectOptionValue(entry.getKey(), value);
+                                }
                             }
                         }
                         addFiltersToTest(test, abi, name);
                     }
                     List<IRemoteTest> shardedTests = tests;
-                    if (mShards > 1) {
+                    if (mTotalShards > 1) {
                          shardedTests = splitShardableTests(tests, buildInfo);
                     }
                     for (IRemoteTest test : shardedTests) {
-                        if (test instanceof IBuildReceiver) {
-                            ((IBuildReceiver)test).setBuild(buildInfo);
-                        }
                         addModuleDef(name, abi, test, pathArg);
                     }
                 }
@@ -330,24 +265,18 @@
                         configFile.getName()), e);
             }
         }
-        mModulesPerShard = mModuleCount / shards;
-        if (mModuleCount % shards != 0) {
-            mModulesPerShard++; // Round up
-        }
-        mSmallModulesPerShard = mSmallModules.size() / shards;
-        mMediumModulesPerShard = mMediumModules.size() / shards;
-        mLargeModulesPerShard = mLargeModules.size() / shards;
     }
 
-    private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests,
-            IBuildInfo buildInfo) {
+    private List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests, IBuildInfo buildInfo) {
         ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
         for (IRemoteTest test : tests) {
-            if (test instanceof IShardableTest) {
-                if (test instanceof IBuildReceiver) {
-                    ((IBuildReceiver)test).setBuild(buildInfo);
+            if (test instanceof IBuildReceiver) {
+                ((IBuildReceiver)test).setBuild(buildInfo);
+            }
+            if (mShardIndex != null && test instanceof IStrictShardableTest) {
+                for (int i = 0; i < mTotalShards; i++) {
+                    shardedList.add(((IStrictShardableTest)test).getTestShard(mTotalShards, i));
                 }
-                shardedList.addAll(((IShardableTest)test).split());
             } else {
                 shardedList.add(test);
             }
@@ -355,7 +284,7 @@
         return shardedList;
     }
 
-    private static void addFilters(Set<String> stringFilters,
+    private void addFilters(Set<String> stringFilters,
             Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
         for (String filterString : stringFilters) {
             TestFilter filter = TestFilter.createFrom(filterString);
@@ -370,12 +299,12 @@
         }
     }
 
-    private static void addFilter(String abi, TestFilter filter,
+    private void addFilter(String abi, TestFilter filter,
             Map<String, List<TestFilter>> filters) {
         getFilter(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
     }
 
-    private static List<TestFilter> getFilter(Map<String, List<TestFilter>> filters, String id) {
+    private List<TestFilter> getFilter(Map<String, List<TestFilter>> filters, String id) {
         List<TestFilter> fs = filters.get(id);
         if (fs == null) {
             fs = new ArrayList<>();
@@ -395,14 +324,9 @@
         Set<String> tokens = moduleDef.getTokens();
         if (tokens != null && !tokens.isEmpty()) {
             mTokenModules.add(moduleDef);
-        } else if (moduleDef.getRuntimeHint() < SMALL_TEST) {
-            mSmallModules.add(moduleDef);
-        } else if (moduleDef.getRuntimeHint() < MEDIUM_TEST) {
-            mMediumModules.add(moduleDef);
         } else {
-            mLargeModules.add(moduleDef);
+            mNonTokenModules.add(moduleDef);
         }
-        mModuleCount++;
     }
 
     private void addFiltersToTest(IRemoteTest test, IAbi abi, String name) {
@@ -513,88 +437,48 @@
      * {@inheritDoc}
      */
     @Override
-    public synchronized List<IModuleDef> getModules(String serial) {
-        List<IModuleDef> modules = new ArrayList<>(mModulesPerShard);
-        Set<String> tokens = mDeviceTokens.get(serial);
-        getModulesWithTokens(tokens, modules);
-        getModules(modules);
-        mSerials.add(serial);
-        if (mSerials.size() == mShards) {
-            for (IModuleDef def : mTokenModules) {
-                CLog.logAndDisplay(LogLevel.WARN,
-                        String.format("No devices found with %s, running %s on %s",
-                                def.getTokens(), def.getId(), serial));
-                modules.add(def);
-            }
-            // Add left over modules
-            modules.addAll(mLargeModules);
-            modules.addAll(mMediumModules);
-            modules.addAll(mSmallModules);
-        }
+    public List<IModuleDef> getModules(String serial, int shardIndex) {
+        Collections.sort(mNonTokenModules, new ExecutionOrderComparator());
+        List<IModuleDef> modules = getShard(mNonTokenModules, shardIndex, mTotalShards);
+
         long estimatedTime = 0;
         for (IModuleDef def : modules) {
             estimatedTime += def.getRuntimeHint();
         }
+
+        // FIXME: Token Modules are the only last part that is not deterministic.
+        synchronized (lock) {
+            // Get tokens from the device
+            Set<String> tokens = mDeviceTokens.get(serial);
+            if (tokens != null && !tokens.isEmpty()) {
+                // if it matches any of the token modules, add them
+                for (IModuleDef def : mTokenModules) {
+                    if (!mTokenModuleScheduled.contains(def)) {
+                        modules.add(def);
+                        CLog.e("Adding %s to scheduled token", def);
+                        mTokenModuleScheduled.add(def);
+                    }
+                }
+            }
+            if (mInitCount == mTotalShards && mTokenModuleScheduled.size() != mTokenModules.size()) {
+                mTokenModules.removeAll(mTokenModuleScheduled);
+                CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+                modules.addAll(mTokenModules);
+            }
+        }
         Collections.sort(modules, new ExecutionOrderComparator());
-        CLog.logAndDisplay(LogLevel.INFO, String.format(
-                "%s running %s modules, expected to complete in %s",
-                serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime)));
+        CLog.d("%s running %s modules, expected to complete in %s: %s", serial, modules.size(),
+                TimeUtil.formatElapsedTime(estimatedTime), modules);
         return modules;
     }
 
     /**
-     * Iterates through the remaining tests that require tokens and if the device has all the
-     * required tokens it will queue that module to run on that device, else the module gets put
-     * back into the list.
+     * Helper to linearly split the list into shards with balanced runtimeHint.
+     * Exposed for testing.
      */
-    private void getModulesWithTokens(Set<String> tokens, List<IModuleDef> modules) {
-        if (tokens != null) {
-            List<IModuleDef> copy = mTokenModules;
-            mTokenModules = new ArrayList<>();
-            for (IModuleDef module : copy) {
-                // If a device has all the tokens required by the module then it can run it.
-                if (tokens.containsAll(module.getTokens())) {
-                    modules.add(module);
-                } else {
-                    mTokenModules.add(module);
-                }
-            }
-        }
-    }
-
-    /**
-     * Adds count modules that do not require tokens, to run on a device.
-     */
-    private void getModules(List<IModuleDef> modules) {
-        // Take the normal share of modules unless the device already has token modules.
-        takeModule(mSmallModules, modules, mSmallModulesPerShard - modules.size());
-        takeModule(mMediumModules, modules, mMediumModulesPerShard);
-        takeModule(mLargeModules, modules, mLargeModulesPerShard);
-        // If one bucket runs out, take from any of the others.
-        boolean success = true;
-        while (success && modules.size() < mModulesPerShard) {
-            // Take modules from the buckets until it has enough, or there are no more modules.
-            success = takeModule(mSmallModules, modules, 1)
-                    || takeModule(mMediumModules, modules, 1)
-                    || takeModule(mLargeModules, modules, 1);
-        }
-    }
-
-    /**
-     * Takes count modules from the first list and move it to the second.
-     */
-    private static boolean takeModule(
-            List<IModuleDef> source, List<IModuleDef> destination, int count) {
-        if (source.isEmpty()) {
-            return false;
-        }
-        if (count > source.size()) {
-            count = source.size();
-        }
-        for (int i = 0; i < count; i++) {
-            destination.add(source.remove(source.size() - 1));// Take from the end of the arraylist.
-        }
-        return true;
+    protected List<IModuleDef> getShard(List<IModuleDef> fullList, int shardIndex, int totalShard) {
+        List<List<IModuleDef>> res = LinearPartition.split(fullList, totalShard);
+        return res.get(shardIndex);
     }
 
     /**
@@ -619,23 +503,31 @@
         return modules;
     }
 
-    private static void putArgs(List<String> args, Map<String, Map<String, String>> argsMap) {
+    private static void putArgs(List<String> args,
+            Map<String, Map<String, List<String>>> argsMap) {
         for (String arg : args) {
             String[] parts = arg.split(":");
             String target = parts[0];
             String key = parts[1];
             String value = parts[2];
-            Map<String, String> map = argsMap.get(target);
+            Map<String, List<String>> map = argsMap.get(target);
             if (map == null) {
                 map = new HashMap<>();
                 argsMap.put(target, map);
             }
-            map.put(key, value);
+            List<String> valueList = map.get(key);
+            if (valueList == null) {
+                valueList = new ArrayList<>();
+                map.put(key, valueList);
+            }
+            valueList.add(value);
         }
     }
 
+    /**
+     * Sort by name and use runtimeHint for separation, shortest test first.
+     */
     private static class ExecutionOrderComparator implements Comparator<IModuleDef> {
-
         @Override
         public int compare(IModuleDef def1, IModuleDef def2) {
             int value1 = 0;
@@ -647,9 +539,21 @@
                 value2 = ENDING_MODULES.get(def2.getName());
             }
             if (value1 == 0 && value2 == 0) {
-                return (int) Math.signum(def2.getRuntimeHint() - def1.getRuntimeHint());
+                int time = (int) Math.signum(def1.getRuntimeHint() - def2.getRuntimeHint());
+                if (time == 0) {
+                    return def1.getName().compareTo(def2.getName());
+                }
+                return time;
             }
             return (int) Math.signum(value1 - value2);
         }
     }
+
+    /**
+     * Reset some module repo variable. Exposed for testing.
+     */
+    protected void resetModuleRepo() {
+        mInitCount = 0;
+        mTokenModuleScheduled = null;
+    }
 }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
index 54d2869..c2c7155 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
@@ -24,7 +24,6 @@
 import org.xml.sax.helpers.DefaultHandler;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/CollectorUtil.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/CollectorUtil.java
index 1321f22..2390d9e 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/CollectorUtil.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/CollectorUtil.java
@@ -16,6 +16,8 @@
 
 package com.android.compatibility.common.tradefed.util;
 
+import com.android.compatibility.common.tradefed.targetprep.DeviceInfoCollector;
+import com.android.compatibility.common.tradefed.targetprep.ReportLogCollector;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -34,7 +36,7 @@
 import java.util.regex.Pattern;
 
 /**
- * Util class for {@link ReportLogCollector} and {@link DeviceInfoCollector}.
+ * Utility class for {@link ReportLogCollector} and {@link DeviceInfoCollector}.
  */
 public class CollectorUtil {
 
@@ -137,7 +139,7 @@
      * Helper function to reformat JSON string.
      *
      * @param jsonString
-     * @return
+     * @return the reformatted JSON string.
      */
     public static String reformatJsonString(String jsonString) {
         StringBuilder newJsonBuilder = new StringBuilder();
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/LinearPartition.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/LinearPartition.java
new file mode 100644
index 0000000..df91e57
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/LinearPartition.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 com.android.compatibility.common.tradefed.util;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for the shard splitting. Split linearly a list into N sublist with
+ * approximately the same weight.
+ * TODO: Can be generalized for any weighted objects.
+ */
+public class LinearPartition {
+
+    /**
+     * Split a list of {@link IModuleDef} into k sub list based on the runtime hint.
+     *
+     * @param seq the full list of {@link IModuleDef} to be splitted
+     * @param k the number of sub list we need.
+     * @return the List of sublist.
+     */
+    public static List<List<IModuleDef>> split(List<IModuleDef> seq, int k) {
+        ArrayList<List<IModuleDef>> result = new ArrayList<>();
+
+        if (k <= 0) {
+            ArrayList<IModuleDef> partition = new ArrayList<>();
+            partition.addAll(seq);
+            result.add(partition);
+            return result;
+        }
+
+        int n = seq.size() - 1;
+
+        if (k > n) {
+            for (IModuleDef value : seq) {
+                ArrayList<IModuleDef> partition = new ArrayList<>();
+                partition.add(value);
+                result.add(partition);
+            }
+            return result;
+        }
+
+        int[][] table = buildPartitionTable(seq, k);
+        k = k - 2;
+
+        while (k >= 0) {
+            ArrayList<IModuleDef> partition = new ArrayList<>();
+
+            for (int i = table[n - 1][k] + 1; i < n + 1; i++) {
+                partition.add(seq.get(i));
+            }
+
+            result.add(0, partition);
+            n = table[n - 1][k];
+            k = k - 1;
+        }
+
+        ArrayList<IModuleDef> partition = new ArrayList<>();
+
+        for (int i = 0; i < n + 1; i++) {
+            partition.add(seq.get(i));
+        }
+
+        result.add(0, partition);
+
+        return result;
+    }
+
+    /**
+     * Internal helper to build the partition table of the linear distribution used for splitting.
+     */
+    private static int[][] buildPartitionTable(List<IModuleDef> seq, int k) {
+        int n = seq.size();
+        float[][] table = new float[n][k];
+        int[][] solution = new int[n - 1][k - 1];
+
+        for (int i = 0; i < n; i++) {
+            table[i][0] = seq.get(i).getRuntimeHint() + ((i > 0) ? (table[i - 1][0]) : 0);
+        }
+
+        for (int j = 0; j < k; j++) {
+            table[0][j] = seq.get(0).getRuntimeHint();
+        }
+
+        for (int i = 1; i < n; i++) {
+            for (int j = 1; j < k; j++) {
+                table[i][j] = Integer.MAX_VALUE;
+                for (int x = 0; x < i; x++) {
+                    float cost = Math.max(table[x][j - 1], table[i][0] - table[x][0]);
+                    if (table[i][j] > cost) {
+                        table[i][j] = cost;
+                        solution[i - 1][j - 1] = x;
+                    }
+                }
+            }
+        }
+
+        return solution;
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java
deleted file mode 100644
index 06f493d..0000000
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/NoOpTestInvocationListener.java
+++ /dev/null
@@ -1,120 +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.util;
-
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.ITestRunListener;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.result.InputStreamSource;
-import com.android.tradefed.result.LogDataType;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.result.TestSummary;
-
-import java.util.Map;
-
-/**
- * Implementation of ITestInvocationListener that does nothing or returns null for all methods.
- * Extend this class to implement some, but not all methods of ITestInvocationListener.
- */
-public class NoOpTestInvocationListener implements ITestInvocationListener {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void invocationStarted(IBuildInfo buildInfo) {}
-
-     /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void invocationEnded(long elapsedTime) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void invocationFailed(Throwable cause) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public TestSummary getSummary() {
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testRunStarted(String runName, int testCount) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testStarted(TestIdentifier test) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testFailed(TestIdentifier test, String trace) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testAssumptionFailure(TestIdentifier test, String trace) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testIgnored(TestIdentifier test) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testRunFailed(String errorMessage) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testRunStopped(long elapsedTime) {}
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {}
-
-}
diff --git a/common/host-side/tradefed/tests/Android.mk b/common/host-side/tradefed/tests/Android.mk
index e8b959a..6bc8bc9 100644
--- a/common/host-side/tradefed/tests/Android.mk
+++ b/common/host-side/tradefed/tests/Android.mk
@@ -34,6 +34,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_RESOURCE_DIRS := res
 
 LOCAL_MODULE := compatibility-tradefed-tests
 
@@ -41,6 +42,6 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := easymock
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt compatibility-mock-tradefed junit-host compatibility-host-util
+LOCAL_JAVA_LIBRARIES := tradefed compatibility-mock-tradefed junit-host compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/tests/res/testtype/testJar1.jar b/common/host-side/tradefed/tests/res/testtype/testJar1.jar
new file mode 100644
index 0000000..50d5bd2
--- /dev/null
+++ b/common/host-side/tradefed/tests/res/testtype/testJar1.jar
Binary files differ
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index b8b7858..4484d49 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -17,18 +17,22 @@
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelperTest;
 import com.android.compatibility.common.tradefed.command.CompatibilityConsoleTest;
+import com.android.compatibility.common.tradefed.config.ConfigurationFactoryTest;
+import com.android.compatibility.common.tradefed.presubmit.PresubmitSetupValidation;
 import com.android.compatibility.common.tradefed.result.ChecksumReporterTest;
 import com.android.compatibility.common.tradefed.result.ConsoleReporterTest;
 import com.android.compatibility.common.tradefed.result.ResultReporterTest;
 import com.android.compatibility.common.tradefed.result.SubPlanCreatorTest;
 import com.android.compatibility.common.tradefed.targetprep.PropertyCheckTest;
 import com.android.compatibility.common.tradefed.targetprep.SettingsPreparerTest;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBaseTest;
 import com.android.compatibility.common.tradefed.testtype.CompatibilityTestTest;
+import com.android.compatibility.common.tradefed.testtype.JarHostTestTest;
 import com.android.compatibility.common.tradefed.testtype.ModuleDefTest;
 import com.android.compatibility.common.tradefed.testtype.ModuleRepoTest;
 import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
-import com.android.compatibility.common.tradefed.util.OptionHelperTest;
 import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
+import com.android.compatibility.common.tradefed.util.OptionHelperTest;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -42,21 +46,39 @@
 
     public UnitTests() {
         super();
+        // build
         addTestSuite(CompatibilityBuildHelperTest.class);
+
+        // command
         addTestSuite(CompatibilityConsoleTest.class);
-        addTestSuite(CompatibilityTestTest.class);
-        addTestSuite(ConsoleReporterTest.class);
+
+        //config
+        addTestSuite(ConfigurationFactoryTest.class);
+
+        // presubmit
+        addTestSuite(PresubmitSetupValidation.class);
+
+        //result
         addTestSuite(ChecksumReporterTest.class);
+        addTestSuite(ConsoleReporterTest.class);
         addTestSuite(ResultReporterTest.class);
-        addTestSuite(CompatibilityTestTest.class);
-        addTestSuite(OptionHelperTest.class);
-        addTestSuite(CollectorUtilTest.class);
-        addTestSuite(ModuleDefTest.class);
-        addTestSuite(ModuleRepoTest.class);
+        addTestSuite(SubPlanCreatorTest.class);
+
+        // targetprep
         addTestSuite(PropertyCheckTest.class);
         addTestSuite(SettingsPreparerTest.class);
+
+        // testtype
+        addTestSuite(CompatibilityHostTestBaseTest.class);
+        addTestSuite(CompatibilityTestTest.class);
+        addTestSuite(JarHostTestTest.class);
+        addTestSuite(ModuleDefTest.class);
+        addTestSuite(ModuleRepoTest.class);
         addTestSuite(SubPlanTest.class);
-        addTestSuite(SubPlanCreatorTest.class);
+
+        // util
+        addTestSuite(CollectorUtilTest.class);
+        addTestSuite(OptionHelperTest.class);
     }
 
     public static Test suite() {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
index 41f9e8d..44c262d 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
@@ -17,6 +17,7 @@
 package com.android.compatibility.common.tradefed.build;
 
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.util.FileUtil;
 
 import junit.framework.TestCase;
@@ -37,7 +38,6 @@
     private static final String BASE_DIR_NAME = "android-tests";
     private static final String TESTCASES = "testcases";
     private static final String COMMAND_LINE_ARGS = "cts -m CtsModuleTestCases";
-    private static final long START_TIME = 123456L;
 
     private File mRoot = null;
     private File mBase = null;
@@ -48,7 +48,28 @@
     @Override
     public void setUp() throws Exception {
         mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
-        CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+        setProperty(mRoot.getAbsolutePath());
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+            @Override
+            protected String getSuiteInfoName() {
+                return SUITE_NAME;
+            }
+            @Override
+            protected String getSuiteInfoBuildNumber() {
+                return BUILD_NUMBER;
+            }
+            @Override
+            protected String getSuiteInfoFullname() {
+                return SUITE_FULL_NAME;
+            }
+            @Override
+            protected String getSuiteInfoVersion() {
+                return SUITE_VERSION;
+            }
+        };
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", DYNAMIC_CONFIG_URL);
         mBuild = provider.getBuild();
         mHelper = new CompatibilityBuildHelper(mBuild);
     }
@@ -71,7 +92,6 @@
 
     public void testSuiteInfoLoad() throws Exception {
         setProperty(mRoot.getAbsolutePath());
-        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
         assertEquals("Incorrect suite build number", BUILD_NUMBER, mHelper.getSuiteBuild());
         assertEquals("Incorrect suite name", SUITE_NAME, mHelper.getSuiteName());
         assertEquals("Incorrect suite full name", SUITE_FULL_NAME, mHelper.getSuiteFullName());
@@ -80,23 +100,29 @@
 
     public void testProperty() throws Exception {
         setProperty(null);
-        CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
-        CompatibilityBuildHelper helper = new CompatibilityBuildHelper(provider.getBuild());
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+            @Override
+            protected String getSuiteInfoName() {
+                return SUITE_NAME;
+            }
+        };
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", DYNAMIC_CONFIG_URL);
         try {
             // Should fail with root unset
-            helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
+            new CompatibilityBuildHelper(provider.getBuild());
             fail("Expected fail for unset root property");
         } catch (IllegalArgumentException e) {
             /* expected */
         }
         setProperty(mRoot.getAbsolutePath());
         // Shouldn't fail with root set
-        helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
+        new CompatibilityBuildHelper(provider.getBuild());
     }
 
     public void testValidation() throws Exception {
         setProperty(mRoot.getAbsolutePath());
-        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
         try {
             mHelper.getDir();
             fail("Build helper validation succeeded on an invalid installation");
@@ -114,7 +140,6 @@
 
     public void testDirs() throws Exception {
         setProperty(mRoot.getAbsolutePath());
-        mHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
         createDirStructure();
         assertNotNull(mRoot);
         assertNotNull(mBuild);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java
index 55c1651..9b59775 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/command/CompatibilityConsoleTest.java
@@ -20,6 +20,9 @@
 
 import junit.framework.TestCase;
 
+/**
+ * Unit tests for {@link CompatibilityConsole}.
+ */
 public class CompatibilityConsoleTest extends TestCase {
 
     @Override
@@ -32,13 +35,8 @@
         CompatibilityBuildHelperTest.setProperty(null);
     }
 
-    public void testHelpExists() throws Exception {
-        CompatibilityConsole console = new CompatibilityConsole() {};
-        assertFalse("No help", console.getGenericHelpString(null).isEmpty());
-    }
-
     public void testPromptExists() throws Exception {
-        CompatibilityConsole console = new CompatibilityConsole() {};
+        CompatibilityConsole console = new CompatibilityConsole();
         assertFalse("No prompt", console.getConsolePrompt().isEmpty());
     }
 }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/config/ConfigurationFactoryTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/config/ConfigurationFactoryTest.java
new file mode 100644
index 0000000..3a59387
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/config/ConfigurationFactoryTest.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.compatibility.common.tradefed.config;
+
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link ConfigurationFactory} imported from Trade Federation to check cts
+ * configuration loading.
+ */
+public class ConfigurationFactoryTest extends TestCase {
+
+    private ConfigurationFactory mConfigFactory;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mConfigFactory = (ConfigurationFactory) ConfigurationFactory.getInstance();
+    }
+
+    /**
+     * Sanity test to ensure all config names on classpath are loadable.
+     */
+    public void testLoadAllConfigs() throws ConfigurationException {
+        // we dry-run the templates otherwise it will always fail.
+        mConfigFactory.loadAllConfigs(false);
+    }
+
+    /**
+     * Sanity test to ensure all configs on classpath can be fully loaded and parsed.
+     */
+    public void testLoadAndPrintAllConfigs() throws ConfigurationException {
+        // Printing the help involves more checks since it tries to resolve the config objects.
+        mConfigFactory.loadAndPrintAllConfigs();
+    }
+}
\ No newline at end of file
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
new file mode 100644
index 0000000..3342ba0
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
@@ -0,0 +1,47 @@
+/*
+ * 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.compatibility.common.tradefed.presubmit;
+
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that validate the CTS presubmit setup to ensure no CL will break the presubmit setup
+ * itself.
+ */
+public class PresubmitSetupValidation extends TestCase {
+    private static final String PRESUBMIT_CTS_UNIT_TESTS = "cts-unit-tests";
+
+    /**
+     * Test that the base cts unit tests configuration is still working, and has a reporter
+     * template placeholder.
+     */
+    public void testCtsPresubmit_unit_tests() {
+        IConfigurationFactory factory = ConfigurationFactory.getInstance();
+        String[] presubmitCommand = {PRESUBMIT_CTS_UNIT_TESTS, "--template:map", "reporters=empty"};
+        try {
+            factory.createConfigurationFromArgs(presubmitCommand);
+        } catch (ConfigurationException e) {
+            CLog.e(e);
+            fail(String.format("ConfigException '%s': One of your change is breaking the presubmit "
+                    + "CTS unit tests configuration.", e.getMessage()));
+        }
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
index 0646385..d5062b3 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -15,9 +15,7 @@
  */
 package com.android.compatibility.common.tradefed.result;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
-import com.android.compatibility.common.tradefed.result.ResultReporter;
 import com.android.compatibility.common.util.ChecksumReporter;
 import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
 import com.android.compatibility.common.util.ICaseResult;
@@ -26,7 +24,6 @@
 import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.TestStatus;
-import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.util.FileUtil;
@@ -46,13 +43,10 @@
     private static final String SUITE_PLAN = "cts";
     private static final String BASE_DIR_NAME = "android-tests";
     private static final String TESTCASES = "testcases";
-    private static final String DYNAMIC_CONFIG_URL = "";
-    private static final long START_TIME = 123456L;
 
     private ChecksumReporter mReporter;
     private File mRoot = null;
     private IBuildInfo mBuildInfo;
-    private CompatibilityBuildHelper mBuildHelper;
     private ReportLog mReportLog = null;
     private IInvocationResult mInvocationResult;
     private IModuleResult mModuleResult;
@@ -69,10 +63,25 @@
         System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
 
         ResultReporter resultReporter = new ResultReporter();
-        OptionSetter setter = new OptionSetter(resultReporter);
-        mBuildInfo = new BuildInfo(BUILD_NUMBER, "", "");
-        mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
-        mBuildHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+            @Override
+            protected String getSuiteInfoName() {
+                return SUITE_NAME;
+            }
+            @Override
+            protected String getSuiteInfoBuildNumber() {
+                return BUILD_NUMBER;
+            }
+            @Override
+            protected String getSuiteInfoVersion() {
+                return BUILD_NUMBER;
+            }
+        };
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", "");
+        mBuildInfo = provider.getBuild();
+
         resultReporter.invocationStarted(mBuildInfo);
         mInvocationResult = resultReporter.getResult();
         mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
@@ -96,6 +105,7 @@
     @Override
     public void tearDown() throws Exception {
         mReporter = null;
+        FileUtil.recursiveDelete(mRoot);
     }
 
     public void testStoreAndRetrieveTestResults() {
@@ -121,8 +131,7 @@
                 mReporter.containsModuleResult(mModuleResult, fingerprint));
     }
 
-    public void testFileSerialization()
-            throws IOException, ClassNotFoundException, ChecksumValidationException {
+    public void testFileSerialization() throws IOException, ChecksumValidationException {
         mReporter.addInvocation(mInvocationResult);
 
         File file1 = new File(mRoot, "file1.txt");
@@ -164,7 +173,7 @@
             fileWriter.append("This is a test file added after crc calculated");
         }
         assertFalse("Should not contain file created after crc calculated",
-                mReporter.containsFile(file3, folderName));
+                mReporter.containsFile(file3, mRoot + "/"));
 
     }
 
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
index 928379e..2db94fa 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ConsoleReporterTest.java
@@ -16,29 +16,20 @@
 
 package com.android.compatibility.common.tradefed.result;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.compatibility.common.util.ICaseResult;
-import com.android.compatibility.common.util.IInvocationResult;
-import com.android.compatibility.common.util.IModuleResult;
-import com.android.compatibility.common.util.ITestResult;
-import com.android.compatibility.common.util.TestStatus;
 import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
-import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.AbiUtils;
 
 import junit.framework.TestCase;
 
-import java.io.File;
-import java.io.FileFilter;
 import java.util.HashMap;
-import java.util.List;
 
+/**
+ * Tests for {@link ConsoleReporter}.
+ */
 public class ConsoleReporterTest extends TestCase {
 
-    private static final String TESTCASES = "testcases";
     private static final String NAME = "ModuleName";
     private static final String NAME2 = "ModuleName2";
     private static final String ABI = "mips64";
@@ -48,19 +39,11 @@
     private static final String METHOD_1 = "testBlah1";
     private static final String METHOD_2 = "testBlah2";
     private static final String METHOD_3 = "testBlah3";
-    private static final String TEST_1 = String.format("%s#%s", CLASS, METHOD_1);
-    private static final String TEST_2 = String.format("%s#%s", CLASS, METHOD_2);
-    private static final String TEST_3 = String.format("%s#%s", CLASS, METHOD_3);
     private static final String STACK_TRACE = "Something small is not alright\n " +
             "at four.big.insects.Marley.sing(Marley.java:10)";
 
     private ConsoleReporter mReporter;
     private IBuildInfo mBuildInfo;
-    private CompatibilityBuildHelper mBuildHelper;
-
-    private File mRoot = null;
-    private File mBase = null;
-    private File mTests = null;
 
     @Override
     public void setUp() throws Exception {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
index 0df6ad0..84f9faf 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -17,16 +17,16 @@
 package com.android.compatibility.common.tradefed.result;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
 import com.android.compatibility.common.util.ICaseResult;
 import com.android.compatibility.common.util.IInvocationResult;
 import com.android.compatibility.common.util.IModuleResult;
 import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.TestStatus;
 import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.FileUtil;
 
 import junit.framework.TestCase;
@@ -39,6 +39,7 @@
 public class ResultReporterTest extends TestCase {
 
     private static final String ROOT_PROPERTY = "TESTS_ROOT";
+    private static final String SUITE_NAME = "TESTS";
     private static final String BUILD_NUMBER = "2";
     private static final String SUITE_PLAN = "cts";
     private static final String DYNAMIC_CONFIG_URL = "";
@@ -63,7 +64,6 @@
         "compatibility_result.xsd",
         "compatibility_result.xsl",
         "logo.png"};
-    private static final long START_TIME = 123456L;
 
     private ResultReporter mReporter;
     private IBuildInfo mBuildInfo;
@@ -76,16 +76,31 @@
     @Override
     public void setUp() throws Exception {
         mReporter = new ResultReporter();
-        OptionSetter setter = new OptionSetter(mReporter);
         mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
         mBase = new File(mRoot, BASE_DIR_NAME);
         mBase.mkdirs();
         mTests = new File(mBase, TESTCASES);
         mTests.mkdirs();
         System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
-        mBuildInfo = new BuildInfo(BUILD_NUMBER, "", "");
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+            @Override
+            protected String getSuiteInfoName() {
+                return SUITE_NAME;
+            }
+            @Override
+            protected String getSuiteInfoBuildNumber() {
+                return BUILD_NUMBER;
+            }
+            @Override
+            protected String getSuiteInfoVersion() {
+                return BUILD_NUMBER;
+            }
+        };
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", DYNAMIC_CONFIG_URL);
+        mBuildInfo = provider.getBuild();
         mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
-        mBuildHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
     }
 
     @Override
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
index 4663a27..e3240c1 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
@@ -18,19 +18,18 @@
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.testtype.ISubPlan;
-import com.android.compatibility.common.util.AbiUtils;
 import com.android.compatibility.common.util.ICaseResult;
 import com.android.compatibility.common.util.IInvocationResult;
 import com.android.compatibility.common.util.IModuleResult;
-import com.android.compatibility.common.util.InvocationResult;
 import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.InvocationResult;
 import com.android.compatibility.common.util.ResultHandler;
 import com.android.compatibility.common.util.TestFilter;
 import com.android.compatibility.common.util.TestStatus;
-import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ArgsOptionParser;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.FileUtil;
 
 import junit.framework.TestCase;
@@ -47,7 +46,6 @@
     private static final String SUITE_VERSION = "5.0";
     private static final String SUITE_PLAN = "cts";
     private static final String SUITE_BUILD = "12345";
-    private static final String REPORT_VERSION = "5.0";
     private static final String NAME_A = "ModuleA";
     private static final String NAME_B = "ModuleB";
     private static final String ABI = "mips64";
@@ -59,7 +57,6 @@
     private static final String EXAMPLE_BUILD_PRODUCT = "wolverine";
     private static final String DEVICE_A = "device123";
     private static final String DEVICE_B = "device456";
-    private static final String DEVICES = "device456,device123";
     private static final String CLASS_A = "android.test.Foor";
     private static final String CLASS_B = "android.test.Bar";
     private static final String METHOD_1 = "testBlah1";
@@ -68,8 +65,6 @@
     private static final String METHOD_4 = "testBlah4";
     private static final long START_MS = 1431586801000L;
     private static final long END_MS = 1431673199000L;
-    private static final String START_DISPLAY = "Fri Aug 20 15:13:03 PDT 2010";
-    private static final String END_DISPLAY = "Fri Aug 20 15:13:04 PDT 2010";
     private static final String REFERENCE_URL="http://android.com";
     private static final String LOG_URL ="file:///path/to/logs";
     private static final String COMMAND_LINE_ARGS = "cts -m CtsMyModuleTestCases";
@@ -169,6 +164,7 @@
             return mResultsDir;
         }
 
+        @Override
         public File getSubPlansDir() throws FileNotFoundException {
             return mSubPlansDir;
         }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
index a309a47..617fde6 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
@@ -45,6 +45,7 @@
         mMockBuildInfo = new DeviceBuildInfo("0", "", "");
         mOptionSetter = new OptionSetter(mPropertyCheck);
         EasyMock.expect(mMockDevice.getProperty(PROPERTY)).andReturn(ACTUAL_VALUE).anyTimes();
+        EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).anyTimes();
     }
 
     public void testWarningMatch() throws Exception {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
index 739662e..7fbb39e 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.compatibility.common.tradefed.targetprep;
 
-import com.android.tradefed.build.DeviceBuildInfo;
 import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
@@ -27,6 +26,9 @@
 
 import org.easymock.EasyMock;
 
+/**
+ * Tests for {@link SettingsPreparer}
+ */
 public class SettingsPreparerTest extends TestCase {
 
     private SettingsPreparer mSettingsPreparer;
@@ -43,6 +45,7 @@
         super.setUp();
         mSettingsPreparer = new SettingsPreparer();
         mMockDevice = EasyMock.createMock(ITestDevice.class);
+        EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).anyTimes();
         mMockBuildInfo = new BuildInfo("0", "", "");
         mOptionSetter = new OptionSetter(mSettingsPreparer);
         mOptionSetter.setOptionValue("device-setting", "stay_on_while_plugged_in");
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBaseTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBaseTest.java
new file mode 100644
index 0000000..2724df6
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityHostTestBaseTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.compatibility.common.tradefed.testtype;
+
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.JUnit4ResultForwarder;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Collections;
+
+/**
+ * Tests for the CompatibilityHostTestBase class.
+ */
+public class CompatibilityHostTestBaseTest extends TestCase {
+
+    private static final String DEVICE_TEST_PKG = "com.android.foo";
+
+    @RunWith(DeviceJUnit4ClassRunner.class)
+    public static class MockTest extends CompatibilityHostTestBase {
+
+        @Test
+        public void testRunDeviceTests() throws Exception {
+            runDeviceTests(DEVICE_TEST_PKG, null, null);
+        }
+
+    }
+
+    public void testRunMockDeviceTests() throws Exception {
+        final TestIdentifier testRunDeviceTests =
+                new TestIdentifier(MockTest.class.getName(), "testRunDeviceTests");
+
+        ITestInvocationListener listener = EasyMock.createMock(ITestInvocationListener.class);
+        ITestDevice device = EasyMock.createMock(ITestDevice.class);
+
+        listener.testStarted(testRunDeviceTests);
+        EasyMock.expect(device.getIDevice()).andReturn(EasyMock.createMock(IDevice.class)).once();
+        EasyMock.expect(device.runInstrumentationTests((RemoteAndroidTestRunner)
+                EasyMock.anyObject(), (CollectingTestListener) EasyMock.anyObject())).andReturn(
+                true).once();
+        listener.testEnded(testRunDeviceTests, Collections.emptyMap());
+        EasyMock.replay(listener, device);
+
+        JUnitCore runnerCore = new JUnitCore();
+        runnerCore.addListener(new JUnit4ResultForwarder(listener));
+        Runner checkRunner = Request.aClass(MockTest.class).getRunner();
+        ((IDeviceTest) checkRunner).setDevice(device);
+        ((IBuildReceiver) checkRunner).setBuild(EasyMock.createMock(IBuildInfo.class));
+        ((IAbiReceiver) checkRunner).setAbi(EasyMock.createMock(IAbi.class));
+        runnerCore.run(checkRunner);
+        EasyMock.verify(listener, device);
+    }
+
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java
index ccab426..927b30b 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestTest.java
@@ -13,19 +13,171 @@
  * 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.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
 import junit.framework.TestCase;
 
+import java.util.HashSet;
+import java.util.Set;
+
+import org.easymock.EasyMock;
+
+/**
+ * Test class for {@link CompatibilityTest}
+ */
 public class CompatibilityTestTest extends TestCase {
 
+    private static final String FAKE_HOST_ARCH = "arm";
+    private CompatibilityTest mTest;
+    private ITestDevice mMockDevice;
+
     @Override
     public void setUp() throws Exception {
+        mTest = new CompatibilityTest() {
+            @Override
+            protected Set<String> getAbisForBuildTargetArch() {
+                return AbiUtils.getAbisForArch(FAKE_HOST_ARCH);
+            }
+        };
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+        mTest.setDevice(mMockDevice);
     }
 
-    @Override
-    public void tearDown() throws Exception {
+    /**
+     * Test that {@link CompatibilityTest#getAbis()} is returning a proper intersection of CTS
+     * supported architectures and Device supported architectures.
+     */
+    public void testGetAbis() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+                .andReturn("arm64-v8a,armeabi-v7a,armeabi");
+        Set<String> expectedAbis = new HashSet<>();
+        expectedAbis.add("arm64-v8a");
+        expectedAbis.add("armeabi-v7a");
+        EasyMock.replay(mMockDevice);
+        Set<IAbi> res = mTest.getAbis();
+        assertEquals(2, res.size());
+        for (IAbi abi : res) {
+            assertTrue(expectedAbis.contains(abi.getName()));
+        }
+        EasyMock.verify(mMockDevice);
     }
 
+    /**
+     * Test that {@link CompatibilityTest#getAbis()} is throwing an exception when none of the
+     * CTS build supported abi match the device abi.
+     */
+    public void testGetAbis_notSupported() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+                .andReturn("armeabi");
+        EasyMock.replay(mMockDevice);
+        try {
+            mTest.getAbis();
+            fail("Should have thrown an exception");
+        } catch (IllegalArgumentException e) {
+            assertEquals("None of the abi supported by this CTS build ('[armeabi-v7a, arm64-v8a]')"
+                    + " are supported by the device ('[armeabi]').", e.getMessage());
+        }
+        EasyMock.verify(mMockDevice);
+    }
+
+    /**
+     * Test that {@link CompatibilityTest#getAbis()} is returning only the device primary abi.
+     */
+    public void testGetAbis_primaryAbiOnly() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue(CompatibilityTest.PRIMARY_ABI_RUN, "true");
+        EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abi")))
+                .andReturn("arm64-v8a");
+        Set<String> expectedAbis = new HashSet<>();
+        expectedAbis.add("arm64-v8a");
+        EasyMock.replay(mMockDevice);
+        Set<IAbi> res = mTest.getAbis();
+        assertEquals(1, res.size());
+        for (IAbi abi : res) {
+            assertTrue(expectedAbis.contains(abi.getName()));
+        }
+        EasyMock.verify(mMockDevice);
+    }
+
+    /**
+     * Test that {@link CompatibilityTest#getAbis()} is throwing an exception if the primary
+     * abi is not supported.
+     */
+    public void testGetAbis_primaryAbiOnly_NotSupported() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue(CompatibilityTest.PRIMARY_ABI_RUN, "true");
+        EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abi")))
+                .andReturn("armeabi");
+        EasyMock.replay(mMockDevice);
+        try {
+            mTest.getAbis();
+            fail("Should have thrown an exception");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Your CTS hasn't been built with abi 'armeabi' support, "
+                    + "this CTS currently supports '[armeabi-v7a, arm64-v8a]'.", e.getMessage());
+        }
+        EasyMock.verify(mMockDevice);
+    }
+
+    /**
+     * Test that {@link CompatibilityTest#getAbis()} is returning the list of abi supported by
+     * Compatibility and the device, and not the particular CTS build.
+     */
+    public void testGetAbis_skipCtsArchCheck() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue(CompatibilityTest.SKIP_HOST_ARCH_CHECK, "true");
+        EasyMock.expect(mMockDevice.getProperty(EasyMock.eq("ro.product.cpu.abilist")))
+                .andReturn("x86_64,x86,armeabi");
+        Set<String> expectedAbis = new HashSet<>();
+        expectedAbis.add("x86_64");
+        expectedAbis.add("x86");
+        EasyMock.replay(mMockDevice);
+        Set<IAbi> res = mTest.getAbis();
+        assertEquals(2, res.size());
+        for (IAbi abi : res) {
+            assertTrue(expectedAbis.contains(abi.getName()));
+        }
+        EasyMock.verify(mMockDevice);
+    }
+
+    /**
+     * Test {@link CompatibilityTest#getAbis()} when we skip the Cts side architecture check and
+     * want to run x86 abi.
+     */
+    public void testGetAbis_skipCtsArchCheck_abiSpecified() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue(CompatibilityTest.SKIP_HOST_ARCH_CHECK, "true");
+        setter.setOptionValue(CompatibilityTest.ABI_OPTION, "x86");
+        Set<String> expectedAbis = new HashSet<>();
+        expectedAbis.add("x86");
+        EasyMock.replay(mMockDevice);
+        Set<IAbi> res = mTest.getAbis();
+        assertEquals(1, res.size());
+        for (IAbi abi : res) {
+            assertTrue(expectedAbis.contains(abi.getName()));
+        }
+        EasyMock.verify(mMockDevice);
+    }
+
+    /**
+     * Test {@link CompatibilityTest#split()} when a shard number is specified.
+     */
+    public void testSplit() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue("shards", "4");
+        assertEquals(4, mTest.split().size());
+    }
+
+    /**
+     * Test {@link CompatibilityTest#split()} when no shard number is specified.
+     */
+    public void testSplit_notShardable() throws Exception {
+        assertNull(mTest.split());
+    }
 }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java
new file mode 100644
index 0000000..cf5e214
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.testtype.HostTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.StubTest;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * Unit tests for {@link JarHostTest}.
+ */
+public class JarHostTestTest extends TestCase {
+
+    private static final String TEST_JAR1 = "/testtype/testJar1.jar";
+    private JarHostTest mTest;
+    private File mTestDir = null;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTest = new JarHostTest();
+        mTestDir = FileUtil.createTempDir("jarhostest");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        FileUtil.recursiveDelete(mTestDir);
+        super.tearDown();
+    }
+
+    /**
+     * Helper to read a file from the res/testtype directory and return it.
+     *
+     * @param filename the name of the file in the res/testtype directory
+     * @param parentDir dir where to put the jar. Null if in default tmp directory.
+     * @return the extracted jar file.
+     */
+    protected File getJarResource(String filename, File parentDir) throws IOException {
+        InputStream jarFileStream = getClass().getResourceAsStream(filename);
+        File jarFile = FileUtil.createTempFile("test", ".jar", parentDir);
+        FileUtil.writeToFile(jarFileStream, jarFile);
+        return jarFile;
+    }
+
+    /**
+     * Test class, we have to annotate with full org.junit.Test to avoid name collision in import.
+     */
+    @RunWith(JUnit4.class)
+    public static class Junit4TestClass  {
+        public Junit4TestClass() {}
+        @org.junit.Test
+        public void testPass1() {}
+    }
+
+    /**
+     * Test class, we have to annotate with full org.junit.Test to avoid name collision in import.
+     */
+    @RunWith(JUnit4.class)
+    public static class Junit4TestClass2  {
+        public Junit4TestClass2() {}
+        @org.junit.Test
+        public void testPass2() {}
+    }
+
+    /**
+     * Test that {@link JarHostTest#split()} inherited from {@link HostTest} is still good.
+     */
+    public void testSplit_withoutJar() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue("class", "com.android.compatibility.common.tradefed.testtype."
+                + "JarHostTestTest$Junit4TestClass");
+        setter.setOptionValue("class", "com.android.compatibility.common.tradefed.testtype."
+                + "JarHostTestTest$Junit4TestClass2");
+        List<IRemoteTest> res = (List<IRemoteTest>)mTest.split();
+        assertEquals(2, res.size());
+        assertTrue(res.get(0) instanceof JarHostTest);
+        assertTrue(res.get(1) instanceof JarHostTest);
+    }
+
+    /**
+     * Test that {@link JarHostTest#split()} can split classes coming from a jar.
+     */
+    public void testSplit_withJar() throws Exception {
+        File testJar = getJarResource(TEST_JAR1, mTestDir);
+        mTest = new JarHostTest() {
+            @Override
+            CompatibilityBuildHelper createBuildHelper(IBuildInfo info) {
+                return new CompatibilityBuildHelper(info) {
+                    @Override
+                    public File getTestsDir() throws FileNotFoundException {
+                        return mTestDir;
+                    }
+                };
+            }
+        };
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue("jar", testJar.getName());
+        List<IRemoteTest> res = (List<IRemoteTest>)mTest.split();
+        assertEquals(2, res.size());
+        assertTrue(res.get(0) instanceof JarHostTest);
+        assertEquals("[android.ui.cts.TaskSwitchingTest]",
+                ((JarHostTest)res.get(0)).getClassNames().toString());
+        assertTrue(res.get(1) instanceof JarHostTest);
+        assertEquals("[android.ui.cts.InstallTimeTest]",
+                ((JarHostTest)res.get(1)).getClassNames().toString());
+    }
+
+    /**
+     * Test that {@link JarHostTest#getTestShard(int, int)} can split classes coming from a jar.
+     */
+    public void testGetTestShard_withJar() throws Exception {
+        File testJar = getJarResource(TEST_JAR1, mTestDir);
+        mTest = new JarHostTest() {
+            @Override
+            CompatibilityBuildHelper createBuildHelper(IBuildInfo info) {
+                return new CompatibilityBuildHelper(info) {
+                    @Override
+                    public File getTestsDir() throws FileNotFoundException {
+                        return mTestDir;
+                    }
+                };
+            }
+        };
+        OptionSetter setter = new OptionSetter(mTest);
+        setter.setOptionValue("jar", testJar.getName());
+        IRemoteTest shard1 = mTest.getTestShard(3, 0);
+        assertTrue(shard1 instanceof JarHostTest);
+        assertEquals("[android.ui.cts.TaskSwitchingTest]",
+                ((JarHostTest)shard1).getClassNames().toString());
+        IRemoteTest shard2 = mTest.getTestShard(3, 1);
+        assertTrue(shard2 instanceof JarHostTest);
+        assertEquals("[android.ui.cts.InstallTimeTest]",
+                ((JarHostTest)shard2).getClassNames().toString());
+        // Not enough class for a real 3rd shard, so it's a stub placeholder instead.
+        IRemoteTest shard3 = mTest.getTestShard(3, 2);
+        assertTrue(shard3 instanceof StubTest);
+    }
+}
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..02eae24 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
@@ -16,17 +16,17 @@
 
 package com.android.compatibility.common.tradefed.testtype;
 
-import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
-import com.android.compatibility.common.util.AbiUtils;
 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;
 import com.android.tradefed.testtype.IRuntimeHintProvider;
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import junit.framework.TestCase;
 
@@ -39,9 +39,6 @@
     private static final String NAME = "ModuleName";
     private static final String ABI = "mips64";
     private static final String ID = AbiUtils.createId(ABI, NAME);
-    private static final String CLASS = "android.test.FoorBar";
-    private static final String METHOD_1 = "testBlah1";
-    private static final String TEST_1 = String.format("%s#%s", CLASS, METHOD_1);
 
     public void testAccessors() throws Exception {
         IAbi abi = new Abi(ABI, "");
@@ -98,6 +95,4 @@
             // Do nothing
         }
     }
-
-    private class MockListener extends NoOpTestInvocationListener {}
 }
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 d54277b..e8cece4 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
@@ -16,28 +16,39 @@
 
 package com.android.compatibility.common.tradefed.testtype;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
 import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
-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.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;
-import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.IRuntimeHintProvider;
+import com.android.tradefed.testtype.IStrictShardableTest;
+import com.android.tradefed.testtype.ITestCollector;
+import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.FileUtil;
 
 import junit.framework.TestCase;
 
+import org.easymock.EasyMock;
+
 import java.io.File;
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
+/**
+ * Unit Tests for {@link ModuleRepo}
+ */
 public class ModuleRepoTest extends TestCase {
 
     private static final String TOKEN =
@@ -56,7 +67,7 @@
     private static final String SERIAL2 = "def";
     private static final String SERIAL3 = "ghi";
     private static final Set<String> SERIALS = new HashSet<>();
-    private static final Set<IAbi> ABIS = new HashSet<>();
+    private static final Set<IAbi> ABIS = new LinkedHashSet<>();
     private static final List<String> DEVICE_TOKENS = new ArrayList<>();
     private static final List<String> TEST_ARGS= new ArrayList<>();
     private static final List<String> MODULE_ARGS = new ArrayList<>();
@@ -103,19 +114,19 @@
         FILES.add(String.format(FILENAME, MODULE_NAME_B));
         FILES.add(String.format(FILENAME, MODULE_NAME_C));
     }
-    private IModuleRepo mRepo;
+    private ModuleRepo mRepo;
     private File mTestsDir;
-    private IBuildInfo mBuild;
+    private IBuildInfo mMockBuildInfo;
 
     @Override
     public void setUp() throws Exception {
         mTestsDir = setUpConfigs();
         mRepo = new ModuleRepo();
-        mBuild = new CompatibilityBuildProvider().getBuild();
+        mMockBuildInfo = EasyMock.createMock(IBuildInfo.class);
     }
 
     private File setUpConfigs() throws IOException {
-        File testsDir = FileUtil.createNamedTempDir("testcases");
+        File testsDir = FileUtil.createTempDir("testcases");
         createConfig(testsDir, MODULE_NAME_A, null);
         createConfig(testsDir, MODULE_NAME_B, null);
         createConfig(testsDir, MODULE_NAME_C, FOOBAR_TOKEN);
@@ -126,8 +137,12 @@
         createConfig(testsDir, name, token, TEST_STUB);
     }
 
-    private void createConfig(File testsDir, String name, String token, String moduleClass) throws IOException {
+    private void createConfig(File testsDir, String name, String token, String moduleClass)
+            throws IOException {
         File config = new File(testsDir, String.format(FILENAME, name));
+        if (!config.createNewFile()) {
+            throw new IOException(String.format("Failed to create '%s'", config.getAbsolutePath()));
+        }
         String preparer = "";
         if (token != null) {
             preparer = String.format(TOKEN, token);
@@ -137,42 +152,80 @@
 
     @Override
     public void tearDown() throws Exception {
-        tearDownConfigs(mTestsDir);
-    }
-
-    private void tearDownConfigs(File testsDir) {
-        FileUtil.recursiveDelete(testsDir);
+        FileUtil.recursiveDelete(mTestsDir);
+        mRepo.resetModuleRepo();
     }
 
     public void testInitialization() throws Exception {
-        mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+        mRepo.initialize(3, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mMockBuildInfo);
         assertTrue("Should be initialized", mRepo.isInitialized());
         assertEquals("Wrong number of shards", 3, mRepo.getNumberOfShards());
-        assertEquals("Wrong number of modules per shard", 2, mRepo.getModulesPerShard());
         Map<String, Set<String>> deviceTokens = mRepo.getDeviceTokens();
         assertEquals("Wrong number of devices with tokens", 1, deviceTokens.size());
         Set<String> tokens = deviceTokens.get(SERIAL3);
         assertEquals("Wrong number of tokens", 1, tokens.size());
         assertTrue("Unexpected device token", tokens.contains(FOOBAR_TOKEN));
-        assertEquals("Wrong number of modules", 0, mRepo.getLargeModules().size());
-        assertEquals("Wrong number of modules", 0, mRepo.getMediumModules().size());
-        assertEquals("Wrong number of modules", 4, mRepo.getSmallModules().size());
+        assertEquals("Wrong number of modules", 4, mRepo.getNonTokenModules().size());
         List<IModuleDef> tokenModules = mRepo.getTokenModules();
         assertEquals("Wrong number of modules with tokens", 2, tokenModules.size());
-        List<IModuleDef> serial1Modules = mRepo.getModules(SERIAL1);
-        assertEquals("Wrong number of modules", 2, serial1Modules.size());
-        List<IModuleDef> serial2Modules = mRepo.getModules(SERIAL2);
-        assertEquals("Wrong number of modules", 2, serial2Modules.size());
-        List<IModuleDef> serial3Modules = mRepo.getModules(SERIAL3);
-        assertEquals("Wrong number of modules", 2, serial3Modules.size());
-        // Serial 3 should have the modules with tokens
-        for (IModuleDef module : serial3Modules) {
-            assertEquals("Wrong module", MODULE_NAME_C, module.getName());
-        }
-        Set<String> serials = mRepo.getSerials();
-        assertEquals("Wrong number of serials", 3, serials.size());
-        assertTrue("Unexpected device serial", serials.containsAll(SERIALS));
+    }
+
+    public void testGetModules() throws Exception {
+        mRepo.initialize(1, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mMockBuildInfo);
+        assertTrue("Should be initialized", mRepo.isInitialized());
+        assertEquals("Wrong number of tokens", 2, mRepo.getTokenModules().size());
+        assertEquals("Wrong number of tokens", 4, mRepo.getNonTokenModules().size());
+    }
+
+    /**
+     * Test sharding with 2 shards of the 4 non token modules.
+     */
+    public void testGetModulesSharded() throws Exception {
+        mRepo.initialize(2, null, mTestsDir, ABIS, new ArrayList<String>(), TEST_ARGS, MODULE_ARGS,
+                INCLUDES, EXCLUDES, mMockBuildInfo);
+        assertTrue("Should be initialized", mRepo.isInitialized());
+        assertEquals("Wrong number of tokens", 2, mRepo.getTokenModules().size());
+        assertEquals("Wrong number of tokens", 4, mRepo.getNonTokenModules().size());
+        List<IModuleDef> shard1 = mRepo.getModules(SERIAL1, 0);
+        assertEquals(2, shard1.size());
+        assertEquals("armeabi-v7a FooModuleA", shard1.get(0).getId());
+        assertEquals("arm64-v8a FooModuleA", shard1.get(1).getId());
+        List<IModuleDef> shard2 = mRepo.getModules(SERIAL2, 1);
+        assertEquals(2, shard2.size());
+        assertEquals("armeabi-v7a FooModuleB", shard2.get(0).getId());
+        assertEquals("arm64-v8a FooModuleB", shard2.get(1).getId());
+    }
+
+    /**
+     * Test sharding with 4 shards of the 6 non token modules.
+     */
+    public void testGetModulesSharded_uneven() throws Exception {
+        createConfig(mTestsDir, "FooModuleD", null);
+        mRepo.initialize(4, null, mTestsDir, ABIS, new ArrayList<String>(), TEST_ARGS, MODULE_ARGS,
+                INCLUDES, EXCLUDES, mMockBuildInfo);
+        assertTrue("Should be initialized", mRepo.isInitialized());
+        assertEquals("Wrong number of tokens", 2, mRepo.getTokenModules().size());
+        assertEquals("Wrong number of tokens", 6, mRepo.getNonTokenModules().size());
+
+        List<IModuleDef> shard1 = mRepo.getModules(SERIAL1, 0);
+        assertEquals(1, shard1.size());
+        assertEquals("armeabi-v7a FooModuleA", shard1.get(0).getId());
+
+        List<IModuleDef> shard2 = mRepo.getModules(SERIAL2, 1);
+        assertEquals(1, shard2.size());
+        assertEquals("arm64-v8a FooModuleA", shard2.get(0).getId());
+
+        List<IModuleDef> shard3 = mRepo.getModules(SERIAL3, 2);
+        assertEquals(2, shard3.size());
+        assertEquals("armeabi-v7a FooModuleB", shard3.get(0).getId());
+        assertEquals("arm64-v8a FooModuleB", shard3.get(1).getId());
+
+        List<IModuleDef> shard4 = mRepo.getModules(SERIAL2, 3);
+        assertEquals(2, shard4.size());
+        assertEquals("armeabi-v7a FooModuleD", shard4.get(0).getId());
+        assertEquals("arm64-v8a FooModuleD", shard4.get(1).getId());
     }
 
     public void testConfigFilter() throws Exception {
@@ -190,9 +243,9 @@
         Set<String> excludeFilters = new HashSet<>();
         excludeFilters.add(ID_A_32);
         excludeFilters.add(MODULE_NAME_B);
-        mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, includeFilters,
-                excludeFilters, mBuild);
-        List<IModuleDef> modules = mRepo.getModules(SERIAL1);
+        mRepo.initialize(1, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS,
+                includeFilters, excludeFilters, mMockBuildInfo);
+        List<IModuleDef> modules = mRepo.getModules(SERIAL1, 0);
         assertEquals("Incorrect number of modules", 1, modules.size());
         IModuleDef module = modules.get(0);
         assertEquals("Incorrect ID", ID_A_64, module.getId());
@@ -200,9 +253,9 @@
     }
 
     public void testParsing() throws Exception {
-        mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
-        List<IModuleDef> modules = mRepo.getModules(SERIAL3);
+        mRepo.initialize(1, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mMockBuildInfo);
+        List<IModuleDef> modules = mRepo.getModules(SERIAL3, 0);
         Set<String> idSet = new HashSet<>();
         for (IModuleDef module : modules) {
             idSet.add(module.getId());
@@ -228,62 +281,104 @@
     }
 
     public void testSplit() throws Exception {
-        createConfig(mTestsDir, "sharder_1", null, SHARDABLE_TEST_STUB);
-        createConfig(mTestsDir, "sharder_2", null, SHARDABLE_TEST_STUB);
-        createConfig(mTestsDir, "sharder_3", null, SHARDABLE_TEST_STUB);
+        createConfig(mTestsDir, "sharded_1", null, SHARDABLE_TEST_STUB);
+        createConfig(mTestsDir, "sharded_2", null, SHARDABLE_TEST_STUB);
+        createConfig(mTestsDir, "sharded_3", null, SHARDABLE_TEST_STUB);
         Set<IAbi> abis = new HashSet<>();
         abis.add(new Abi(ABI_64, "64"));
         ArrayList<String> emptyList = new ArrayList<>();
 
-        mRepo.initialize(3, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, INCLUDES,
-                         EXCLUDES, mBuild);
+        mRepo.initialize(3, 0, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, INCLUDES,
+                         EXCLUDES, mMockBuildInfo);
 
         List<IModuleDef> modules = new ArrayList<>();
-        modules.addAll(mRepo.getLargeModules());
-        modules.addAll(mRepo.getMediumModules());
-        modules.addAll(mRepo.getSmallModules());
+        modules.addAll(mRepo.getNonTokenModules());
         modules.addAll(mRepo.getTokenModules());
 
         int shardableCount = 0;
         for (IModuleDef def : modules) {
             IRemoteTest test = def.getTest();
-            if (test instanceof IShardableTest) {
-                assertNotNull("Build not set", ((ShardableTestStub)test).mBuildInfo);
+            if (test instanceof IStrictShardableTest) {
                 shardableCount++;
             }
         }
-        assertEquals("Shards wrong", 3*3, shardableCount);
+        assertEquals("Shards wrong", 9, shardableCount);
     }
 
     public void testGetModuleIds() {
-        mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+        mRepo.initialize(3, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+                EXCLUDES, mMockBuildInfo);
         assertTrue("Should be initialized", mRepo.isInitialized());
 
         assertArrayEquals(EXPECTED_MODULE_IDS, mRepo.getModuleIds());
     }
 
-    public void testIsPrepared() {
-        mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
-        assertTrue("Should be initialized", mRepo.isInitialized());
-        mRepo.setPrepared(true);
-        mRepo.setPrepared(true);
-        mRepo.setPrepared(true); // each shard should call setPrepared() once
-        assertTrue(mRepo.isPrepared(0, TimeUnit.MINUTES));
-    }
-
-    public void testIsNotPrepared() {
-        mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
-        assertTrue("Should be initialized", mRepo.isInitialized());
-        mRepo.setPrepared(true);
-        mRepo.setPrepared(false); // mRepo should return false for setPrepared() after third call
-        mRepo.setPrepared(true);
-        assertFalse(mRepo.isPrepared(0, TimeUnit.MINUTES));
-    }
-
     private void assertArrayEquals(Object[] expected, Object[] actual) {
         assertEquals(Arrays.asList(expected), Arrays.asList(actual));
     }
+
+    /**
+     * Test class to provide runtimeHint.
+     */
+    private class TestRuntime implements IRemoteTest, IRuntimeHintProvider, IAbiReceiver,
+            ITestCollector, ITestFilterReceiver {
+        public long runtimeHint = 0l;
+        @Override
+        public long getRuntimeHint() {
+            return runtimeHint;
+        }
+        // ignore all the other calls
+        @Override
+        public void run(ITestInvocationListener arg0) throws DeviceNotAvailableException {}
+        @Override
+        public void addAllExcludeFilters(Set<String> arg0) {}
+        @Override
+        public void addAllIncludeFilters(Set<String> arg0) {}
+        @Override
+        public void addExcludeFilter(String arg0) {}
+        @Override
+        public void addIncludeFilter(String arg0) {}
+        @Override
+        public void setCollectTestsOnly(boolean arg0) {}
+        @Override
+        public void setAbi(IAbi arg0) {}
+    }
+
+    /**
+     * Balance the load of runtime of the modules for the same runtimehint everywhere.
+     */
+    public void testGetshard_allSameRuntime() throws Exception {
+        List<IModuleDef> testList = new ArrayList<>();
+        TestRuntime test1 = new TestRuntime();
+        test1.runtimeHint = 100l;
+        IModuleDef mod1 = new ModuleDef("test1", new Abi("arm", "32"), test1,
+                new ArrayList<ITargetPreparer>());
+        testList.add(mod1);
+        TestRuntime test2 = new TestRuntime();
+        test2.runtimeHint = 100l;
+        IModuleDef mod2 = new ModuleDef("test2", new Abi("arm", "32"), test2,
+                new ArrayList<ITargetPreparer>());
+        testList.add(mod2);
+        TestRuntime test3 = new TestRuntime();
+        test3.runtimeHint = 100l;
+        IModuleDef mod3 = new ModuleDef("test3", new Abi("arm", "32"), test3,
+                new ArrayList<ITargetPreparer>());
+        testList.add(mod3);
+        TestRuntime test4 = new TestRuntime();
+        test4.runtimeHint = 100l;
+        IModuleDef mod4 = new ModuleDef("test4", new Abi("arm", "32"), test4,
+                new ArrayList<ITargetPreparer>());
+        testList.add(mod4);
+        // if we don't shard everything is in one shard.
+        List<IModuleDef> res = mRepo.getShard(testList, 0, 1);
+        assertEquals(4, res.size());
+        res = mRepo.getShard(testList, 0, 2);
+        assertEquals(2, res.size());
+        assertEquals(mod1, res.get(0));
+        assertEquals(mod2, res.get(1));
+        res = mRepo.getShard(testList, 1, 2);
+        assertEquals(2, res.size());
+        assertEquals(mod3, res.get(0));
+        assertEquals(mod4, res.get(1));
+    }
 }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
index f638da8..1a63b03 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -25,18 +25,17 @@
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IRuntimeHintProvider;
 import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.IStrictShardableTest;
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFilterReceiver;
 
-import junit.framework.Assert;
-
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
 import java.util.Set;
 
 public class ShardableTestStub implements IRemoteTest, IShardableTest, IBuildReceiver,
-        IAbiReceiver, IRuntimeHintProvider, ITestCollector, ITestFilterReceiver {
+        IAbiReceiver, IRuntimeHintProvider, ITestCollector, ITestFilterReceiver,
+        IStrictShardableTest {
 
     @Option(name = "module")
     String mModule;
@@ -58,7 +57,7 @@
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     @Override
     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
@@ -70,8 +69,6 @@
      */
     @Override
     public Collection<IRemoteTest> split() {
-        Assert.assertNotNull(mBuildInfo);
-
         mShards = new ArrayList<>();
         for (int i = 0; i < 3; i++) {
             mShards.add(new ShardableTestStub());
@@ -79,6 +76,14 @@
         return mShards;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IRemoteTest getTestShard(int shardCount, int shardIndex) {
+        return new ShardableTestStub();
+    }
+
     @Override
     public void setAbi(IAbi abi) {
         // Do nothing
@@ -113,5 +118,4 @@
     public void addAllExcludeFilters(Set<String> filters) {
 
     }
-
 }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
index f6ec507..75b5df6 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
@@ -25,12 +25,14 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.HashSet;
 import java.util.Set;
 
+/**
+ * Tests for {@link SubPlan}
+ */
 public class SubPlanTest extends TestCase {
 
     private static final String ABI = "armeabi-v7a";
@@ -64,34 +66,41 @@
 
         // Serialize to file
         File subPlanFile = FileUtil.createTempFile("test-subPlan-serialization", ".txt");
-        OutputStream subPlanOutputStream = new FileOutputStream(subPlanFile);
-        subPlan.serialize(subPlanOutputStream);
-        subPlanOutputStream.close();
-
-        // Parse subPlan and assert correctness
-        checkSubPlan(subPlanFile);
-
+        try {
+            OutputStream subPlanOutputStream = new FileOutputStream(subPlanFile);
+            subPlan.serialize(subPlanOutputStream);
+            subPlanOutputStream.close();
+            // Parse subPlan and assert correctness
+            checkSubPlan(subPlanFile);
+        } finally {
+            FileUtil.deleteFile(subPlanFile);
+        }
     }
 
     public void testParsing() throws Exception {
-        File subPlanFile = FileUtil.createTempFile("test-subPlan-parsing", ".txt");
-        FileWriter writer = new FileWriter(subPlanFile);
-        Set<String> entries = new HashSet<String>();
-        entries.add(generateEntryXml(ABI, MODULE_A, TEST_1, true)); // include format 1
-        entries.add(generateEntryXml(ABI, MODULE_A, TEST_2, true));
-        entries.add(generateEntryXml(null, null,
-                new TestFilter(ABI, MODULE_A, TEST_3).toString(), true)); // include format 2
-        entries.add(generateEntryXml(null, MODULE_B, null, true));
-        entries.add(generateEntryXml(null, null,
-                new TestFilter(null, MODULE_B, TEST_1).toString(), false));
-        entries.add(generateEntryXml(null, null,
-                new TestFilter(null, MODULE_B, TEST_2).toString(), false));
-        entries.add(generateEntryXml(null, null,
-                new TestFilter(null, MODULE_B, TEST_3).toString(), false));
-        String xml = String.format(XML_BASE, String.join("\n", entries));
-        writer.write(xml);
-        writer.flush();
-        checkSubPlan(subPlanFile);
+        File planFile = FileUtil.createTempFile("test-plan-parsing", ".txt");
+        FileWriter writer = new FileWriter(planFile);
+        try {
+            Set<String> entries = new HashSet<String>();
+            entries.add(generateEntryXml(ABI, MODULE_A, TEST_1, true)); // include format 1
+            entries.add(generateEntryXml(ABI, MODULE_A, TEST_2, true));
+            entries.add(generateEntryXml(null, null,
+                    new TestFilter(ABI, MODULE_A, TEST_3).toString(), true)); // include format 2
+            entries.add(generateEntryXml(null, MODULE_B, null, true));
+            entries.add(generateEntryXml(null, null,
+                    new TestFilter(null, MODULE_B, TEST_1).toString(), false));
+            entries.add(generateEntryXml(null, null,
+                    new TestFilter(null, MODULE_B, TEST_2).toString(), false));
+            entries.add(generateEntryXml(null, null,
+                    new TestFilter(null, MODULE_B, TEST_3).toString(), false));
+            String xml = String.format(XML_BASE, String.join("\n", entries));
+            writer.write(xml);
+            writer.flush();
+            checkSubPlan(planFile);
+        } finally {
+            writer.close();
+            FileUtil.deleteFile(planFile);
+        }
     }
 
     private void checkSubPlan(File subPlanFile) throws Exception {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
index 729fda2..dbd7d30 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
@@ -20,14 +20,11 @@
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IRuntimeHintProvider;
-import com.android.tradefed.testtype.IShardableTest;
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFilterReceiver;
 
-import java.util.List;
 import java.util.Set;
 
 public class TestStub implements IRemoteTest, IAbiReceiver, IRuntimeHintProvider, ITestCollector,
diff --git a/common/host-side/util/Android.mk b/common/host-side/util/Android.mk
index 5f5fb6f..771e334 100644
--- a/common/host-side/util/Android.mk
+++ b/common/host-side/util/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-hostsidelib jsonlib
 
-LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed
 
 LOCAL_MODULE := compatibility-host-util
 
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
deleted file mode 100644
index faac61f..0000000
--- a/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compatibility.common.util;
-
-import com.android.annotations.Nullable;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.hash.BloomFilter;
-import com.google.common.hash.Funnels;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInput;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutput;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.security.DigestException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.HashMap;
-
-/***
- * Calculate and store checksum values for files and test results
- */
-public final class ChecksumReporter implements Serializable {
-
-    public static final String NAME = "checksum.data";
-    public static final String PREV_NAME = "checksum.previous.data";
-
-    private static final double DEFAULT_FPP = 0.05;
-    private static final String SEPARATOR = "/";
-    private static final String ID_SEPARATOR = "@";
-    private static final String NAME_SEPARATOR = ".";
-
-    private static final short CURRENT_VERSION = 1;
-    // Serialized format Id (ie magic number) used to identify serialized data.
-    static final short SERIALIZED_FORMAT_CODE = 650;
-
-    private final BloomFilter<CharSequence> mResultChecksum;
-    private final HashMap<String, byte[]> mFileChecksum;
-    private final short mVersion;
-
-    /***
-     * Calculate checksum of test results and files in result directory and write to disk
-     * @param dir test results directory
-     * @param result test results
-     * @return true if successful, false if unable to calculate or store the checksum
-     */
-    public static boolean tryCreateChecksum(File dir, IInvocationResult result) {
-        try {
-            int totalCount = countTestResults(result);
-            ChecksumReporter checksumReporter =
-                    new ChecksumReporter(totalCount, DEFAULT_FPP, CURRENT_VERSION);
-            checksumReporter.addInvocation(result);
-            checksumReporter.addDirectory(dir);
-            checksumReporter.saveToFile(dir);
-        } catch (Exception e) {
-            return false;
-        }
-        return true;
-    }
-
-    /***
-     * Create Checksum Reporter from data saved on disk
-     * @param directory
-     * @return
-     * @throws ChecksumValidationException
-     */
-    public static ChecksumReporter load(File directory) throws ChecksumValidationException {
-        ChecksumReporter reporter = new ChecksumReporter(directory);
-        if (reporter.getCapacity() > 1.1) {
-            throw new ChecksumValidationException("Capacity exceeded.");
-        }
-        return reporter;
-    }
-
-    /***
-     * Deserialize checksum from file
-     * @param directory the parent directory containing the checksum file
-     * @throws ChecksumValidationException
-     */
-    public ChecksumReporter(File directory) throws ChecksumValidationException {
-        File file = new File(directory, ChecksumReporter.NAME);
-        try (FileInputStream fileStream = new FileInputStream(file);
-            InputStream outputStream = new BufferedInputStream(fileStream);
-            ObjectInput objectInput = new ObjectInputStream(outputStream)) {
-            short magicNumber = objectInput.readShort();
-            switch (magicNumber) {
-                case SERIALIZED_FORMAT_CODE:
-                   mVersion = objectInput.readShort();
-                    mResultChecksum = (BloomFilter<CharSequence>) objectInput.readObject();
-                    mFileChecksum = (HashMap<String, byte[]>) objectInput.readObject();
-                    break;
-                default:
-                    throw new ChecksumValidationException("Unknown format of serialized data.");
-            }
-        } catch (Exception e) {
-            throw new ChecksumValidationException("Unable to load checksum from file", e);
-        }
-        if (mVersion > CURRENT_VERSION) {
-            throw new ChecksumValidationException(
-                    "File contains a newer version of ChecksumReporter");
-        }
-    }
-
-    /***
-     * Create new instance of ChecksumReporter
-     * @param testCount the number of test results that will be stored
-     * @param fpp the false positive percentage for result lookup misses
-     */
-    public ChecksumReporter(int testCount, double fpp, short version) {
-        mResultChecksum = BloomFilter.create(Funnels.unencodedCharsFunnel(),
-                testCount, fpp);
-        mFileChecksum = new HashMap<>();
-        mVersion = version;
-    }
-
-    /***
-     * Add each test result from each module and test case
-     */
-    public void addInvocation(IInvocationResult invocationResult) {
-        for (IModuleResult module : invocationResult.getModules()) {
-            String buildFingerprint = invocationResult.getBuildFingerprint();
-            addModuleResult(module, buildFingerprint);
-            for (ICaseResult caseResult : module.getResults()) {
-                for (ITestResult testResult : caseResult.getResults()) {
-                    addTestResult(testResult, module, buildFingerprint);
-                }
-            }
-        }
-    }
-
-    /***
-     * Calculate CRC of file and store the result
-     * @param file crc calculated on this file
-     * @param path part of the key to identify the files crc
-     */
-    public void addFile(File file, String path) {
-        byte[] crc;
-        try {
-            crc = calculateFileChecksum(file);
-        } catch (ChecksumValidationException e) {
-            crc = new byte[0];
-        }
-        String key = path + SEPARATOR + file.getName();
-        mFileChecksum.put(key, crc);
-    }
-
-    @VisibleForTesting
-    public boolean containsFile(File file, String path) {
-        String key = path + SEPARATOR + file.getName();
-        if (mFileChecksum.containsKey(key))
-        {
-            try {
-                byte[] crc = calculateFileChecksum(file);
-                return Arrays.equals(mFileChecksum.get(key), crc);
-            } catch (ChecksumValidationException e) {
-                return false;
-            }
-        }
-        return false;
-    }
-
-    /***
-     * Adds all child files recursively through all sub directories
-     * @param directory target that is deeply searched for files
-     */
-    public void addDirectory(File directory) {
-        addDirectory(directory, directory.getName());
-    }
-
-    /***
-     * @param path the relative path to the current directory from the base directory
-     */
-    private void addDirectory(File directory, String path) {
-        for(String childName : directory.list()) {
-            File child = new File(directory, childName);
-            if (child.isDirectory()) {
-                addDirectory(child, path + SEPARATOR + child.getName());
-            } else {
-                addFile(child, path);
-            }
-        }
-    }
-
-    /***
-     * Calculate checksum of test result and store the value
-     * @param testResult the target of the checksum
-     * @param moduleResult the module that contains the test result
-     * @param buildFingerprint the fingerprint the test execution is running against
-     */
-    public void addTestResult(
-        ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
-
-        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
-        mResultChecksum.put(signature);
-    }
-
-    @VisibleForTesting
-    public boolean containsTestResult(
-            ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
-
-        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
-        return mResultChecksum.mightContain(signature);
-    }
-
-    /***
-     * Calculate checksm of module result and store value
-     * @param moduleResult  the target of the checksum
-     * @param buildFingerprint the fingerprint the test execution is running against
-     */
-    public void addModuleResult(IModuleResult moduleResult, String buildFingerprint) {
-        mResultChecksum.put(
-                generateModuleResultSignature(moduleResult, buildFingerprint));
-        mResultChecksum.put(
-                generateModuleSummarySignature(moduleResult, buildFingerprint));
-    }
-
-    @VisibleForTesting
-    public Boolean containsModuleResult(IModuleResult moduleResult, String buildFingerprint) {
-        return mResultChecksum.mightContain(
-                generateModuleResultSignature(moduleResult, buildFingerprint));
-    }
-
-    /***
-     * Write the checksum data to disk.
-     * Overwrites existing file
-     * @param directory
-     * @throws IOException
-     */
-    public void saveToFile(File directory) throws IOException {
-        File file = new File(directory, NAME);
-
-        try (FileOutputStream fileStream = new FileOutputStream(file, false);
-             OutputStream outputStream = new BufferedOutputStream(fileStream);
-             ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) {
-            objectOutput.writeShort(SERIALIZED_FORMAT_CODE);
-            objectOutput.writeShort(mVersion);
-            objectOutput.writeObject(mResultChecksum);
-            objectOutput.writeObject(mFileChecksum);
-        }
-    }
-
-    @VisibleForTesting
-    double getCapacity() {
-        // If default FPP changes:
-        // increment the CURRENT_VERSION and set the denominator based on this.mVersion
-        return mResultChecksum.expectedFpp() / DEFAULT_FPP;
-    }
-
-    static String generateTestResultSignature(ITestResult testResult, IModuleResult module,
-            String buildFingerprint) {
-        StringBuilder sb = new StringBuilder();
-        String stacktrace = testResult.getStackTrace();
-
-        stacktrace = stacktrace == null ? "" : stacktrace.trim();
-        // Line endings for stacktraces are somewhat unpredictable and there is no need to
-        // actually read the result they are all removed for consistency.
-        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
-        sb.append(buildFingerprint).append(SEPARATOR)
-                .append(module.getId()).append(SEPARATOR)
-                .append(testResult.getFullName()).append(SEPARATOR)
-                .append(testResult.getResultStatus().getValue()).append(SEPARATOR)
-                .append(stacktrace).append(SEPARATOR);
-        return sb.toString();
-    }
-
-    static String generateTestResultSignature(
-            String packageName, String suiteName, String caseName, String testName, String abi,
-            String status,
-            String stacktrace,
-            String buildFingerprint) {
-
-        String testId = buildTestId(suiteName, caseName, testName, abi);
-        StringBuilder sb = new StringBuilder();
-
-        stacktrace = stacktrace == null ? "" : stacktrace.trim();
-        // Line endings for stacktraces are somewhat unpredictable and there is no need to
-        // actually read the result they are all removed for consistency.
-        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
-        sb.append(buildFingerprint)
-                .append(SEPARATOR)
-                .append(packageName)
-                .append(SEPARATOR)
-                .append(testId)
-                .append(SEPARATOR)
-                .append(status)
-                .append(SEPARATOR)
-                .append(stacktrace)
-                .append(SEPARATOR);
-        return sb.toString();
-    }
-
-    private static String buildTestId(
-            String suiteName, String caseName, String testName, @Nullable String abi) {
-        String name = Joiner.on(NAME_SEPARATOR).skipNulls().join(
-                Strings.emptyToNull(suiteName),
-                Strings.emptyToNull(caseName),
-                Strings.emptyToNull(testName));
-        return Joiner.on(ID_SEPARATOR).skipNulls().join(
-                Strings.emptyToNull(name),
-                Strings.emptyToNull(abi));
-    }
-
-
-    private static String generateModuleResultSignature(IModuleResult module,
-            String buildFingerprint) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(buildFingerprint).append(SEPARATOR)
-                .append(module.getId()).append(SEPARATOR)
-                .append(module.isDone()).append(SEPARATOR)
-                .append(module.getNotExecuted()).append(SEPARATOR)
-                .append(module.countResults(TestStatus.FAIL));
-        return sb.toString();
-    }
-
-    private static String generateModuleSummarySignature(IModuleResult module,
-            String buildFingerprint) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(buildFingerprint).append(SEPARATOR)
-                .append(module.getId()).append(SEPARATOR)
-                .append(module.countResults(TestStatus.FAIL));
-        return sb.toString();
-    }
-
-    static byte[] calculateFileChecksum(File file) throws ChecksumValidationException {
-
-        try (FileInputStream fis = new FileInputStream(file);
-             InputStream inputStream = new BufferedInputStream(fis)) {
-            MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
-            int cnt;
-            int bufferSize = 8192;
-            byte [] buffer = new byte[bufferSize];
-            while ((cnt = inputStream.read(buffer)) != -1) {
-                hashSum.update(buffer, 0, cnt);
-            }
-
-            byte[] partialHash = new byte[32];
-            hashSum.digest(partialHash, 0, 32);
-            return partialHash;
-        } catch (NoSuchAlgorithmException e) {
-            throw new ChecksumValidationException("Unable to hash file.", e);
-        } catch (IOException e) {
-            throw new ChecksumValidationException("Unable to hash file.", e);
-        } catch (DigestException e) {
-            throw new ChecksumValidationException("Unable to hash file.", e);
-        }
-    }
-
-
-    private static int countTestResults(IInvocationResult invocation) {
-        int count = 0;
-        for (IModuleResult module : invocation.getModules()) {
-            // Two entries per module (result & summary)
-            count += 2;
-            for (ICaseResult caseResult : module.getResults()) {
-                count += caseResult.getResults().size();
-            }
-        }
-        return count;
-    }
-
-    public static class ChecksumValidationException extends Exception {
-        public ChecksumValidationException(String detailMessage) {
-            super(detailMessage);
-        }
-
-        public ChecksumValidationException(String detailMessage, Throwable throwable) {
-            super(detailMessage, throwable);
-        }
-    }
-}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
deleted file mode 100644
index c2c717d..0000000
--- a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ /dev/null
@@ -1,516 +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.util;
-
-import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
-
-import com.google.common.base.Strings;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * Handles conversion of results to/from files.
- */
-public class ResultHandler {
-
-    private static final String ENCODING = "UTF-8";
-    private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
-    private static final String NS = null;
-    private static final String RESULT_FILE_VERSION = "5.0";
-    /* package */ static final String TEST_RESULT_FILE_NAME = "test_result.xml";
-
-    // XML constants
-    private static final String ABI_ATTR = "abi";
-    private static final String BUGREPORT_TAG = "BugReport";
-    private static final String BUILD_FINGERPRINT = "build_fingerprint";
-    private static final String BUILD_ID = "build_id";
-    private static final String BUILD_PRODUCT = "build_product";
-    private static final String BUILD_TAG = "Build";
-    private static final String CASE_TAG = "TestCase";
-    private static final String COMMAND_LINE_ARGS = "command_line_args";
-    private static final String DEVICES_ATTR = "devices";
-    private static final String DONE_ATTR = "done";
-    private static final String END_DISPLAY_TIME_ATTR = "end_display";
-    private static final String END_TIME_ATTR = "end";
-    private static final String FAILED_ATTR = "failed";
-    private static final String FAILURE_TAG = "Failure";
-    private static final String HOST_NAME_ATTR = "host_name";
-    private static final String JAVA_VENDOR_ATTR = "java_vendor";
-    private static final String JAVA_VERSION_ATTR = "java_version";
-    private static final String LOGCAT_TAG = "Logcat";
-    private static final String LOG_URL_ATTR = "log_url";
-    private static final String MESSAGE_ATTR = "message";
-    private static final String MODULE_TAG = "Module";
-    private static final String MODULES_EXECUTED_ATTR = "modules_done";
-    private static final String MODULES_TOTAL_ATTR = "modules_total";
-    private static final String NAME_ATTR = "name";
-    private static final String NOT_EXECUTED_ATTR = "not_executed";
-    private static final String OS_ARCH_ATTR = "os_arch";
-    private static final String OS_NAME_ATTR = "os_name";
-    private static final String OS_VERSION_ATTR = "os_version";
-    private static final String PASS_ATTR = "pass";
-    private static final String REPORT_VERSION_ATTR = "report_version";
-    private static final String REFERENCE_URL_ATTR = "reference_url";
-    private static final String RESULT_ATTR = "result";
-    private static final String RESULT_TAG = "Result";
-    private static final String RUNTIME_ATTR = "runtime";
-    private static final String SCREENSHOT_TAG = "Screenshot";
-    private static final String STACK_TAG = "StackTrace";
-    private static final String START_DISPLAY_TIME_ATTR = "start_display";
-    private static final String START_TIME_ATTR = "start";
-    private static final String SUITE_NAME_ATTR = "suite_name";
-    private static final String SUITE_PLAN_ATTR = "suite_plan";
-    private static final String SUITE_VERSION_ATTR = "suite_version";
-    private static final String SUITE_BUILD_ATTR = "suite_build_number";
-    private static final String SUMMARY_TAG = "Summary";
-    private static final String TEST_TAG = "Test";
-
-    /**
-     * @param resultsDir
-     */
-    public static List<IInvocationResult> getResults(File resultsDir) {
-        return getResults(resultsDir, false);
-    }
-
-    /**
-     * @param resultsDir
-     * @param useChecksum
-     */
-    public static List<IInvocationResult> getResults(
-            File resultsDir, Boolean useChecksum) {
-        List<IInvocationResult> results = new ArrayList<>();
-        List<File> files = getResultDirectories(resultsDir);;
-        for (File resultDir : files) {
-            if (!resultDir.isDirectory()) {
-                continue;
-            }
-            try {
-                File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
-                if (!resultFile.exists()) {
-                    continue;
-                }
-                Boolean invocationUseChecksum = useChecksum;
-                IInvocationResult invocation = new InvocationResult();
-                invocation.setRetryDirectory(resultDir);
-                ChecksumReporter checksumReporter = null;
-                if (invocationUseChecksum) {
-                    try {
-                        checksumReporter = ChecksumReporter.load(resultDir);
-                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithChecksum);
-                    } catch (ChecksumValidationException e) {
-                        // Unable to read checksum form previous execution
-                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithoutChecksum);
-                        invocationUseChecksum = false;
-                    }
-                }
-                XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
-                XmlPullParser parser = factory.newPullParser();
-                parser.setInput(new FileReader(resultFile));
-
-                parser.nextTag();
-                parser.require(XmlPullParser.START_TAG, NS, RESULT_TAG);
-                invocation.setStartTime(Long.valueOf(
-                        parser.getAttributeValue(NS, START_TIME_ATTR)));
-                invocation.setTestPlan(parser.getAttributeValue(NS, SUITE_PLAN_ATTR));
-                invocation.setCommandLineArgs(parser.getAttributeValue(NS, COMMAND_LINE_ARGS));
-                String deviceList = parser.getAttributeValue(NS, DEVICES_ATTR);
-                for (String device : deviceList.split(",")) {
-                    invocation.addDeviceSerial(device);
-                }
-
-                parser.nextTag();
-                parser.require(XmlPullParser.START_TAG, NS, BUILD_TAG);
-                invocation.addInvocationInfo(BUILD_ID, parser.getAttributeValue(NS, BUILD_ID));
-                invocation.addInvocationInfo(BUILD_PRODUCT, parser.getAttributeValue(NS,
-                        BUILD_PRODUCT));
-                invocation.setBuildFingerprint(parser.getAttributeValue(NS, BUILD_FINGERPRINT));
-
-                // TODO(stuartscott): may want to reload these incase the retry was done with
-                // --skip-device-info flag
-                parser.nextTag();
-                parser.require(XmlPullParser.END_TAG, NS, BUILD_TAG);
-                parser.nextTag();
-                parser.require(XmlPullParser.START_TAG, NS, SUMMARY_TAG);
-                parser.nextTag();
-                parser.require(XmlPullParser.END_TAG, NS, SUMMARY_TAG);
-                while (parser.nextTag() == XmlPullParser.START_TAG) {
-                    parser.require(XmlPullParser.START_TAG, NS, MODULE_TAG);
-                    String name = parser.getAttributeValue(NS, NAME_ATTR);
-                    String abi = parser.getAttributeValue(NS, ABI_ATTR);
-                    String moduleId = AbiUtils.createId(abi, name);
-                    boolean done = Boolean.parseBoolean(parser.getAttributeValue(NS, DONE_ATTR));
-                    IModuleResult module = invocation.getOrCreateModule(moduleId);
-                    module.setDone(done);
-                    int notExecuted =
-                            Integer.parseInt(parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
-                    module.setNotExecuted(notExecuted);
-                    long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
-                    module.addRuntime(runtime);
-                    while (parser.nextTag() == XmlPullParser.START_TAG) {
-                        parser.require(XmlPullParser.START_TAG, NS, CASE_TAG);
-                        String caseName = parser.getAttributeValue(NS, NAME_ATTR);
-                        ICaseResult testCase = module.getOrCreateResult(caseName);
-                        while (parser.nextTag() == XmlPullParser.START_TAG) {
-                            parser.require(XmlPullParser.START_TAG, NS, TEST_TAG);
-                            String testName = parser.getAttributeValue(NS, NAME_ATTR);
-                            ITestResult test = testCase.getOrCreateResult(testName);
-                            String result = parser.getAttributeValue(NS, RESULT_ATTR);
-                            test.setResultStatus(TestStatus.getStatus(result));
-                            test.setRetry(true);
-                            while (parser.nextTag() == XmlPullParser.START_TAG) {
-                                if (parser.getName().equals(FAILURE_TAG)) {
-                                    test.setMessage(parser.getAttributeValue(NS, MESSAGE_ATTR));
-                                    if (parser.nextTag() == XmlPullParser.START_TAG) {
-                                        parser.require(XmlPullParser.START_TAG, NS, STACK_TAG);
-                                        test.setStackTrace(parser.nextText());
-                                        parser.require(XmlPullParser.END_TAG, NS, STACK_TAG);
-                                        parser.nextTag();
-                                    }
-                                    parser.require(XmlPullParser.END_TAG, NS, FAILURE_TAG);
-                                } else if (parser.getName().equals(BUGREPORT_TAG)) {
-                                    test.setBugReport(parser.nextText());
-                                    parser.require(XmlPullParser.END_TAG, NS, BUGREPORT_TAG);
-                                } else if (parser.getName().equals(LOGCAT_TAG)) {
-                                    test.setLog(parser.nextText());
-                                    parser.require(XmlPullParser.END_TAG, NS, LOGCAT_TAG);
-                                } else if (parser.getName().equals(SCREENSHOT_TAG)) {
-                                    test.setScreenshot(parser.nextText());
-                                    parser.require(XmlPullParser.END_TAG, NS, SCREENSHOT_TAG);
-                                } else {
-                                    test.setReportLog(ReportLog.parse(parser));
-                                }
-                            }
-                            parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
-                            Boolean checksumMismatch = invocationUseChecksum
-                                    && !checksumReporter.containsTestResult(
-                                    test, module, invocation.getBuildFingerprint());
-                            if (checksumMismatch) {
-                                test.removeResult();
-                            }
-                        }
-                        parser.require(XmlPullParser.END_TAG, NS, CASE_TAG);
-                    }
-                    parser.require(XmlPullParser.END_TAG, NS, MODULE_TAG);
-                    Boolean checksumMismatch = invocationUseChecksum
-                            && !checksumReporter.containsModuleResult(
-                            module, invocation.getBuildFingerprint());
-                    if (checksumMismatch) {
-                        module.setDone(false);
-                    }
-                }
-                parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
-                results.add(invocation);
-            } catch (XmlPullParserException e) {
-                e.printStackTrace();
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-        // Sort the table entries on each entry's timestamp.
-        Collections.sort(results, new Comparator<IInvocationResult>() {
-            public int compare(IInvocationResult result1, IInvocationResult result2) {
-                return Long.compare(result1.getStartTime(), result2.getStartTime());
-            }
-        });
-        return results;
-    }
-
-    /**
-     * @param result
-     * @param resultDir
-     * @param startTime
-     * @param referenceUrl A nullable string that can contain a URL to a related data
-     * @param logUrl A nullable string that can contain a URL to related log files
-     * @param commandLineArgs A string containing the arguments to the run command
-     * @return The result file created.
-     * @throws IOException
-     * @throws XmlPullParserException
-     */
-    public static File writeResults(String suiteName, String suiteVersion, String suitePlan,
-            String suiteBuild, IInvocationResult result, File resultDir,
-            long startTime, long endTime, String referenceUrl, String logUrl,
-            String commandLineArgs)
-                    throws IOException, XmlPullParserException {
-        int passed = result.countResults(TestStatus.PASS);
-        int failed = result.countResults(TestStatus.FAIL);
-        int notExecuted = result.getNotExecuted();
-        File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
-        OutputStream stream = new FileOutputStream(resultFile);
-        XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
-        serializer.setOutput(stream, ENCODING);
-        serializer.startDocument(ENCODING, false);
-        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-        serializer.processingInstruction(
-                "xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"");
-        serializer.startTag(NS, RESULT_TAG);
-        serializer.attribute(NS, START_TIME_ATTR, String.valueOf(startTime));
-        serializer.attribute(NS, END_TIME_ATTR, String.valueOf(endTime));
-        serializer.attribute(NS, START_DISPLAY_TIME_ATTR, toReadableDateString(startTime));
-        serializer.attribute(NS, END_DISPLAY_TIME_ATTR, toReadableDateString(endTime));
-
-        serializer.attribute(NS, SUITE_NAME_ATTR, suiteName);
-        serializer.attribute(NS, SUITE_VERSION_ATTR, suiteVersion);
-        serializer.attribute(NS, SUITE_PLAN_ATTR, suitePlan);
-        serializer.attribute(NS, SUITE_BUILD_ATTR, suiteBuild);
-        serializer.attribute(NS, REPORT_VERSION_ATTR, RESULT_FILE_VERSION);
-        serializer.attribute(NS, COMMAND_LINE_ARGS, nullToEmpty(commandLineArgs));
-
-        if (referenceUrl != null) {
-            serializer.attribute(NS, REFERENCE_URL_ATTR, referenceUrl);
-        }
-
-        if (logUrl != null) {
-            serializer.attribute(NS, LOG_URL_ATTR, logUrl);
-        }
-
-        // Device Info
-        Set<String> devices = result.getDeviceSerials();
-        StringBuilder deviceList = new StringBuilder();
-        boolean first = true;
-        for (String device : devices) {
-            if (first) {
-                first = false;
-            } else {
-                deviceList.append(",");
-            }
-            deviceList.append(device);
-        }
-        serializer.attribute(NS, DEVICES_ATTR, deviceList.toString());
-
-        // Host Info
-        String hostName = "";
-        try {
-            hostName = InetAddress.getLocalHost().getHostName();
-        } catch (UnknownHostException ignored) {}
-        serializer.attribute(NS, HOST_NAME_ATTR, hostName);
-        serializer.attribute(NS, OS_NAME_ATTR, System.getProperty("os.name"));
-        serializer.attribute(NS, OS_VERSION_ATTR, System.getProperty("os.version"));
-        serializer.attribute(NS, OS_ARCH_ATTR, System.getProperty("os.arch"));
-        serializer.attribute(NS, JAVA_VENDOR_ATTR, System.getProperty("java.vendor"));
-        serializer.attribute(NS, JAVA_VERSION_ATTR, System.getProperty("java.version"));
-
-        // Build Info
-        serializer.startTag(NS, BUILD_TAG);
-        for (Entry<String, String> entry : result.getInvocationInfo().entrySet()) {
-            serializer.attribute(NS, entry.getKey(), entry.getValue());
-            if (Strings.isNullOrEmpty(result.getBuildFingerprint()) &&
-                    entry.getKey().equals(BUILD_FINGERPRINT)) {
-                result.setBuildFingerprint(entry.getValue());
-            }
-        }
-        serializer.endTag(NS, BUILD_TAG);
-
-        // Summary
-        serializer.startTag(NS, SUMMARY_TAG);
-        serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
-        serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
-        serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
-        serializer.attribute(NS, MODULES_EXECUTED_ATTR,
-                Integer.toString(result.getModuleCompleteCount()));
-        serializer.attribute(NS, MODULES_TOTAL_ATTR,
-                Integer.toString(result.getModules().size()));
-        serializer.endTag(NS, SUMMARY_TAG);
-
-        // Results
-        for (IModuleResult module : result.getModules()) {
-            serializer.startTag(NS, MODULE_TAG);
-            serializer.attribute(NS, NAME_ATTR, module.getName());
-            serializer.attribute(NS, ABI_ATTR, module.getAbi());
-            serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
-            serializer.attribute(NS, DONE_ATTR, Boolean.toString(module.isDone()));
-            serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(module.getNotExecuted()));
-            for (ICaseResult cr : module.getResults()) {
-                serializer.startTag(NS, CASE_TAG);
-                serializer.attribute(NS, NAME_ATTR, cr.getName());
-                for (ITestResult r : cr.getResults()) {
-                    TestStatus status = r.getResultStatus();
-                    if (status == null) {
-                        continue; // test was not executed, don't report
-                    }
-                    serializer.startTag(NS, TEST_TAG);
-                    serializer.attribute(NS, RESULT_ATTR, status.getValue());
-                    serializer.attribute(NS, NAME_ATTR, r.getName());
-                    String message = r.getMessage();
-                    if (message != null) {
-                        serializer.startTag(NS, FAILURE_TAG);
-                        serializer.attribute(NS, MESSAGE_ATTR, message);
-                        String stackTrace = r.getStackTrace();
-                        if (stackTrace != null) {
-                            serializer.startTag(NS, STACK_TAG);
-                            serializer.text(stackTrace);
-                            serializer.endTag(NS, STACK_TAG);
-                        }
-                        serializer.endTag(NS, FAILURE_TAG);
-                    }
-                    String bugreport = r.getBugReport();
-                    if (bugreport != null) {
-                        serializer.startTag(NS, BUGREPORT_TAG);
-                        serializer.text(bugreport);
-                        serializer.endTag(NS, BUGREPORT_TAG);
-                    }
-                    String logcat = r.getLog();
-                    if (logcat != null) {
-                        serializer.startTag(NS, LOGCAT_TAG);
-                        serializer.text(logcat);
-                        serializer.endTag(NS, LOGCAT_TAG);
-                    }
-                    String screenshot = r.getScreenshot();
-                    if (screenshot != null) {
-                        serializer.startTag(NS, SCREENSHOT_TAG);
-                        serializer.text(screenshot);
-                        serializer.endTag(NS, SCREENSHOT_TAG);
-                    }
-                    ReportLog report = r.getReportLog();
-                    if (report != null) {
-                        ReportLog.serialize(serializer, report);
-                    }
-                    serializer.endTag(NS, TEST_TAG);
-                }
-                serializer.endTag(NS, CASE_TAG);
-            }
-            serializer.endTag(NS, MODULE_TAG);
-        }
-        serializer.endDocument();
-        createChecksum(resultDir, result);
-        return resultFile;
-    }
-
-    private static void createChecksum(File resultDir, IInvocationResult invocationResult) {
-        RetryChecksumStatus retryStatus = invocationResult.getRetryChecksumStatus();
-        switch (retryStatus) {
-            case NotRetry: case RetryWithChecksum:
-                // Do not disrupt the process if there is a problem generating checksum.
-                ChecksumReporter.tryCreateChecksum(resultDir, invocationResult);
-                break;
-            case RetryWithoutChecksum:
-                // If the previous run has an invalid checksum file,
-                // copy it into current results folder for future troubleshooting
-                File retryDirectory = invocationResult.getRetryDirectory();
-                Path retryChecksum = FileSystems.getDefault().getPath(
-                        retryDirectory.getAbsolutePath(), ChecksumReporter.NAME);
-                if (!retryChecksum.toFile().exists()) {
-                    // if no checksum file, check for a copy from a previous retry
-                    retryChecksum = FileSystems.getDefault().getPath(
-                            retryDirectory.getAbsolutePath(), ChecksumReporter.PREV_NAME);
-                }
-
-                if (retryChecksum.toFile().exists()) {
-                    File checksumCopy = new File(resultDir, ChecksumReporter.PREV_NAME);
-                    try (FileOutputStream stream = new FileOutputStream(checksumCopy)) {
-                        Files.copy(retryChecksum, stream);
-                    } catch (IOException e) {
-                        // Do not disrupt the process if there is a problem copying checksum
-                    }
-                }
-        }
-    }
-
-    /**
-     * Find the IInvocationResult for the given sessionId.
-     */
-    public static IInvocationResult findResult(File resultsDir, Integer sessionId)
-            throws FileNotFoundException {
-        return findResult(resultsDir, sessionId, true);
-    }
-
-    /**
-     * Find the IInvocationResult for the given sessionId.
-     */
-    private static IInvocationResult findResult(
-            File resultsDir, Integer sessionId, Boolean useChecksum) throws FileNotFoundException {
-        if (sessionId < 0) {
-            throw new IllegalArgumentException(
-                String.format("Invalid session id [%d] ", sessionId));
-        }
-
-        List<IInvocationResult> results = getResults(resultsDir, useChecksum);
-        if (results == null || sessionId >= results.size()) {
-            throw new RuntimeException(String.format("Could not find session [%d]", sessionId));
-        }
-        return results.get(sessionId);
-    }
-
-    /**
-     * Get a list of child directories that contain test invocation results
-     * @param resultsDir the root test result directory
-     * @return
-     */
-    public static List<File> getResultDirectories(File resultsDir) {
-        List<File> directoryList = new ArrayList<>();
-        File[] files = resultsDir.listFiles();
-        if (files == null || files.length == 0) {
-            // No results, just return the empty list
-            return directoryList;
-        }
-        for (File resultDir : files) {
-            if (!resultDir.isDirectory()) {
-                continue;
-            }
-            // Only include if it contain results file
-            File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
-            if (!resultFile.exists()) {
-                continue;
-            }
-            directoryList.add(resultDir);
-        }
-        Collections.sort(directoryList, (d1, d2) -> d1.getName().compareTo(d2.getName()));
-        return directoryList;
-    }
-
-    /**
-     * Return the given time as a {@link String} suitable for displaying.
-     * <p/>
-     * Example: Fri Aug 20 15:13:03 PDT 2010
-     *
-     * @param time the epoch time in ms since midnight Jan 1, 1970
-     */
-    static String toReadableDateString(long time) {
-        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
-        return dateFormat.format(new Date(time));
-    }
-
-    /**
-     * When nullable is null, return an empty string. Otherwise, return the value in nullable.
-     */
-    private static String nullToEmpty(String nullable) {
-        return nullable == null ? "" : nullable;
-    }
-}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/TestFilter.java b/common/host-side/util/src/com/android/compatibility/common/util/TestFilter.java
new file mode 100644
index 0000000..c9220a4
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/TestFilter.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import com.android.tradefed.util.AbiUtils;
+
+/**
+ * Represents a filter for including and excluding tests.
+ */
+public class TestFilter {
+
+    private final String mAbi;
+    private final String mName;
+    private final String mTest;
+
+    /**
+     * Builds a new {@link TestFilter} from the given string. Filters can be in one of four forms,
+     * the instance will be initialized as;
+     * -"name"                 -> abi = null, name = "name", test = null
+     * -"name" "test..."       -> abi = null, name = "name", test = "test..."
+     * -"abi" "name"           -> abi = "abi", name = "name", test = null
+     * -"abi" "name" "test..." -> abi = "abi", name = "name", test = "test..."
+     *
+     * Test identifier can contain multiple parts, eg parameterized tests.
+     *
+     * @param filter the filter to parse
+     * @return the {@link TestFilter}
+     */
+    public static TestFilter createFrom(String filter) {
+        if (filter.isEmpty()) {
+            throw new IllegalArgumentException("Filter was empty");
+        }
+        String[] parts = filter.split(" ");
+        String abi = null, name = null, test = null;
+        // Either:
+        // <name>
+        // <name> <test>
+        // <abi> <name>
+        // <abi> <name> <test>
+        if (parts.length == 1) {
+            name = parts[0];
+        } else {
+            int index = 0;
+            if (AbiUtils.isAbiSupportedByCompatibility(parts[0])) {
+                abi = parts[0];
+                index++;
+            }
+            name = parts[index];
+            index++;
+            parts = filter.split(" ", index + 1);
+            if (parts.length > index) {
+                test = parts[index];
+            }
+        }
+        return new TestFilter(abi, name, test);
+    }
+
+    /**
+     * Creates a new {@link TestFilter} from the given parts.
+     *
+     * @param abi The ABI must be supported {@link AbiUtils#isAbiSupportedByCompatibility(String)}
+     * @param name The module's name
+     * @param test The test's identifier eg <package>.<class>#<method>
+     */
+    public TestFilter(String abi, String name, String test) {
+        mAbi = abi;
+        mName = name;
+        mTest = test;
+    }
+
+    /**
+     * Returns a String representation of this filter. This function is the inverse of
+     * {@link TestFilter#createFrom(String)}.
+     *
+     * For a valid filter f;
+     * <pre>
+     * {@code
+     * new TestFilter(f).toString().equals(f)
+     * }
+     * </pre>
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (mAbi != null) {
+            sb.append(mAbi.trim());
+            sb.append(" ");
+        }
+        if (mName != null) {
+            sb.append(mName.trim());
+        }
+        if (mTest != null) {
+            sb.append(" ");
+            sb.append(mTest.trim());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @return the abi of this filter, or null if not specified.
+     */
+    public String getAbi() {
+        return mAbi;
+    }
+
+    /**
+     * @return the module name of this filter, or null if not specified.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * @return the test identifier of this filter, or null if not specified.
+     */
+    public String getTest() {
+        return mTest;
+    }
+
+}
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
index 6981ed7..b5806c7 100644
--- a/common/host-side/util/tests/Android.mk
+++ b/common/host-side/util/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util junit-host json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util junit-host json-prebuilt tradefed
 
 LOCAL_MODULE := compatibility-host-util-tests
 
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
index 36c4970..a1d3d0a2 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+
 import junit.framework.TestCase;
 
 import java.io.File;
@@ -92,29 +95,31 @@
     public void testDynamicConfigHandler() throws Exception {
         String module = "test1";
         File localConfigFile = createFileFromStr(localConfig, module);
+        try {
+            File mergedFile = DynamicConfigHandler
+                    .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
 
-        File mergedFile = DynamicConfigHandler
-                .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
+            Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
 
-        Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
+            assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
+            assertTrue(configMap.get("override-config-list-1")
+                    .contains("override-config-list-val-1-1"));
+            assertTrue(configMap.get("override-config-list-1")
+                    .contains("override-config-list-val-1-2"));
+            assertTrue(configMap.get("override-config-list-3").size() == 0);
 
-        assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
-        assertTrue(configMap.get("override-config-list-1")
-                .contains("override-config-list-val-1-1"));
-        assertTrue(configMap.get("override-config-list-1")
-                .contains("override-config-list-val-1-2"));
-        assertTrue(configMap.get("override-config-list-3").size() == 0);
+            assertEquals("test config 1", configMap.get("test-config-1").get(0));
+            assertTrue(configMap.get("config-list").contains("config2"));
 
-        assertEquals("test config 1", configMap.get("test-config-1").get(0));
-        assertTrue(configMap.get("config-list").contains("config2"));
-
-        assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
-        assertEquals(1, configMap.get("override-config-list-2").size());
-        assertTrue(configMap.get("override-config-list-2")
-                .contains("override-config-list-val-2-1"));
+            assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
+            assertEquals(1, configMap.get("override-config-list-2").size());
+            assertTrue(configMap.get("override-config-list-2")
+                    .contains("override-config-list-val-2-1"));
+        } finally {
+            FileUtil.deleteFile(localConfigFile);
+        }
     }
 
-
     private File createFileFromStr(String configStr, String module) throws IOException {
         File file = File.createTempFile(module, "dynamic");
         FileOutputStream stream = null;
@@ -123,9 +128,7 @@
             stream.write(configStr.getBytes());
             stream.flush();
         } finally {
-            if (stream != null) {
-                stream.close();
-            }
+            StreamUtil.close(stream);
         }
         return file;
     }
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
index 169cfdb..a706018 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
@@ -28,7 +28,8 @@
     public HostUnitTests() {
         super();
         addTestSuite(DynamicConfigHandlerTest.class);
-        addTestSuite(ResultHandlerTest.class);
+        addTestSuite(ModuleResultTest.class);
+        addTestSuite(TestFilterTest.class);
     }
 
     public static Test suite() {
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
new file mode 100644
index 0000000..474d168
--- /dev/null
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link ModuleResult}
+ */
+public class ModuleResultTest extends TestCase {
+
+    private static final String NAME = "ModuleName";
+    private static final String NAME_2 = "ModuleName2";
+    private static final String ABI = "mips64";
+    private static final String ID = AbiUtils.createId(ABI, NAME);
+    private static final String ID_2 = AbiUtils.createId(ABI, NAME_2);
+    private static final String CLASS = "android.test.FoorBar";
+    private static final String CLASS_2 = "android.test.FoorBar2";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private ModuleResult mResult;
+
+    @Override
+    public void setUp() throws Exception {
+        mResult = new ModuleResult(ID);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mResult = null;
+    }
+
+    public void testAccessors() throws Exception {
+        assertEquals("Incorrect module ID", ID, mResult.getId());
+        assertEquals("Incorrect module ABI", ABI, mResult.getAbi());
+        assertEquals("Incorrect module name", NAME, mResult.getName());
+    }
+
+    public void testResultCreation() throws Exception {
+        ICaseResult caseResult = mResult.getOrCreateResult(CLASS);
+        // Should create one
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
+        // Should not create another one
+        ICaseResult caseResult2 = mResult.getOrCreateResult(CLASS);
+        assertEquals("Expected the same result", caseResult, caseResult2);
+        assertEquals("Expected one result", 1, mResult.getResults().size());
+    }
+
+    public void testCountResults() throws Exception {
+        ICaseResult testCase = mResult.getOrCreateResult(CLASS);
+        testCase.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
+        testCase.getOrCreateResult(METHOD_2).failed(STACK_TRACE);
+        testCase.getOrCreateResult(METHOD_3).passed(null);
+        assertEquals("Expected two failures", 2, mResult.countResults(TestStatus.FAIL));
+        assertEquals("Expected one pass", 1, mResult.countResults(TestStatus.PASS));
+    }
+
+    public void testMergeModule() throws Exception {
+        ICaseResult caseResult = mResult.getOrCreateResult(CLASS);
+        caseResult.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
+        caseResult.getOrCreateResult(METHOD_3).passed(null);
+
+        ICaseResult caseResult2 = mResult.getOrCreateResult(CLASS_2);
+        caseResult2.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
+        caseResult2.getOrCreateResult(METHOD_3).passed(null);
+
+        assertEquals("Expected two results", 2, mResult.getResults().size());
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult2));
+
+        ModuleResult otherResult = new ModuleResult(ID);
+        // Same class but all passing tests
+        ICaseResult otherCaseResult = otherResult.getOrCreateResult(CLASS);
+        otherCaseResult.getOrCreateResult(METHOD_1).passed(null);
+        otherCaseResult.getOrCreateResult(METHOD_2).passed(null);
+        otherCaseResult.getOrCreateResult(METHOD_3).passed(null);
+        otherResult.setDone(true);
+
+        mResult.mergeFrom(otherResult);
+
+        assertEquals("Expected two results", 2, mResult.getResults().size());
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
+        assertTrue("Expected test result", mResult.getResults().contains(caseResult2));
+        assertTrue(mResult.isDone());
+    }
+
+    public void testSetDone() {
+        assertFalse(mResult.isDone());
+        mResult.setDone(true);
+        assertTrue(mResult.isDone());
+    }
+
+    public void testMergeModule_mismatchedModuleId() throws Exception {
+
+        ModuleResult otherResult = new ModuleResult(ID_2);
+        try {
+            mResult.mergeFrom(otherResult);
+            fail("Expected IlleglArgumentException");
+        } catch (IllegalArgumentException expected) {}
+    }
+}
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
deleted file mode 100644
index 601dba2..0000000
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ /dev/null
@@ -1,341 +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.util;
-
-import com.android.tradefed.util.FileUtil;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Unit tests for {@link ResultHandler}
- */
-public class ResultHandlerTest extends TestCase {
-
-    private static final String SUITE_NAME = "CTS";
-    private static final String SUITE_VERSION = "5.0";
-    private static final String SUITE_PLAN = "cts";
-    private static final String SUITE_BUILD = "12345";
-    private static final String REPORT_VERSION = "5.0";
-    private static final String OS_NAME = System.getProperty("os.name");
-    private static final String OS_VERSION = System.getProperty("os.version");
-    private static final String OS_ARCH = System.getProperty("os.arch");
-    private static final String JAVA_VENDOR = System.getProperty("java.vendor");
-    private static final String JAVA_VERSION = System.getProperty("java.version");
-    private static final String NAME_A = "ModuleA";
-    private static final String NAME_B = "ModuleB";
-    private static final String DONE_A = "false";
-    private static final String DONE_B = "true";
-    private static final String NOT_EXECUTED_A = "1";
-    private static final String NOT_EXECUTED_B = "0";
-    private static final String RUNTIME_A = "100";
-    private static final String RUNTIME_B = "200";
-    private static final String ABI = "mips64";
-    private static final String ID_A = AbiUtils.createId(ABI, NAME_A);
-    private static final String ID_B = AbiUtils.createId(ABI, NAME_B);
-
-    private static final String BUILD_ID = "build_id";
-    private static final String BUILD_PRODUCT = "build_product";
-    private static final String EXAMPLE_BUILD_ID = "XYZ";
-    private static final String EXAMPLE_BUILD_PRODUCT = "wolverine";
-
-    private static final String DEVICE_A = "device123";
-    private static final String DEVICE_B = "device456";
-    private static final String DEVICES = "device456,device123";
-    private static final String CLASS_A = "android.test.Foor";
-    private static final String CLASS_B = "android.test.Bar";
-    private static final String METHOD_1 = "testBlah1";
-    private static final String METHOD_2 = "testBlah2";
-    private static final String METHOD_3 = "testBlah3";
-    private static final String METHOD_4 = "testBlah4";
-    private static final String SUMMARY_SOURCE = String.format("%s#%s:20", CLASS_B, METHOD_4);
-    private static final String DETAILS_SOURCE = String.format("%s#%s:18", CLASS_B, METHOD_4);
-    private static final String SUMMARY_MESSAGE = "Headline";
-    private static final double SUMMARY_VALUE = 9001;
-    private static final String DETAILS_MESSAGE = "Deats";
-    private static final double DETAILS_VALUE_1 = 14;
-    private static final double DETAILS_VALUE_2 = 18;
-    private static final double DETAILS_VALUE_3 = 17;
-    private static final String MESSAGE = "Something small is not alright";
-    private static final String STACK_TRACE = "Something small is not alright\n " +
-            "at four.big.insects.Marley.sing(Marley.java:10)";
-    private static final String BUG_REPORT = "https://cnsviewer.corp.google.com/cns/bugreport.txt";
-    private static final String LOGCAT = "https://cnsviewer.corp.google.com/cns/logcat.gz";
-    private static final String SCREENSHOT = "https://cnsviewer.corp.google.com/screenshot.png";
-    private static final long START_MS = 1431586801000L;
-    private static final long END_MS = 1431673199000L;
-    private static final String START_DISPLAY = "Fri Aug 20 15:13:03 PDT 2010";
-    private static final String END_DISPLAY = "Fri Aug 20 15:13:04 PDT 2010";
-
-    private static final String REFERENCE_URL="http://android.com";
-    private static final String LOG_URL ="file:///path/to/logs";
-    private static final String COMMAND_LINE_ARGS = "cts -m CtsMyModuleTestCases";
-    private static final String JOIN = "%s%s";
-    private static final String XML_BASE =
-            "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
-            "<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n" +
-            "<Result start=\"%d\" end=\"%d\" start_display=\"%s\"" +
-            "end_display=\"%s\" suite_name=\"%s\" suite_version=\"%s\" " +
-            "suite_plan=\"%s\" suite_build_number=\"%s\" report_version=\"%s\" " +
-            "devices=\"%s\" host_name=\"%s\"" +
-            "os_name=\"%s\" os_version=\"%s\" os_arch=\"%s\" java_vendor=\"%s\"" +
-            "java_version=\"%s\" reference_url=\"%s\" log_url=\"%s\"" +
-            "command_line_args=\"%s\">\n" +
-            "%s%s%s" +
-            "</Result>";
-    private static final String XML_BUILD_INFO =
-            "  <Build build_fingerprint=\"%s\" " + BUILD_ID + "=\"%s\" " +
-               BUILD_PRODUCT + "=\"%s\" />\n";
-    private static final String XML_SUMMARY =
-            "  <Summary pass=\"%d\" failed=\"%d\" not_executed=\"%d\" " +
-            "modules_done=\"1\" modules_total=\"1\" />\n";
-    private static final String XML_MODULE =
-            "  <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\" not_executed=\"%s\">\n" +
-            "%s" +
-            "  </Module>\n";
-    private static final String XML_CASE =
-            "    <TestCase name=\"%s\">\n" +
-            "%s" +
-            "    </TestCase>\n";
-    private static final String XML_TEST_PASS =
-            "      <Test result=\"pass\" name=\"%s\"/>\n";
-    private static final String XML_TEST_NOT_EXECUTED =
-            "      <Test result=\"not_executed\" name=\"%s\"/>\n";
-    private static final String XML_TEST_FAIL =
-            "      <Test result=\"fail\" name=\"%s\">\n" +
-            "        <Failure message=\"%s\">\n" +
-            "          <StackTrace>%s</StackTrace>\n" +
-            "        </Failure>\n" +
-            "        <BugReport>%s</BugReport>\n" +
-            "        <Logcat>%s</Logcat>\n" +
-            "        <Screenshot>%s</Screenshot>\n" +
-            "      </Test>\n";
-    private static final String XML_TEST_RESULT =
-            "      <Test result=\"pass\" name=\"%s\">\n" +
-            "        <Summary>\n" +
-            "          <Metric source=\"%s\" message=\"%s\" score_type=\"%s\" score_unit=\"%s\">\n" +
-            "             <Value>%s</Value>\n" +
-            "          </Metric>\n" +
-            "        </Summary>\n" +
-            "      </Test>\n";
-    private File resultsDir = null;
-    private File resultDir = null;
-
-    @Override
-    public void setUp() throws Exception {
-        resultsDir = FileUtil.createTempDir("results");
-        resultDir = FileUtil.createTempDir("12345", resultsDir);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        if (resultsDir != null) {
-            FileUtil.recursiveDelete(resultsDir);
-        }
-    }
-
-    public void testSerialization() throws Exception {
-        IInvocationResult result = new InvocationResult();
-        result.setStartTime(START_MS);
-        result.setTestPlan(SUITE_PLAN);
-        result.addDeviceSerial(DEVICE_A);
-        result.addDeviceSerial(DEVICE_B);
-        result.addInvocationInfo(BUILD_ID, EXAMPLE_BUILD_ID);
-        result.addInvocationInfo(BUILD_PRODUCT, EXAMPLE_BUILD_PRODUCT);
-        IModuleResult moduleA = result.getOrCreateModule(ID_A);
-        moduleA.setDone(false);
-        moduleA.addRuntime(Integer.parseInt(RUNTIME_A));
-        ICaseResult moduleACase = moduleA.getOrCreateResult(CLASS_A);
-        ITestResult moduleATest1 = moduleACase.getOrCreateResult(METHOD_1);
-        moduleATest1.setResultStatus(TestStatus.PASS);
-        ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
-        moduleATest2.setResultStatus(null); // not executed test
-        moduleA.setNotExecuted(1);
-
-        IModuleResult moduleB = result.getOrCreateModule(ID_B);
-        moduleB.setDone(true);
-        moduleB.addRuntime(Integer.parseInt(RUNTIME_B));
-        ICaseResult moduleBCase = moduleB.getOrCreateResult(CLASS_B);
-        ITestResult moduleBTest3 = moduleBCase.getOrCreateResult(METHOD_3);
-        moduleBTest3.setResultStatus(TestStatus.FAIL);
-        moduleBTest3.setMessage(MESSAGE);
-        moduleBTest3.setStackTrace(STACK_TRACE);
-        moduleBTest3.setBugReport(BUG_REPORT);
-        moduleBTest3.setLog(LOGCAT);
-        moduleBTest3.setScreenshot(SCREENSHOT);
-        ITestResult moduleBTest4 = moduleBCase.getOrCreateResult(METHOD_4);
-        moduleBTest4.setResultStatus(TestStatus.PASS);
-        ReportLog report = new ReportLog();
-        ReportLog.Metric summary = new ReportLog.Metric(SUMMARY_SOURCE, SUMMARY_MESSAGE,
-                SUMMARY_VALUE, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
-        report.setSummary(summary);
-        moduleBTest4.setReportLog(report);
-
-        // Serialize to file
-        ResultHandler.writeResults(SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD,
-                result, resultDir, START_MS, END_MS, REFERENCE_URL, LOG_URL,
-                COMMAND_LINE_ARGS);
-
-        // Parse the results and assert correctness
-        checkResult(ResultHandler.getResults(resultsDir), resultDir);
-    }
-
-    public void testParsing() throws Exception {
-        File resultsDir = null;
-        FileWriter writer = null;
-        try {
-            resultsDir = FileUtil.createTempDir("results");
-            File resultDir = FileUtil.createTempDir("12345", resultsDir);
-            // Create the result file
-            File resultFile = new File(resultDir, ResultHandler.TEST_RESULT_FILE_NAME);
-            writer = new FileWriter(resultFile);
-            String buildInfo = String.format(XML_BUILD_INFO, DEVICE_A,
-                    EXAMPLE_BUILD_ID, EXAMPLE_BUILD_PRODUCT);
-            String summary = String.format(XML_SUMMARY, 2, 1, 1);
-            String moduleATest = String.format(XML_TEST_PASS, METHOD_1);
-            String moduleACases = String.format(XML_CASE, CLASS_A, moduleATest);
-            String moduleA = String.format(XML_MODULE, NAME_A, ABI, DEVICE_A, RUNTIME_A, DONE_A,
-                    NOT_EXECUTED_A, moduleACases);
-            String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE,
-                    BUG_REPORT, LOGCAT, SCREENSHOT);
-            String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4,
-                    SUMMARY_SOURCE, SUMMARY_MESSAGE, ResultType.HIGHER_BETTER.toReportString(),
-                    ResultUnit.SCORE.toReportString(), Double.toString(SUMMARY_VALUE),
-                    DETAILS_SOURCE, DETAILS_MESSAGE, ResultType.LOWER_BETTER.toReportString(),
-                    ResultUnit.MS.toReportString(), Double.toString(DETAILS_VALUE_1),
-                    Double.toString(DETAILS_VALUE_2), Double.toString(DETAILS_VALUE_3));
-            String moduleBTests = String.format(JOIN, moduleBTest3, moduleBTest4);
-            String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
-            String moduleB = String.format(XML_MODULE, NAME_B, ABI, DEVICE_B, RUNTIME_B, DONE_B,
-                    NOT_EXECUTED_B, moduleBCases);
-            String modules = String.format(JOIN, moduleA, moduleB);
-            String hostName = "";
-            try {
-                hostName = InetAddress.getLocalHost().getHostName();
-            } catch (UnknownHostException ignored) {}
-            String output = String.format(XML_BASE, START_MS, END_MS, START_DISPLAY, END_DISPLAY,
-                    SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD, REPORT_VERSION, DEVICES,
-                    hostName, OS_NAME, OS_VERSION, OS_ARCH, JAVA_VENDOR,
-                    JAVA_VERSION, REFERENCE_URL, LOG_URL, COMMAND_LINE_ARGS,
-                    buildInfo, summary, modules);
-            writer.write(output);
-            writer.flush();
-
-            // Parse the results and assert correctness
-            checkResult(ResultHandler.getResults(resultsDir), resultDir);
-        } finally {
-            if (writer != null) {
-                writer.close();
-            }
-        }
-    }
-
-    private void checkResult(List<IInvocationResult> results, File resultDir) throws Exception {
-        assertEquals("Expected 1 result", 1, results.size());
-        IInvocationResult result = results.get(0);
-        assertEquals("Expected 2 passes", 2, result.countResults(TestStatus.PASS));
-        assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
-        assertEquals("Expected 1 not executed", 1, result.getNotExecuted());
-
-        Map<String, String> buildInfo = result.getInvocationInfo();
-        assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
-        assertEquals("Incorrect Build Product",
-            EXAMPLE_BUILD_PRODUCT, buildInfo.get(BUILD_PRODUCT));
-
-        Set<String> serials = result.getDeviceSerials();
-        assertTrue("Missing device", serials.contains(DEVICE_A));
-        assertTrue("Missing device", serials.contains(DEVICE_B));
-        assertEquals("Expected 2 devices", 2, serials.size());
-        assertTrue("Incorrect devices", serials.contains(DEVICE_A) && serials.contains(DEVICE_B));
-        assertEquals("Incorrect start time", START_MS, result.getStartTime());
-        assertEquals("Incorrect test plan", SUITE_PLAN, result.getTestPlan());
-
-        List<IModuleResult> modules = result.getModules();
-        assertEquals("Expected 2 modules", 2, modules.size());
-
-        IModuleResult moduleA = modules.get(0);
-        assertEquals("Expected 1 pass", 1, moduleA.countResults(TestStatus.PASS));
-        assertEquals("Expected 0 failures", 0, moduleA.countResults(TestStatus.FAIL));
-        assertEquals("Incorrect ABI", ABI, moduleA.getAbi());
-        assertEquals("Incorrect name", NAME_A, moduleA.getName());
-        assertEquals("Incorrect ID", ID_A, moduleA.getId());
-        assertEquals("Incorrect runtime", Integer.parseInt(RUNTIME_A), moduleA.getRuntime());
-        List<ICaseResult> moduleACases = moduleA.getResults();
-        assertEquals("Expected 1 test case", 1, moduleACases.size());
-        ICaseResult moduleACase = moduleACases.get(0);
-        assertEquals("Incorrect name", CLASS_A, moduleACase.getName());
-        List<ITestResult> moduleAResults = moduleACase.getResults();
-        assertEquals("Expected 1 result", 1, moduleAResults.size());
-        ITestResult moduleATest1 = moduleAResults.get(0);
-        assertEquals("Incorrect name", METHOD_1, moduleATest1.getName());
-        assertEquals("Incorrect result", TestStatus.PASS, moduleATest1.getResultStatus());
-        assertNull("Unexpected bugreport", moduleATest1.getBugReport());
-        assertNull("Unexpected log", moduleATest1.getLog());
-        assertNull("Unexpected screenshot", moduleATest1.getScreenshot());
-        assertNull("Unexpected message", moduleATest1.getMessage());
-        assertNull("Unexpected stack trace", moduleATest1.getStackTrace());
-        assertNull("Unexpected report", moduleATest1.getReportLog());
-
-        IModuleResult moduleB = modules.get(1);
-        assertEquals("Expected 1 pass", 1, moduleB.countResults(TestStatus.PASS));
-        assertEquals("Expected 1 failure", 1, moduleB.countResults(TestStatus.FAIL));
-        assertEquals("Incorrect ABI", ABI, moduleB.getAbi());
-        assertEquals("Incorrect name", NAME_B, moduleB.getName());
-        assertEquals("Incorrect ID", ID_B, moduleB.getId());
-        assertEquals("Incorrect runtime", Integer.parseInt(RUNTIME_B), moduleB.getRuntime());
-        List<ICaseResult> moduleBCases = moduleB.getResults();
-        assertEquals("Expected 1 test case", 1, moduleBCases.size());
-        ICaseResult moduleBCase = moduleBCases.get(0);
-        assertEquals("Incorrect name", CLASS_B, moduleBCase.getName());
-        List<ITestResult> moduleBResults = moduleBCase.getResults();
-        assertEquals("Expected 2 results", 2, moduleBResults.size());
-        ITestResult moduleBTest3 = moduleBResults.get(0);
-        assertEquals("Incorrect name", METHOD_3, moduleBTest3.getName());
-        assertEquals("Incorrect result", TestStatus.FAIL, moduleBTest3.getResultStatus());
-        assertEquals("Incorrect bugreport", BUG_REPORT, moduleBTest3.getBugReport());
-        assertEquals("Incorrect log", LOGCAT, moduleBTest3.getLog());
-        assertEquals("Incorrect screenshot", SCREENSHOT, moduleBTest3.getScreenshot());
-        assertEquals("Incorrect message", MESSAGE, moduleBTest3.getMessage());
-        assertEquals("Incorrect stack trace", STACK_TRACE, moduleBTest3.getStackTrace());
-        assertNull("Unexpected report", moduleBTest3.getReportLog());
-        ITestResult moduleBTest4 = moduleBResults.get(1);
-        assertEquals("Incorrect name", METHOD_4, moduleBTest4.getName());
-        assertEquals("Incorrect result", TestStatus.PASS, moduleBTest4.getResultStatus());
-        assertNull("Unexpected bugreport", moduleBTest4.getBugReport());
-        assertNull("Unexpected log", moduleBTest4.getLog());
-        assertNull("Unexpected screenshot", moduleBTest4.getScreenshot());
-        assertNull("Unexpected message", moduleBTest4.getMessage());
-        assertNull("Unexpected stack trace", moduleBTest4.getStackTrace());
-        ReportLog report = moduleBTest4.getReportLog();
-        assertNotNull("Expected report", report);
-        ReportLog.Metric summary = report.getSummary();
-        assertNotNull("Expected report summary", summary);
-        assertEquals("Incorrect source", SUMMARY_SOURCE, summary.getSource());
-        assertEquals("Incorrect message", SUMMARY_MESSAGE, summary.getMessage());
-        assertEquals("Incorrect type", ResultType.HIGHER_BETTER, summary.getType());
-        assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
-        assertTrue("Incorrect values", Arrays.equals(new double[] { SUMMARY_VALUE },
-                summary.getValues()));
-    }
-}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java
similarity index 100%
rename from common/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java
rename to common/host-side/util/tests/src/com/android/compatibility/common/util/TestFilterTest.java
diff --git a/common/util/Android.mk b/common/util/Android.mk
index faf4596..b6cf927 100644
--- a/common/util/Android.mk
+++ b/common/util/Android.mk
@@ -26,6 +26,8 @@
 
 LOCAL_MODULE := compatibility-common-util-devicesidelib
 
+LOCAL_STATIC_JAVA_LIBRARIES :=  guava
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
@@ -42,7 +44,10 @@
 
 LOCAL_MODULE := compatibility-common-util-hostsidelib
 
-LOCAL_STATIC_JAVA_LIBRARIES := junit-host kxml2-2.3.0 platform-test-annotations-host
+LOCAL_STATIC_JAVA_LIBRARIES :=  guavalib \
+                                junit-host \
+                                kxml2-2.3.0 \
+                                platform-test-annotations-host
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/common/util/src/com/android/compatibility/common/util/AbiUtils.java b/common/util/src/com/android/compatibility/common/util/AbiUtils.java
deleted file mode 100644
index ef42a00..0000000
--- a/common/util/src/com/android/compatibility/common/util/AbiUtils.java
+++ /dev/null
@@ -1,200 +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.compatibility.common.util;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Utility class for handling device ABIs
- */
-public class AbiUtils {
-
-    /**
-     * The set of 32Bit ABIs.
-     */
-    private static final Set<String> ABIS_32BIT = new HashSet<String>();
-
-    /**
-     * The set of 64Bit ABIs.
-     */
-    private static final Set<String> ABIS_64BIT = new HashSet<String>();
-
-    /**
-     * The set of ARM ABIs.
-     */
-    private static final Set<String> ARM_ABIS = new HashSet<String>();
-
-    /**
-     * The set of Intel ABIs.
-     */
-    private static final Set<String> INTEL_ABIS = new HashSet<String>();
-
-    /**
-     * The set of Mips ABIs.
-     */
-    private static final Set<String> MIPS_ABIS = new HashSet<String>();
-
-    /**
-     * The set of ABI names which Compatibility supports.
-     */
-    private static final Set<String> ABIS_SUPPORTED_BY_COMPATIBILITY = new HashSet<String>();
-
-    /**
-     * The map of architecture to ABI.
-     */
-    private static final Map<String, Set<String>> ARCH_TO_ABIS = new HashMap<String, Set<String>>();
-    static {
-        ABIS_32BIT.add("armeabi-v7a");
-        ABIS_32BIT.add("x86");
-        ABIS_32BIT.add("mips");
-
-        ABIS_64BIT.add("arm64-v8a");
-        ABIS_64BIT.add("x86_64");
-        ABIS_64BIT.add("mips64");
-
-        ARM_ABIS.add("armeabi-v7a");
-        ARM_ABIS.add("arm64-v8a");
-
-        INTEL_ABIS.add("x86");
-        INTEL_ABIS.add("x86_64");
-
-        MIPS_ABIS.add("mips");
-        MIPS_ABIS.add("mips64");
-
-        ARCH_TO_ABIS.put("arm", ARM_ABIS);
-        ARCH_TO_ABIS.put("arm64", ARM_ABIS);
-        ARCH_TO_ABIS.put("x86", INTEL_ABIS);
-        ARCH_TO_ABIS.put("x86_64", INTEL_ABIS);
-        ARCH_TO_ABIS.put("mips", MIPS_ABIS);
-        ARCH_TO_ABIS.put("mips64", MIPS_ABIS);
-
-        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(ARM_ABIS);
-        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(INTEL_ABIS);
-        ABIS_SUPPORTED_BY_COMPATIBILITY.addAll(MIPS_ABIS);
-    }
-
-    /**
-     * Private constructor to avoid instantiation.
-     */
-    private AbiUtils() {}
-
-    /**
-     * Returns the set of ABIs associated with the given architecture.
-     * @param arch The architecture to look up.
-     * @return a new Set containing the ABIs.
-     */
-    public static Set<String> getAbisForArch(String arch) {
-        if (arch == null || arch.isEmpty() || !ARCH_TO_ABIS.containsKey(arch)) {
-            return getAbisSupportedByCompatibility();
-        }
-        return new HashSet<String>(ARCH_TO_ABIS.get(arch));
-    }
-
-    /**
-     * Returns the set of ABIs supported by Compatibility.
-     * @return a new Set containing the supported ABIs.
-     */
-    public static Set<String> getAbisSupportedByCompatibility() {
-        return new HashSet<String>(ABIS_SUPPORTED_BY_COMPATIBILITY);
-    }
-
-    /**
-     * @param abi The ABI name to test.
-     * @return true if the given ABI is supported by Compatibility.
-     */
-    public static boolean isAbiSupportedByCompatibility(String abi) {
-        return ABIS_SUPPORTED_BY_COMPATIBILITY.contains(abi);
-    }
-
-    /**
-     * Creates a flag for the given ABI.
-     * @param abi the ABI to create the flag for.
-     * @return a string which can be add to a command sent to ADB.
-     */
-    public static String createAbiFlag(String abi) {
-        if (abi == null || abi.isEmpty() || !isAbiSupportedByCompatibility(abi)) {
-            return "";
-        }
-        return String.format("--abi %s ", abi);
-    }
-
-    /**
-     * Creates a unique id from the given ABI and name.
-     * @param abi The ABI to use.
-     * @param name The name to use.
-     * @return a string which uniquely identifies a run.
-     */
-    public static String createId(String abi, String name) {
-        return String.format("%s %s", abi, name);
-    }
-
-    /**
-     * Parses a unique id into the ABI and name.
-     * @param id The id to parse.
-     * @return a string array containing the ABI and name.
-     */
-    public static String[] parseId(String id) {
-        if (id == null || !id.contains(" ")) {
-            return new String[] {"", ""};
-        }
-        return id.split(" ");
-    }
-
-    /**
-     * @return the test name portion of the test id.
-     *         e.g. armeabi-v7a android.mytest = android.mytest
-     */
-    public static String parseTestName(String id) {
-        return parseId(id)[1];
-    }
-
-    /**
-     * @return the abi portion of the test id.
-     *         e.g. armeabi-v7a android.mytest = armeabi-v7a
-     */
-    public static String parseAbi(String id) {
-        return parseId(id)[0];
-    }
-
-    /**
-     * @param name The name of the ABI.
-     * @return The bitness of the ABI with the given name
-     */
-    public static String getBitness(String name) {
-        return ABIS_32BIT.contains(name) ? "32" : "64";
-    }
-
-    /**
-     * @param unsupportedAbiDescription A comma separated string containing abis.
-     * @return A List of Strings containing valid ABIs.
-     */
-    public static Set<String> parseAbiList(String unsupportedAbiDescription) {
-        Set<String> abiSet = new HashSet<>();
-        String[] descSegments = unsupportedAbiDescription.split(":");
-        if (descSegments.length == 2) {
-            for (String abi : descSegments[1].split(",")) {
-                String trimmedAbi = abi.trim();
-                if (isAbiSupportedByCompatibility(trimmedAbi)) {
-                    abiSet.add(trimmedAbi);
-                }
-            }
-        }
-        return abiSet;
-    }
-}
diff --git a/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
new file mode 100644
index 0000000..32fa532
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
@@ -0,0 +1,394 @@
+/*
+ * 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.compatibility.common.util;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.hash.BloomFilter;
+import com.google.common.hash.Funnels;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/***
+ * Calculate and store checksum values for files and test results
+ */
+public final class ChecksumReporter implements Serializable {
+
+    public static final String NAME = "checksum.data";
+    public static final String PREV_NAME = "checksum.previous.data";
+
+    private static final double DEFAULT_FPP = 0.05;
+    private static final String SEPARATOR = "/";
+    private static final String ID_SEPARATOR = "@";
+    private static final String NAME_SEPARATOR = ".";
+
+    private static final short CURRENT_VERSION = 1;
+    // Serialized format Id (ie magic number) used to identify serialized data.
+    static final short SERIALIZED_FORMAT_CODE = 650;
+
+    private final BloomFilter<CharSequence> mResultChecksum;
+    private final HashMap<String, byte[]> mFileChecksum;
+    private final short mVersion;
+
+    /***
+     * Calculate checksum of test results and files in result directory and write to disk
+     * @param dir test results directory
+     * @param result test results
+     * @return true if successful, false if unable to calculate or store the checksum
+     */
+    public static boolean tryCreateChecksum(File dir, IInvocationResult result) {
+        try {
+            int totalCount = countTestResults(result);
+            ChecksumReporter checksumReporter =
+                    new ChecksumReporter(totalCount, DEFAULT_FPP, CURRENT_VERSION);
+            checksumReporter.addInvocation(result);
+            checksumReporter.addDirectory(dir);
+            checksumReporter.saveToFile(dir);
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /***
+     * Create Checksum Reporter from data saved on disk
+     * @param directory
+     * @return
+     * @throws ChecksumValidationException
+     */
+    public static ChecksumReporter load(File directory) throws ChecksumValidationException {
+        ChecksumReporter reporter = new ChecksumReporter(directory);
+        if (reporter.getCapacity() > 1.1) {
+            throw new ChecksumValidationException("Capacity exceeded.");
+        }
+        return reporter;
+    }
+
+    /***
+     * Deserialize checksum from file
+     * @param directory the parent directory containing the checksum file
+     * @throws ChecksumValidationException
+     */
+    public ChecksumReporter(File directory) throws ChecksumValidationException {
+        File file = new File(directory, ChecksumReporter.NAME);
+        try (FileInputStream fileStream = new FileInputStream(file);
+            InputStream outputStream = new BufferedInputStream(fileStream);
+            ObjectInput objectInput = new ObjectInputStream(outputStream)) {
+            short magicNumber = objectInput.readShort();
+            switch (magicNumber) {
+                case SERIALIZED_FORMAT_CODE:
+                   mVersion = objectInput.readShort();
+                    mResultChecksum = (BloomFilter<CharSequence>) objectInput.readObject();
+                    mFileChecksum = (HashMap<String, byte[]>) objectInput.readObject();
+                    break;
+                default:
+                    throw new ChecksumValidationException("Unknown format of serialized data.");
+            }
+        } catch (Exception e) {
+            throw new ChecksumValidationException("Unable to load checksum from file", e);
+        }
+        if (mVersion > CURRENT_VERSION) {
+            throw new ChecksumValidationException(
+                    "File contains a newer version of ChecksumReporter");
+        }
+    }
+
+    /***
+     * Create new instance of ChecksumReporter
+     * @param testCount the number of test results that will be stored
+     * @param fpp the false positive percentage for result lookup misses
+     */
+    public ChecksumReporter(int testCount, double fpp, short version) {
+        mResultChecksum = BloomFilter.create(Funnels.unencodedCharsFunnel(),
+                testCount, fpp);
+        mFileChecksum = new HashMap<>();
+        mVersion = version;
+    }
+
+    /***
+     * Add each test result from each module and test case
+     */
+    public void addInvocation(IInvocationResult invocationResult) {
+        for (IModuleResult module : invocationResult.getModules()) {
+            String buildFingerprint = invocationResult.getBuildFingerprint();
+            addModuleResult(module, buildFingerprint);
+            for (ICaseResult caseResult : module.getResults()) {
+                for (ITestResult testResult : caseResult.getResults()) {
+                    addTestResult(testResult, module, buildFingerprint);
+                }
+            }
+        }
+    }
+
+    /***
+     * Calculate CRC of file and store the result
+     * @param file crc calculated on this file
+     * @param path part of the key to identify the files crc
+     */
+    public void addFile(File file, String path) {
+        byte[] crc;
+        try {
+            crc = calculateFileChecksum(file);
+        } catch (ChecksumValidationException e) {
+            crc = new byte[0];
+        }
+        String key = path + SEPARATOR + file.getName();
+        mFileChecksum.put(key, crc);
+    }
+
+    @VisibleForTesting
+    public boolean containsFile(File file, String path) {
+        String key = path + SEPARATOR + file.getName();
+        if (mFileChecksum.containsKey(key))
+        {
+            try {
+                byte[] crc = calculateFileChecksum(file);
+                return Arrays.equals(mFileChecksum.get(key), crc);
+            } catch (ChecksumValidationException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /***
+     * Adds all child files recursively through all sub directories
+     * @param directory target that is deeply searched for files
+     */
+    public void addDirectory(File directory) {
+        addDirectory(directory, directory.getName());
+    }
+
+    /***
+     * @param path the relative path to the current directory from the base directory
+     */
+    private void addDirectory(File directory, String path) {
+        for(String childName : directory.list()) {
+            File child = new File(directory, childName);
+            if (child.isDirectory()) {
+                addDirectory(child, path + SEPARATOR + child.getName());
+            } else {
+                addFile(child, path);
+            }
+        }
+    }
+
+    /***
+     * Calculate checksum of test result and store the value
+     * @param testResult the target of the checksum
+     * @param moduleResult the module that contains the test result
+     * @param buildFingerprint the fingerprint the test execution is running against
+     */
+    public void addTestResult(
+        ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+        mResultChecksum.put(signature);
+    }
+
+    @VisibleForTesting
+    public boolean containsTestResult(
+            ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+        return mResultChecksum.mightContain(signature);
+    }
+
+    /***
+     * Calculate checksm of module result and store value
+     * @param moduleResult  the target of the checksum
+     * @param buildFingerprint the fingerprint the test execution is running against
+     */
+    public void addModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+        mResultChecksum.put(
+                generateModuleResultSignature(moduleResult, buildFingerprint));
+        mResultChecksum.put(
+                generateModuleSummarySignature(moduleResult, buildFingerprint));
+    }
+
+    @VisibleForTesting
+    public Boolean containsModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+        return mResultChecksum.mightContain(
+                generateModuleResultSignature(moduleResult, buildFingerprint));
+    }
+
+    /***
+     * Write the checksum data to disk.
+     * Overwrites existing file
+     * @param directory
+     * @throws IOException
+     */
+    public void saveToFile(File directory) throws IOException {
+        File file = new File(directory, NAME);
+
+        try (FileOutputStream fileStream = new FileOutputStream(file, false);
+             OutputStream outputStream = new BufferedOutputStream(fileStream);
+             ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) {
+            objectOutput.writeShort(SERIALIZED_FORMAT_CODE);
+            objectOutput.writeShort(mVersion);
+            objectOutput.writeObject(mResultChecksum);
+            objectOutput.writeObject(mFileChecksum);
+        }
+    }
+
+    @VisibleForTesting
+    double getCapacity() {
+        // If default FPP changes:
+        // increment the CURRENT_VERSION and set the denominator based on this.mVersion
+        return mResultChecksum.expectedFpp() / DEFAULT_FPP;
+    }
+
+    static String generateTestResultSignature(ITestResult testResult, IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        String stacktrace = testResult.getStackTrace();
+
+        stacktrace = stacktrace == null ? "" : stacktrace.trim();
+        // Line endings for stacktraces are somewhat unpredictable and there is no need to
+        // actually read the result they are all removed for consistency.
+        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(testResult.getFullName()).append(SEPARATOR)
+                .append(testResult.getResultStatus().getValue()).append(SEPARATOR)
+                .append(stacktrace).append(SEPARATOR);
+        return sb.toString();
+    }
+
+    static String generateTestResultSignature(
+            String packageName, String suiteName, String caseName, String testName, String abi,
+            String status,
+            String stacktrace,
+            String buildFingerprint) {
+
+        String testId = buildTestId(suiteName, caseName, testName, abi);
+        StringBuilder sb = new StringBuilder();
+
+        stacktrace = stacktrace == null ? "" : stacktrace.trim();
+        // Line endings for stacktraces are somewhat unpredictable and there is no need to
+        // actually read the result they are all removed for consistency.
+        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+        sb.append(buildFingerprint)
+                .append(SEPARATOR)
+                .append(packageName)
+                .append(SEPARATOR)
+                .append(testId)
+                .append(SEPARATOR)
+                .append(status)
+                .append(SEPARATOR)
+                .append(stacktrace)
+                .append(SEPARATOR);
+        return sb.toString();
+    }
+
+    private static String buildTestId(
+            String suiteName, String caseName, String testName, String abi) {
+        String name = Joiner.on(NAME_SEPARATOR).skipNulls().join(
+                Strings.emptyToNull(suiteName),
+                Strings.emptyToNull(caseName),
+                Strings.emptyToNull(testName));
+        return Joiner.on(ID_SEPARATOR).skipNulls().join(
+                Strings.emptyToNull(name),
+                Strings.emptyToNull(abi));
+    }
+
+
+    private static String generateModuleResultSignature(IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(module.isDone()).append(SEPARATOR)
+                .append(module.getNotExecuted()).append(SEPARATOR)
+                .append(module.countResults(TestStatus.FAIL));
+        return sb.toString();
+    }
+
+    private static String generateModuleSummarySignature(IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(module.countResults(TestStatus.FAIL));
+        return sb.toString();
+    }
+
+    static byte[] calculateFileChecksum(File file) throws ChecksumValidationException {
+
+        try (FileInputStream fis = new FileInputStream(file);
+             InputStream inputStream = new BufferedInputStream(fis)) {
+            MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
+            int cnt;
+            int bufferSize = 8192;
+            byte [] buffer = new byte[bufferSize];
+            while ((cnt = inputStream.read(buffer)) != -1) {
+                hashSum.update(buffer, 0, cnt);
+            }
+
+            byte[] partialHash = new byte[32];
+            hashSum.digest(partialHash, 0, 32);
+            return partialHash;
+        } catch (NoSuchAlgorithmException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        } catch (IOException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        } catch (DigestException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        }
+    }
+
+
+    private static int countTestResults(IInvocationResult invocation) {
+        int count = 0;
+        for (IModuleResult module : invocation.getModules()) {
+            // Two entries per module (result & summary)
+            count += 2;
+            for (ICaseResult caseResult : module.getResults()) {
+                count += caseResult.getResults().size();
+            }
+        }
+        return count;
+    }
+
+    public static class ChecksumValidationException extends Exception {
+        public ChecksumValidationException(String detailMessage) {
+            super(detailMessage);
+        }
+
+        public ChecksumValidationException(String detailMessage, Throwable throwable) {
+            super(detailMessage, throwable);
+        }
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java b/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java
new file mode 100644
index 0000000..ec24b42
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.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 com.android.compatibility.common.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class for collecting device information. This is used to enforce
+ * consistent property collection host-side and device-side for CTS reports.
+ *
+ * Note that properties across sources can differ, e.g. {@code android.os.Build}
+ * properties sometimes deviate from the read-only properties that they're based
+ * on.
+ */
+public final class DevicePropertyInfo {
+
+    private final String mAbi;
+    private final String mAbi2;
+    private final String mAbis;
+    private final String mAbis32;
+    private final String mAbis64;
+    private final String mBoard;
+    private final String mBrand;
+    private final String mDevice;
+    private final String mFingerprint;
+    private final String mId;
+    private final String mManufacturer;
+    private final String mModel;
+    private final String mProduct;
+    private final String mReferenceFingerprint;
+    private final String mSerial;
+    private final String mTags;
+    private final String mType;
+    private final String mVersionBaseOs;
+    private final String mVersionRelease;
+    private final String mVersionSdk;
+    private final String mVersionSecurityPatch;
+
+    public DevicePropertyInfo(String abi, String abi2, String abis, String abis32, String abis64,
+            String board, String brand, String device, String fingerprint, String id,
+            String manufacturer, String model, String product, String referenceFigerprint,
+            String serial, String tags, String type, String versionBaseOs, String versionRelease,
+            String versionSdk, String versionSecurityPatch) {
+        mAbi = abi;
+        mAbi2 = abi2;
+        mAbis = abis;
+        mAbis32 = abis32;
+        mAbis64 = abis64;
+        mBoard = board;
+        mBrand = brand;
+        mDevice = device;
+        mFingerprint = fingerprint;
+        mId = id;
+        mManufacturer = manufacturer;
+        mModel = model;
+        mProduct = product;
+        mReferenceFingerprint = referenceFigerprint;
+        mSerial = serial;
+        mTags = tags;
+        mType = type;
+        mVersionBaseOs = versionBaseOs;
+        mVersionRelease = versionRelease;
+        mVersionSdk = versionSdk;
+        mVersionSecurityPatch = versionSecurityPatch;
+    }
+
+    /**
+     * Return a {@code Map} with property keys prepended with a given prefix
+     * string. This is intended to be used to generate entries for
+     * {@code} Build tag attributes in CTS test results.
+     */
+    public Map<String, String> getPropertytMapWithPrefix(String prefix) {
+        Map<String, String> propertyMap = new HashMap<>();
+
+        propertyMap.put(prefix + "abi", mAbi);
+        propertyMap.put(prefix + "abi2", mAbi2);
+        propertyMap.put(prefix + "abis", mAbis);
+        propertyMap.put(prefix + "abis_32", mAbis32);
+        propertyMap.put(prefix + "abis_64", mAbis64);
+        propertyMap.put(prefix + "board", mBoard);
+        propertyMap.put(prefix + "brand", mBrand);
+        propertyMap.put(prefix + "device", mDevice);
+        propertyMap.put(prefix + "fingerprint", mFingerprint);
+        propertyMap.put(prefix + "id", mId);
+        propertyMap.put(prefix + "manufacturer", mManufacturer);
+        propertyMap.put(prefix + "model", mModel);
+        propertyMap.put(prefix + "product", mProduct);
+        propertyMap.put(prefix + "reference_fingerprint", mReferenceFingerprint);
+        propertyMap.put(prefix + "serial", mSerial);
+        propertyMap.put(prefix + "tags", mTags);
+        propertyMap.put(prefix + "type", mType);
+        propertyMap.put(prefix + "version_base_os", mVersionBaseOs);
+        propertyMap.put(prefix + "version_release", mVersionRelease);
+        propertyMap.put(prefix + "version_sdk", mVersionSdk);
+        propertyMap.put(prefix + "version_security_patch", mVersionSecurityPatch);
+
+        return propertyMap;
+    }
+
+}
diff --git a/common/util/src/com/android/compatibility/common/util/IInvocationResult.java b/common/util/src/com/android/compatibility/common/util/IInvocationResult.java
index 2b75371..96eca2d 100644
--- a/common/util/src/com/android/compatibility/common/util/IInvocationResult.java
+++ b/common/util/src/com/android/compatibility/common/util/IInvocationResult.java
@@ -134,4 +134,5 @@
      * Set the directory of the previous sessions results
      */
     void setRetryDirectory(File resultDir);
+
 }
diff --git a/common/util/src/com/android/compatibility/common/util/ITestResult.java b/common/util/src/com/android/compatibility/common/util/ITestResult.java
index 24ee1aa..d5c95e8 100644
--- a/common/util/src/com/android/compatibility/common/util/ITestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ITestResult.java
@@ -121,13 +121,17 @@
      * Report that the test was skipped.
      *
      * This means that the test is not considered appropriate for the
-     * current device, and thus is never attempted.  Unlike notExecuted(),
-     * this indicates the run of this test was valid and nothing further
-     * needs to be done.
+     * current device, and thus is never attempted. The test does not require execution,
+     * and nothing more needs to be done.
      */
     void skipped();
 
     /**
+     * Retrieves whether execution for this test result has been determined unnecessary.
+     */
+    boolean isSkipped();
+
+    /**
      * Resets the result.
      */
     void reset();
diff --git a/common/util/src/com/android/compatibility/common/util/InvocationResult.java b/common/util/src/com/android/compatibility/common/util/InvocationResult.java
index 83f1dac..c11c27d 100644
--- a/common/util/src/com/android/compatibility/common/util/InvocationResult.java
+++ b/common/util/src/com/android/compatibility/common/util/InvocationResult.java
@@ -40,6 +40,7 @@
     private int mNotExecuted = 0;
     private RetryChecksumStatus mRetryChecksumStatus = RetryChecksumStatus.NotRetry;
     private File mRetryDirectory = null;
+
     /**
      * {@inheritDoc}
      */
diff --git a/common/util/src/com/android/compatibility/common/util/ModuleResult.java b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
index 0c43e93..12ffeff 100644
--- a/common/util/src/com/android/compatibility/common/util/ModuleResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
@@ -94,7 +94,8 @@
      */
     @Override
     public String getName() {
-        return AbiUtils.parseTestName(mId);
+        // TODO: switch to using AbiUtils#parseTestName when available
+        return parseId(mId)[1];
     }
 
     /**
@@ -102,7 +103,21 @@
      */
     @Override
     public String getAbi() {
-        return AbiUtils.parseAbi(mId);
+        // TODO: switch to using AbiUtils#parseAbi when available
+        return parseId(mId)[0];
+    }
+
+    /**
+     * Parses a unique id into the ABI and name.
+     * @param id The id to parse.
+     * @return a string array containing the ABI and name.
+     */
+    private static String[] parseId(String id) {
+        // TODO: remove this when AbiUtils is available for getName and getAbi
+        if (id == null || !id.contains(" ")) {
+            return new String[] {"", ""};
+        }
+        return id.split(" ");
     }
 
     /**
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
new file mode 100644
index 0000000..10a9681
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -0,0 +1,525 @@
+/*
+ * 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.util;
+
+import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
+
+import com.google.common.base.Strings;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Handles conversion of results to/from files.
+ */
+public class ResultHandler {
+
+    private static final String ENCODING = "UTF-8";
+    private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
+    private static final String NS = null;
+    private static final String RESULT_FILE_VERSION = "5.0";
+    public static final String TEST_RESULT_FILE_NAME = "test_result.xml";
+
+    // XML constants
+    private static final String ABI_ATTR = "abi";
+    private static final String BUGREPORT_TAG = "BugReport";
+    private static final String BUILD_FINGERPRINT = "build_fingerprint";
+    private static final String BUILD_ID = "build_id";
+    private static final String BUILD_PRODUCT = "build_product";
+    private static final String BUILD_TAG = "Build";
+    private static final String CASE_TAG = "TestCase";
+    private static final String COMMAND_LINE_ARGS = "command_line_args";
+    private static final String DEVICES_ATTR = "devices";
+    private static final String DONE_ATTR = "done";
+    private static final String END_DISPLAY_TIME_ATTR = "end_display";
+    private static final String END_TIME_ATTR = "end";
+    private static final String FAILED_ATTR = "failed";
+    private static final String FAILURE_TAG = "Failure";
+    private static final String HOST_NAME_ATTR = "host_name";
+    private static final String JAVA_VENDOR_ATTR = "java_vendor";
+    private static final String JAVA_VERSION_ATTR = "java_version";
+    private static final String LOGCAT_TAG = "Logcat";
+    private static final String LOG_URL_ATTR = "log_url";
+    private static final String MESSAGE_ATTR = "message";
+    private static final String MODULE_TAG = "Module";
+    private static final String MODULES_EXECUTED_ATTR = "modules_done";
+    private static final String MODULES_TOTAL_ATTR = "modules_total";
+    private static final String NAME_ATTR = "name";
+    private static final String NOT_EXECUTED_ATTR = "not_executed";
+    private static final String OS_ARCH_ATTR = "os_arch";
+    private static final String OS_NAME_ATTR = "os_name";
+    private static final String OS_VERSION_ATTR = "os_version";
+    private static final String PASS_ATTR = "pass";
+    private static final String REPORT_VERSION_ATTR = "report_version";
+    private static final String REFERENCE_URL_ATTR = "reference_url";
+    private static final String RESULT_ATTR = "result";
+    private static final String RESULT_TAG = "Result";
+    private static final String RUNTIME_ATTR = "runtime";
+    private static final String SCREENSHOT_TAG = "Screenshot";
+    private static final String SKIPPED_ATTR = "skipped";
+    private static final String STACK_TAG = "StackTrace";
+    private static final String START_DISPLAY_TIME_ATTR = "start_display";
+    private static final String START_TIME_ATTR = "start";
+    private static final String SUITE_NAME_ATTR = "suite_name";
+    private static final String SUITE_PLAN_ATTR = "suite_plan";
+    private static final String SUITE_VERSION_ATTR = "suite_version";
+    private static final String SUITE_BUILD_ATTR = "suite_build_number";
+    private static final String SUMMARY_TAG = "Summary";
+    private static final String TEST_TAG = "Test";
+
+
+    /**
+     * @param resultsDir
+     */
+    public static List<IInvocationResult> getResults(File resultsDir) {
+        return getResults(resultsDir, false);
+    }
+
+    /**
+     * @param resultsDir
+     * @param useChecksum
+     */
+    public static List<IInvocationResult> getResults(
+            File resultsDir, Boolean useChecksum) {
+        List<IInvocationResult> results = new ArrayList<>();
+        List<File> files = getResultDirectories(resultsDir);
+
+        for (File resultDir : files) {
+            try {
+                File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+                if (!resultFile.exists()) {
+                    continue;
+                }
+                Boolean invocationUseChecksum = useChecksum;
+                IInvocationResult invocation = new InvocationResult();
+                invocation.setRetryDirectory(resultDir);
+                ChecksumReporter checksumReporter = null;
+                if (invocationUseChecksum) {
+                    try {
+                        checksumReporter = ChecksumReporter.load(resultDir);
+                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithChecksum);
+                    } catch (ChecksumValidationException e) {
+                        // Unable to read checksum form previous execution
+                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithoutChecksum);
+                        invocationUseChecksum = false;
+                    }
+                }
+                XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+                XmlPullParser parser = factory.newPullParser();
+                parser.setInput(new FileReader(resultFile));
+
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, RESULT_TAG);
+                invocation.setStartTime(Long.valueOf(
+                        parser.getAttributeValue(NS, START_TIME_ATTR)));
+                invocation.setTestPlan(parser.getAttributeValue(NS, SUITE_PLAN_ATTR));
+                invocation.setCommandLineArgs(parser.getAttributeValue(NS, COMMAND_LINE_ARGS));
+                String deviceList = parser.getAttributeValue(NS, DEVICES_ATTR);
+                for (String device : deviceList.split(",")) {
+                    invocation.addDeviceSerial(device);
+                }
+
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, BUILD_TAG);
+                invocation.addInvocationInfo(BUILD_ID, parser.getAttributeValue(NS, BUILD_ID));
+                invocation.addInvocationInfo(BUILD_PRODUCT, parser.getAttributeValue(NS,
+                        BUILD_PRODUCT));
+                invocation.setBuildFingerprint(parser.getAttributeValue(NS, BUILD_FINGERPRINT));
+
+                // TODO(stuartscott): may want to reload these incase the retry was done with
+                // --skip-device-info flag
+                parser.nextTag();
+                parser.require(XmlPullParser.END_TAG, NS, BUILD_TAG);
+                parser.nextTag();
+                parser.require(XmlPullParser.START_TAG, NS, SUMMARY_TAG);
+                parser.nextTag();
+                parser.require(XmlPullParser.END_TAG, NS, SUMMARY_TAG);
+                while (parser.nextTag() == XmlPullParser.START_TAG) {
+                    parser.require(XmlPullParser.START_TAG, NS, MODULE_TAG);
+                    String name = parser.getAttributeValue(NS, NAME_ATTR);
+                    String abi = parser.getAttributeValue(NS, ABI_ATTR);
+                    // TODO: use AbiUtils#createId when available for use
+                    String moduleId = String.format("%s %s", abi, name);
+                    boolean done = Boolean.parseBoolean(parser.getAttributeValue(NS, DONE_ATTR));
+                    IModuleResult module = invocation.getOrCreateModule(moduleId);
+                    module.setDone(done);
+                    int notExecuted =
+                            Integer.parseInt(parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
+                    module.setNotExecuted(notExecuted);
+                    long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
+                    module.addRuntime(runtime);
+                    while (parser.nextTag() == XmlPullParser.START_TAG) {
+                        parser.require(XmlPullParser.START_TAG, NS, CASE_TAG);
+                        String caseName = parser.getAttributeValue(NS, NAME_ATTR);
+                        ICaseResult testCase = module.getOrCreateResult(caseName);
+                        while (parser.nextTag() == XmlPullParser.START_TAG) {
+                            parser.require(XmlPullParser.START_TAG, NS, TEST_TAG);
+                            String testName = parser.getAttributeValue(NS, NAME_ATTR);
+                            ITestResult test = testCase.getOrCreateResult(testName);
+                            String result = parser.getAttributeValue(NS, RESULT_ATTR);
+                            String skipped = parser.getAttributeValue(NS, SKIPPED_ATTR);
+                            if (skipped != null && Boolean.parseBoolean(skipped)) {
+                                // mark test passed and skipped
+                                test.skipped();
+                            } else {
+                                // only apply result status directly if test was not skipped
+                                test.setResultStatus(TestStatus.getStatus(result));
+                            }
+                            test.setRetry(true);
+                            while (parser.nextTag() == XmlPullParser.START_TAG) {
+                                if (parser.getName().equals(FAILURE_TAG)) {
+                                    test.setMessage(parser.getAttributeValue(NS, MESSAGE_ATTR));
+                                    if (parser.nextTag() == XmlPullParser.START_TAG) {
+                                        parser.require(XmlPullParser.START_TAG, NS, STACK_TAG);
+                                        test.setStackTrace(parser.nextText());
+                                        parser.require(XmlPullParser.END_TAG, NS, STACK_TAG);
+                                        parser.nextTag();
+                                    }
+                                    parser.require(XmlPullParser.END_TAG, NS, FAILURE_TAG);
+                                } else if (parser.getName().equals(BUGREPORT_TAG)) {
+                                    test.setBugReport(parser.nextText());
+                                    parser.require(XmlPullParser.END_TAG, NS, BUGREPORT_TAG);
+                                } else if (parser.getName().equals(LOGCAT_TAG)) {
+                                    test.setLog(parser.nextText());
+                                    parser.require(XmlPullParser.END_TAG, NS, LOGCAT_TAG);
+                                } else if (parser.getName().equals(SCREENSHOT_TAG)) {
+                                    test.setScreenshot(parser.nextText());
+                                    parser.require(XmlPullParser.END_TAG, NS, SCREENSHOT_TAG);
+                                } else {
+                                    test.setReportLog(ReportLog.parse(parser));
+                                }
+                            }
+                            parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
+                            Boolean checksumMismatch = invocationUseChecksum
+                                && !checksumReporter.containsTestResult(
+                                    test, module, invocation.getBuildFingerprint());
+                            if (checksumMismatch) {
+                                test.removeResult();
+                            }
+                        }
+                        parser.require(XmlPullParser.END_TAG, NS, CASE_TAG);
+                    }
+                    parser.require(XmlPullParser.END_TAG, NS, MODULE_TAG);
+                    Boolean checksumMismatch = invocationUseChecksum
+                        && !checksumReporter.containsModuleResult(
+                                module, invocation.getBuildFingerprint());
+                    if (checksumMismatch) {
+                        module.setDone(false);
+                    }
+                }
+                parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
+                results.add(invocation);
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        // Sort the table entries on each entry's timestamp.
+        Collections.sort(results,  (result1, result2) -> Long.compare(
+                result1.getStartTime(),
+                result2.getStartTime()));
+        return results;
+    }
+
+    /**
+     * @param result
+     * @param resultDir
+     * @param startTime
+     * @param referenceUrl A nullable string that can contain a URL to a related data
+     * @param logUrl A nullable string that can contain a URL to related log files
+     * @param commandLineArgs A string containing the arguments to the run command
+     * @return The result file created.
+     * @throws IOException
+     * @throws XmlPullParserException
+     */
+    public static File writeResults(String suiteName, String suiteVersion, String suitePlan,
+            String suiteBuild, IInvocationResult result, File resultDir,
+            long startTime, long endTime, String referenceUrl, String logUrl,
+            String commandLineArgs)
+                    throws IOException, XmlPullParserException {
+        int passed = result.countResults(TestStatus.PASS);
+        int failed = result.countResults(TestStatus.FAIL);
+        int notExecuted = result.getNotExecuted();
+        File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+        OutputStream stream = new FileOutputStream(resultFile);
+        XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
+        serializer.setOutput(stream, ENCODING);
+        serializer.startDocument(ENCODING, false);
+        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        serializer.processingInstruction(
+                "xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"");
+        serializer.startTag(NS, RESULT_TAG);
+        serializer.attribute(NS, START_TIME_ATTR, String.valueOf(startTime));
+        serializer.attribute(NS, END_TIME_ATTR, String.valueOf(endTime));
+        serializer.attribute(NS, START_DISPLAY_TIME_ATTR, toReadableDateString(startTime));
+        serializer.attribute(NS, END_DISPLAY_TIME_ATTR, toReadableDateString(endTime));
+
+        serializer.attribute(NS, SUITE_NAME_ATTR, suiteName);
+        serializer.attribute(NS, SUITE_VERSION_ATTR, suiteVersion);
+        serializer.attribute(NS, SUITE_PLAN_ATTR, suitePlan);
+        serializer.attribute(NS, SUITE_BUILD_ATTR, suiteBuild);
+        serializer.attribute(NS, REPORT_VERSION_ATTR, RESULT_FILE_VERSION);
+        serializer.attribute(NS, COMMAND_LINE_ARGS, nullToEmpty(commandLineArgs));
+
+        if (referenceUrl != null) {
+            serializer.attribute(NS, REFERENCE_URL_ATTR, referenceUrl);
+        }
+
+        if (logUrl != null) {
+            serializer.attribute(NS, LOG_URL_ATTR, logUrl);
+        }
+
+        // Device Info
+        Set<String> devices = result.getDeviceSerials();
+        StringBuilder deviceList = new StringBuilder();
+        boolean first = true;
+        for (String device : devices) {
+            if (first) {
+                first = false;
+            } else {
+                deviceList.append(",");
+            }
+            deviceList.append(device);
+        }
+        serializer.attribute(NS, DEVICES_ATTR, deviceList.toString());
+
+        // Host Info
+        String hostName = "";
+        try {
+            hostName = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException ignored) {}
+        serializer.attribute(NS, HOST_NAME_ATTR, hostName);
+        serializer.attribute(NS, OS_NAME_ATTR, System.getProperty("os.name"));
+        serializer.attribute(NS, OS_VERSION_ATTR, System.getProperty("os.version"));
+        serializer.attribute(NS, OS_ARCH_ATTR, System.getProperty("os.arch"));
+        serializer.attribute(NS, JAVA_VENDOR_ATTR, System.getProperty("java.vendor"));
+        serializer.attribute(NS, JAVA_VERSION_ATTR, System.getProperty("java.version"));
+
+        // Build Info
+        serializer.startTag(NS, BUILD_TAG);
+        for (Entry<String, String> entry : result.getInvocationInfo().entrySet()) {
+            serializer.attribute(NS, entry.getKey(), entry.getValue());
+            if (Strings.isNullOrEmpty(result.getBuildFingerprint()) &&
+                entry.getKey().equals(BUILD_FINGERPRINT)) {
+                result.setBuildFingerprint(entry.getValue());
+            }
+        }
+        serializer.endTag(NS, BUILD_TAG);
+
+        // Summary
+        serializer.startTag(NS, SUMMARY_TAG);
+        serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
+        serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
+        serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
+        serializer.attribute(NS, MODULES_EXECUTED_ATTR,
+                Integer.toString(result.getModuleCompleteCount()));
+        serializer.attribute(NS, MODULES_TOTAL_ATTR,
+                Integer.toString(result.getModules().size()));
+        serializer.endTag(NS, SUMMARY_TAG);
+
+        // Results
+        for (IModuleResult module : result.getModules()) {
+            serializer.startTag(NS, MODULE_TAG);
+            serializer.attribute(NS, NAME_ATTR, module.getName());
+            serializer.attribute(NS, ABI_ATTR, module.getAbi());
+            serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
+            serializer.attribute(NS, DONE_ATTR, Boolean.toString(module.isDone()));
+            serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(module.getNotExecuted()));
+            for (ICaseResult cr : module.getResults()) {
+                serializer.startTag(NS, CASE_TAG);
+                serializer.attribute(NS, NAME_ATTR, cr.getName());
+                for (ITestResult r : cr.getResults()) {
+                    TestStatus status = r.getResultStatus();
+                    if (status == null) {
+                        continue; // test was not executed, don't report
+                    }
+                    serializer.startTag(NS, TEST_TAG);
+                    serializer.attribute(NS, RESULT_ATTR, status.getValue());
+                    serializer.attribute(NS, NAME_ATTR, r.getName());
+                    if (r.isSkipped()) {
+                        serializer.attribute(NS, SKIPPED_ATTR, Boolean.toString(true));
+                    }
+                    String message = r.getMessage();
+                    if (message != null) {
+                        serializer.startTag(NS, FAILURE_TAG);
+                        serializer.attribute(NS, MESSAGE_ATTR, message);
+                        String stackTrace = r.getStackTrace();
+                        if (stackTrace != null) {
+                            serializer.startTag(NS, STACK_TAG);
+                            serializer.text(stackTrace);
+                            serializer.endTag(NS, STACK_TAG);
+                        }
+                        serializer.endTag(NS, FAILURE_TAG);
+                    }
+                    String bugreport = r.getBugReport();
+                    if (bugreport != null) {
+                        serializer.startTag(NS, BUGREPORT_TAG);
+                        serializer.text(bugreport);
+                        serializer.endTag(NS, BUGREPORT_TAG);
+                    }
+                    String logcat = r.getLog();
+                    if (logcat != null) {
+                        serializer.startTag(NS, LOGCAT_TAG);
+                        serializer.text(logcat);
+                        serializer.endTag(NS, LOGCAT_TAG);
+                    }
+                    String screenshot = r.getScreenshot();
+                    if (screenshot != null) {
+                        serializer.startTag(NS, SCREENSHOT_TAG);
+                        serializer.text(screenshot);
+                        serializer.endTag(NS, SCREENSHOT_TAG);
+                    }
+                    ReportLog report = r.getReportLog();
+                    if (report != null) {
+                        ReportLog.serialize(serializer, report);
+                    }
+                    serializer.endTag(NS, TEST_TAG);
+                }
+                serializer.endTag(NS, CASE_TAG);
+            }
+            serializer.endTag(NS, MODULE_TAG);
+        }
+        serializer.endDocument();
+        createChecksum(resultDir, result);
+        return resultFile;
+    }
+
+    private static void createChecksum(File resultDir, IInvocationResult invocationResult) {
+        RetryChecksumStatus retryStatus = invocationResult.getRetryChecksumStatus();
+        switch (retryStatus) {
+            case NotRetry: case RetryWithChecksum:
+                // Do not disrupt the process if there is a problem generating checksum.
+                ChecksumReporter.tryCreateChecksum(resultDir, invocationResult);
+                break;
+            case RetryWithoutChecksum:
+                // If the previous run has an invalid checksum file,
+                // copy it into current results folder for future troubleshooting
+                File retryDirectory = invocationResult.getRetryDirectory();
+                Path retryChecksum = FileSystems.getDefault().getPath(
+                        retryDirectory.getAbsolutePath(), ChecksumReporter.NAME);
+                if (!retryChecksum.toFile().exists()) {
+                    // if no checksum file, check for a copy from a previous retry
+                    retryChecksum = FileSystems.getDefault().getPath(
+                            retryDirectory.getAbsolutePath(), ChecksumReporter.PREV_NAME);
+                }
+
+                if (retryChecksum.toFile().exists()) {
+                    File checksumCopy = new File(resultDir, ChecksumReporter.PREV_NAME);
+                    try (FileOutputStream stream = new FileOutputStream(checksumCopy)) {
+                        Files.copy(retryChecksum, stream);
+                    } catch (IOException e) {
+                        // Do not disrupt the process if there is a problem copying checksum
+                    }
+                }
+        }
+    }
+
+
+    /**
+     * Find the IInvocationResult for the given sessionId.
+     */
+    public static IInvocationResult findResult(File resultsDir, Integer sessionId)
+            throws FileNotFoundException {
+        return findResult(resultsDir, sessionId, true);
+    }
+
+    /**
+     * Find the IInvocationResult for the given sessionId.
+     */
+    private static IInvocationResult findResult(
+            File resultsDir, Integer sessionId, Boolean useChecksum) throws FileNotFoundException {
+        if (sessionId < 0) {
+            throw new IllegalArgumentException(
+                String.format("Invalid session id [%d] ", sessionId));
+        }
+
+        List<IInvocationResult> results = getResults(resultsDir, useChecksum);
+        if (results == null || sessionId >= results.size()) {
+            throw new RuntimeException(String.format("Could not find session [%d]", sessionId));
+        }
+        return results.get(sessionId);
+    }
+
+    /**
+     * Get a list of child directories that contain test invocation results
+     * @param resultsDir the root test result directory
+     * @return
+     */
+    public static List<File> getResultDirectories(File resultsDir) {
+        List<File> directoryList = new ArrayList<>();
+        File[] files = resultsDir.listFiles();
+        if (files == null || files.length == 0) {
+            // No results, just return the empty list
+            return directoryList;
+        }
+        for (File resultDir : files) {
+            if (!resultDir.isDirectory()) {
+                continue;
+            }
+            // Only include if it contain results file
+            File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+            if (!resultFile.exists()) {
+                continue;
+            }
+            directoryList.add(resultDir);
+        }
+        Collections.sort(directoryList, (d1, d2) -> d1.getName().compareTo(d2.getName()));
+        return directoryList;
+    }
+
+    /**
+     * Return the given time as a {@link String} suitable for displaying.
+     * <p/>
+     * Example: Fri Aug 20 15:13:03 PDT 2010
+     *
+     * @param time the epoch time in ms since midnight Jan 1, 1970
+     */
+    static String toReadableDateString(long time) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
+        return dateFormat.format(new Date(time));
+    }
+
+    /**
+     * When nullable is null, return an empty string. Otherwise, return the value in nullable.
+     */
+    private static String nullToEmpty(String nullable) {
+        return nullable == null ? "" : nullable;
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/TestFilter.java b/common/util/src/com/android/compatibility/common/util/TestFilter.java
deleted file mode 100644
index 460e34f..0000000
--- a/common/util/src/com/android/compatibility/common/util/TestFilter.java
+++ /dev/null
@@ -1,131 +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.util;
-
-/**
- * Represents a filter for including and excluding tests.
- */
-public class TestFilter {
-
-    private final String mAbi;
-    private final String mName;
-    private final String mTest;
-
-    /**
-     * Builds a new {@link TestFilter} from the given string. Filters can be in one of four forms,
-     * the instance will be initialized as;
-     * -"name"                 -> abi = null, name = "name", test = null
-     * -"name" "test..."       -> abi = null, name = "name", test = "test..."
-     * -"abi" "name"           -> abi = "abi", name = "name", test = null
-     * -"abi" "name" "test..." -> abi = "abi", name = "name", test = "test..."
-     *
-     * Test identifier can contain multiple parts, eg parameterized tests.
-     *
-     * @param filter the filter to parse
-     * @return the {@link TestFilter}
-     */
-    public static TestFilter createFrom(String filter) {
-        if (filter.isEmpty()) {
-            throw new IllegalArgumentException("Filter was empty");
-        }
-        String[] parts = filter.split(" ");
-        String abi = null, name = null, test = null;
-        // Either:
-        // <name>
-        // <name> <test>
-        // <abi> <name>
-        // <abi> <name> <test>
-        if (parts.length == 1) {
-            name = parts[0];
-        } else {
-            int index = 0;
-            if (AbiUtils.isAbiSupportedByCompatibility(parts[0])) {
-                abi = parts[0];
-                index++;
-            }
-            name = parts[index];
-            index++;
-            parts = filter.split(" ", index + 1);
-            if (parts.length > index) {
-                test = parts[index];
-            }
-        }
-        return new TestFilter(abi, name, test);
-    }
-
-    /**
-     * Creates a new {@link TestFilter} from the given parts.
-     *
-     * @param abi The ABI must be supported {@link AbiUtils#isAbiSupportedByCompatibility(String)}
-     * @param name The module's name
-     * @param test The test's identifier eg <package>.<class>#<method>
-     */
-    public TestFilter(String abi, String name, String test) {
-        mAbi = abi;
-        mName = name;
-        mTest = test;
-    }
-
-    /**
-     * Returns a String representation of this filter. This function is the inverse of
-     * {@link TestFilter#createFrom(String)}.
-     *
-     * For a valid filter f;
-     * <pre>
-     * {@code
-     * new TestFilter(f).toString().equals(f)
-     * }
-     * </pre>
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        if (mAbi != null) {
-            sb.append(mAbi.trim());
-            sb.append(" ");
-        }
-        if (mName != null) {
-            sb.append(mName.trim());
-        }
-        if (mTest != null) {
-            sb.append(" ");
-            sb.append(mTest.trim());
-        }
-        return sb.toString();
-    }
-
-    /**
-     * @return the abi of this filter, or null if not specified.
-     */
-    public String getAbi() {
-        return mAbi;
-    }
-
-    /**
-     * @return the module name of this filter, or null if not specified.
-     */
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * @return the test identifier of this filter, or null if not specified.
-     */
-    public String getTest() {
-        return mTest;
-    }
-
-}
diff --git a/common/util/src/com/android/compatibility/common/util/TestResult.java b/common/util/src/com/android/compatibility/common/util/TestResult.java
index 36b6e5a..18a8b4c 100644
--- a/common/util/src/com/android/compatibility/common/util/TestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/TestResult.java
@@ -30,6 +30,7 @@
     private String mLog;
     private String mScreenshot;
     private boolean mIsRetry;
+    private boolean mSkipped;
 
     /**
      * Create a {@link TestResult} for the given test name.
@@ -173,6 +174,7 @@
      */
     @Override
     public void failed(String trace) {
+        mSkipped = false;
         setResultStatus(TestStatus.FAIL);
         int index = trace.indexOf('\n');
         if (index < 0) {
@@ -189,6 +191,7 @@
      */
     @Override
     public void passed(ReportLog report) {
+        mSkipped = false;
         if (getResultStatus() != TestStatus.FAIL) {
             setResultStatus(TestStatus.PASS);
             if (report != null) {
@@ -202,9 +205,18 @@
      */
     @Override
     public void skipped() {
-        // TODO(b/28386054): Report SKIPPED as a separate result.
-        // For now, we mark this as PASS.
-        setResultStatus(TestStatus.PASS);
+        if (getResultStatus() == null) {
+            mSkipped = true;
+            setResultStatus(TestStatus.PASS);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isSkipped() {
+        return mSkipped;
     }
 
     /**
@@ -220,6 +232,7 @@
         mLog = null;
         mScreenshot = null;
         mIsRetry = false;
+        mSkipped = false;
     }
 
     /**
diff --git a/common/util/tests/Android.mk b/common/util/tests/Android.mk
index aa39ef5..5e3370b 100644
--- a/common/util/tests/Android.mk
+++ b/common/util/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := junit-host kxml2-2.3.0 tradefed-prebuilt compatibility-common-util-hostsidelib
+LOCAL_JAVA_LIBRARIES := junit-host kxml2-2.3.0 tradefed compatibility-common-util-hostsidelib
 
 LOCAL_MODULE := compatibility-common-util-tests
 
diff --git a/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java b/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java
deleted file mode 100644
index 567da54..0000000
--- a/common/util/tests/src/com/android/compatibility/common/util/AbiUtilsTest.java
+++ /dev/null
@@ -1,58 +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.util;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link AbiUtils}
- */
-public class AbiUtilsTest extends TestCase {
-
-    private static final String MODULE_NAME = "ModuleName";
-    private static final String ABI_NAME = "mips64";
-    private static final String ABI_FLAG = "--abi mips64 ";
-    private static final String ABI_ID = "mips64 ModuleName";
-
-    public void testCreateAbiFlag() {
-        String flag = AbiUtils.createAbiFlag(ABI_NAME);
-        assertEquals("Incorrect flag created", ABI_FLAG, flag);
-    }
-
-    public void testCreateId() {
-        String id = AbiUtils.createId(ABI_NAME, MODULE_NAME);
-        assertEquals("Incorrect id created", ABI_ID, id);
-    }
-
-    public void testParseId() {
-        String[] parts = AbiUtils.parseId(ABI_ID);
-        assertEquals("Wrong size array", 2, parts.length);
-        assertEquals("Wrong abi name", ABI_NAME, parts[0]);
-        assertEquals("Wrong module name", MODULE_NAME, parts[1]);
-    }
-
-    public void testParseName() {
-        String name = AbiUtils.parseTestName(ABI_ID);
-        assertEquals("Incorrect module name", MODULE_NAME, name);
-    }
-
-    public void testParseAbi() {
-        String abi = AbiUtils.parseAbi(ABI_ID);
-        assertEquals("Incorrect abi name", ABI_NAME, abi);
-    }
-
-}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
index cf1892a..df50d11 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
@@ -16,6 +16,8 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.tradefed.util.FileUtil;
+
 import junit.framework.TestCase;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -81,24 +83,28 @@
     public void testCorrectConfig() throws Exception {
         DynamicConfig config = new DynamicConfig();
         File file = createFileFromStr(correctConfig);
-        config.initializeConfig(file);
-
-        assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
-        assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
-        assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
-        assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
-        assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+        try {
+            config.initializeConfig(file);
+            assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
+            assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
+            assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
+            assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
+            assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+        } finally {
+            FileUtil.deleteFile(file);
+        }
     }
 
     public void testConfigWithWrongNodeName() throws Exception {
         DynamicConfig config = new DynamicConfig();
         File file = createFileFromStr(configWrongNodeName);
-
         try {
             config.initializeConfig(file);
             fail("Cannot detect error when config file has wrong node name");
         } catch (XmlPullParserException e) {
             //expected
+        } finally {
+            FileUtil.deleteFile(file);
         }
     }
 
@@ -107,6 +113,7 @@
         FileOutputStream stream = new FileOutputStream(file);
         stream.write(configStr.getBytes());
         stream.flush();
+        stream.close();
         return file;
     }
 }
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java b/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
deleted file mode 100644
index e71e1c3..0000000
--- a/common/util/tests/src/com/android/compatibility/common/util/ModuleResultTest.java
+++ /dev/null
@@ -1,119 +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.util;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link ModuleResult}
- */
-public class ModuleResultTest extends TestCase {
-
-    private static final String NAME = "ModuleName";
-    private static final String NAME_2 = "ModuleName2";
-    private static final String ABI = "mips64";
-    private static final String ID = AbiUtils.createId(ABI, NAME);
-    private static final String ID_2 = AbiUtils.createId(ABI, NAME_2);
-    private static final String CLASS = "android.test.FoorBar";
-    private static final String CLASS_2 = "android.test.FoorBar2";
-    private static final String METHOD_1 = "testBlah1";
-    private static final String METHOD_2 = "testBlah2";
-    private static final String METHOD_3 = "testBlah3";
-    private static final String STACK_TRACE = "Something small is not alright\n " +
-            "at four.big.insects.Marley.sing(Marley.java:10)";
-    private ModuleResult mResult;
-
-    @Override
-    public void setUp() throws Exception {
-        mResult = new ModuleResult(ID);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mResult = null;
-    }
-
-    public void testAccessors() throws Exception {
-        assertEquals("Incorrect module ID", ID, mResult.getId());
-        assertEquals("Incorrect module ABI", ABI, mResult.getAbi());
-        assertEquals("Incorrect module name", NAME, mResult.getName());
-    }
-
-    public void testResultCreation() throws Exception {
-        ICaseResult caseResult = mResult.getOrCreateResult(CLASS);
-        // Should create one
-        assertEquals("Expected one result", 1, mResult.getResults().size());
-        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
-        // Should not create another one
-        ICaseResult caseResult2 = mResult.getOrCreateResult(CLASS);
-        assertEquals("Expected the same result", caseResult, caseResult2);
-        assertEquals("Expected one result", 1, mResult.getResults().size());
-    }
-
-    public void testCountResults() throws Exception {
-        ICaseResult testCase = mResult.getOrCreateResult(CLASS);
-        testCase.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
-        testCase.getOrCreateResult(METHOD_2).failed(STACK_TRACE);
-        testCase.getOrCreateResult(METHOD_3).passed(null);
-        assertEquals("Expected two failures", 2, mResult.countResults(TestStatus.FAIL));
-        assertEquals("Expected one pass", 1, mResult.countResults(TestStatus.PASS));
-    }
-
-    public void testMergeModule() throws Exception {
-        ICaseResult caseResult = mResult.getOrCreateResult(CLASS);
-        caseResult.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
-        caseResult.getOrCreateResult(METHOD_3).passed(null);
-
-        ICaseResult caseResult2 = mResult.getOrCreateResult(CLASS_2);
-        caseResult2.getOrCreateResult(METHOD_1).failed(STACK_TRACE);
-        caseResult2.getOrCreateResult(METHOD_3).passed(null);
-
-        assertEquals("Expected two results", 2, mResult.getResults().size());
-        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
-        assertTrue("Expected test result", mResult.getResults().contains(caseResult2));
-
-        ModuleResult otherResult = new ModuleResult(ID);
-        // Same class but all passing tests
-        ICaseResult otherCaseResult = otherResult.getOrCreateResult(CLASS);
-        otherCaseResult.getOrCreateResult(METHOD_1).passed(null);
-        otherCaseResult.getOrCreateResult(METHOD_2).passed(null);
-        otherCaseResult.getOrCreateResult(METHOD_3).passed(null);
-        otherResult.setDone(true);
-
-        mResult.mergeFrom(otherResult);
-
-        assertEquals("Expected two results", 2, mResult.getResults().size());
-        assertTrue("Expected test result", mResult.getResults().contains(caseResult));
-        assertTrue("Expected test result", mResult.getResults().contains(caseResult2));
-        assertTrue(mResult.isDone());
-    }
-
-    public void testSetDone() {
-        assertFalse(mResult.isDone());
-        mResult.setDone(true);
-        assertTrue(mResult.isDone());
-    }
-
-    public void testMergeModule_mismatchedModuleId() throws Exception {
-
-        ModuleResult otherResult = new ModuleResult(ID_2);
-        try {
-            mResult.mergeFrom(otherResult);
-            fail("Expected IlleglArgumentException");
-        } catch (IllegalArgumentException expected) {}
-    }
-}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
index c8d4682..0da5f2d 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -20,9 +20,6 @@
 
 import junit.framework.TestCase;
 
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.util.List;
 import java.util.Arrays;
 
 /**
@@ -38,7 +35,8 @@
     private static final String SUMMARY_XML =
             HEADER_XML + "\r\n" +
             "<Summary>\r\n" +
-            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
+            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" "
+            + "message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
             "    <Value>1.0</Value>\r\n" +
             "  </Metric>\r\n" +
             "</Summary>";
@@ -66,7 +64,7 @@
 
     public void testSerialize_summaryOnly() throws Exception {
         mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
-        assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:68"),
+        assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:66"),
                 ReportLog.serialize(mReportLog));
     }
 
@@ -78,7 +76,7 @@
     public void testSerialize_full() throws Exception {
         mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
         mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
-        assertEquals(String.format(FULL_XML, "testSerialize_full:79"),
+        assertEquals(String.format(FULL_XML, "testSerialize_full:77"),
                 ReportLog.serialize(mReportLog));
     }
 
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
new file mode 100644
index 0000000..c7471c7
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -0,0 +1,347 @@
+/*
+ * 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.util;
+
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link ResultHandler}
+ */
+public class ResultHandlerTest extends TestCase {
+
+    private static final String SUITE_NAME = "CTS";
+    private static final String SUITE_VERSION = "5.0";
+    private static final String SUITE_PLAN = "cts";
+    private static final String SUITE_BUILD = "12345";
+    private static final String REPORT_VERSION = "5.0";
+    private static final String OS_NAME = System.getProperty("os.name");
+    private static final String OS_VERSION = System.getProperty("os.version");
+    private static final String OS_ARCH = System.getProperty("os.arch");
+    private static final String JAVA_VENDOR = System.getProperty("java.vendor");
+    private static final String JAVA_VERSION = System.getProperty("java.version");
+    private static final String NAME_A = "ModuleA";
+    private static final String NAME_B = "ModuleB";
+    private static final String DONE_A = "false";
+    private static final String DONE_B = "true";
+    private static final String NOT_EXECUTED_A = "1";
+    private static final String NOT_EXECUTED_B = "0";
+    private static final String RUNTIME_A = "100";
+    private static final String RUNTIME_B = "200";
+    private static final String ABI = "mips64";
+    private static final String ID_A = AbiUtils.createId(ABI, NAME_A);
+    private static final String ID_B = AbiUtils.createId(ABI, NAME_B);
+
+    private static final String BUILD_ID = "build_id";
+    private static final String BUILD_PRODUCT = "build_product";
+    private static final String EXAMPLE_BUILD_ID = "XYZ";
+    private static final String EXAMPLE_BUILD_PRODUCT = "wolverine";
+
+    private static final String DEVICE_A = "device123";
+    private static final String DEVICE_B = "device456";
+    private static final String DEVICES = "device456,device123";
+    private static final String CLASS_A = "android.test.Foor";
+    private static final String CLASS_B = "android.test.Bar";
+    private static final String METHOD_1 = "testBlah1";
+    private static final String METHOD_2 = "testBlah2";
+    private static final String METHOD_3 = "testBlah3";
+    private static final String METHOD_4 = "testBlah4";
+    private static final String METHOD_5 = "testBlah5";
+    private static final String SUMMARY_SOURCE = String.format("%s#%s:20", CLASS_B, METHOD_4);
+    private static final String SUMMARY_MESSAGE = "Headline";
+    private static final double SUMMARY_VALUE = 9001;
+    private static final String MESSAGE = "Something small is not alright";
+    private static final String STACK_TRACE = "Something small is not alright\n " +
+            "at four.big.insects.Marley.sing(Marley.java:10)";
+    private static final String BUG_REPORT = "https://cnsviewer.corp.google.com/cns/bugreport.txt";
+    private static final String LOGCAT = "https://cnsviewer.corp.google.com/cns/logcat.gz";
+    private static final String SCREENSHOT = "https://cnsviewer.corp.google.com/screenshot.png";
+    private static final long START_MS = 1431586801000L;
+    private static final long END_MS = 1431673199000L;
+    private static final String START_DISPLAY = "Fri Aug 20 15:13:03 PDT 2010";
+    private static final String END_DISPLAY = "Fri Aug 20 15:13:04 PDT 2010";
+
+    private static final String REFERENCE_URL="http://android.com";
+    private static final String LOG_URL ="file:///path/to/logs";
+    private static final String COMMAND_LINE_ARGS = "cts -m CtsMyModuleTestCases";
+    private static final String XML_BASE =
+            "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
+            "<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n" +
+            "<Result start=\"%d\" end=\"%d\" start_display=\"%s\"" +
+            "end_display=\"%s\" suite_name=\"%s\" suite_version=\"%s\" " +
+            "suite_plan=\"%s\" suite_build_number=\"%s\" report_version=\"%s\" " +
+            "devices=\"%s\" host_name=\"%s\"" +
+            "os_name=\"%s\" os_version=\"%s\" os_arch=\"%s\" java_vendor=\"%s\"" +
+            "java_version=\"%s\" reference_url=\"%s\" log_url=\"%s\"" +
+            "command_line_args=\"%s\">\n" +
+            "%s%s%s" +
+            "</Result>";
+    private static final String XML_BUILD_INFO =
+            "  <Build build_fingerprint=\"%s\" " + BUILD_ID + "=\"%s\" " +
+               BUILD_PRODUCT + "=\"%s\" />\n";
+    private static final String XML_SUMMARY =
+            "  <Summary pass=\"%d\" failed=\"%d\" not_executed=\"%d\" " +
+            "modules_done=\"1\" modules_total=\"1\" />\n";
+    private static final String XML_MODULE =
+            "  <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\" not_executed=\"%s\">\n" +
+            "%s" +
+            "  </Module>\n";
+    private static final String XML_CASE =
+            "    <TestCase name=\"%s\">\n" +
+            "%s" +
+            "    </TestCase>\n";
+    private static final String XML_TEST_PASS =
+            "      <Test result=\"pass\" name=\"%s\"/>\n";
+    private static final String XML_TEST_SKIP =
+            "      <Test result=\"pass\" name=\"%s\" skipped=\"true\"/>\n";
+    private static final String XML_TEST_FAIL =
+            "      <Test result=\"fail\" name=\"%s\">\n" +
+            "        <Failure message=\"%s\">\n" +
+            "          <StackTrace>%s</StackTrace>\n" +
+            "        </Failure>\n" +
+            "        <BugReport>%s</BugReport>\n" +
+            "        <Logcat>%s</Logcat>\n" +
+            "        <Screenshot>%s</Screenshot>\n" +
+            "      </Test>\n";
+    private static final String XML_TEST_RESULT =
+            "      <Test result=\"pass\" name=\"%s\">\n" +
+            "        <Summary>\n" +
+            "          <Metric source=\"%s\" message=\"%s\" score_type=\"%s\" score_unit=\"%s\">\n" +
+            "             <Value>%s</Value>\n" +
+            "          </Metric>\n" +
+            "        </Summary>\n" +
+            "      </Test>\n";
+    private File resultsDir = null;
+    private File resultDir = null;
+
+    @Override
+    public void setUp() throws Exception {
+        resultsDir = FileUtil.createTempDir("results");
+        resultDir = FileUtil.createTempDir("12345", resultsDir);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        FileUtil.recursiveDelete(resultsDir);
+    }
+
+    public void testSerialization() throws Exception {
+        IInvocationResult result = new InvocationResult();
+        result.setStartTime(START_MS);
+        result.setTestPlan(SUITE_PLAN);
+        result.addDeviceSerial(DEVICE_A);
+        result.addDeviceSerial(DEVICE_B);
+        result.addInvocationInfo(BUILD_ID, EXAMPLE_BUILD_ID);
+        result.addInvocationInfo(BUILD_PRODUCT, EXAMPLE_BUILD_PRODUCT);
+        // Module A: test1 passes, test2 not executed
+        IModuleResult moduleA = result.getOrCreateModule(ID_A);
+        moduleA.setDone(false);
+        moduleA.addRuntime(Integer.parseInt(RUNTIME_A));
+        ICaseResult moduleACase = moduleA.getOrCreateResult(CLASS_A);
+        ITestResult moduleATest1 = moduleACase.getOrCreateResult(METHOD_1);
+        moduleATest1.setResultStatus(TestStatus.PASS);
+        ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
+        moduleATest2.setResultStatus(null); // not executed test
+        moduleA.setNotExecuted(1);
+        // Module B: test3 fails, test4 passes with report log, test5 passes with skip
+        IModuleResult moduleB = result.getOrCreateModule(ID_B);
+        moduleB.setDone(true);
+        moduleB.addRuntime(Integer.parseInt(RUNTIME_B));
+        ICaseResult moduleBCase = moduleB.getOrCreateResult(CLASS_B);
+        ITestResult moduleBTest3 = moduleBCase.getOrCreateResult(METHOD_3);
+        moduleBTest3.setResultStatus(TestStatus.FAIL);
+        moduleBTest3.setMessage(MESSAGE);
+        moduleBTest3.setStackTrace(STACK_TRACE);
+        moduleBTest3.setBugReport(BUG_REPORT);
+        moduleBTest3.setLog(LOGCAT);
+        moduleBTest3.setScreenshot(SCREENSHOT);
+        ITestResult moduleBTest4 = moduleBCase.getOrCreateResult(METHOD_4);
+        moduleBTest4.setResultStatus(TestStatus.PASS);
+        ReportLog report = new ReportLog();
+        ReportLog.Metric summary = new ReportLog.Metric(SUMMARY_SOURCE, SUMMARY_MESSAGE,
+                SUMMARY_VALUE, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
+        report.setSummary(summary);
+        moduleBTest4.setReportLog(report);
+        ITestResult moduleBTest5 = moduleBCase.getOrCreateResult(METHOD_5);
+        moduleBTest5.skipped();
+
+        // Serialize to file
+        ResultHandler.writeResults(SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD,
+                result, resultDir, START_MS, END_MS, REFERENCE_URL, LOG_URL,
+                COMMAND_LINE_ARGS);
+
+        // Parse the results and assert correctness
+        checkResult(ResultHandler.getResults(resultsDir), resultDir);
+    }
+
+    public void testParsing() throws Exception {
+        File resultsDir = null;
+        FileWriter writer = null;
+        try {
+            resultsDir = FileUtil.createTempDir("results");
+            File resultDir = FileUtil.createTempDir("12345", resultsDir);
+            // Create the result file
+            File resultFile = new File(resultDir, ResultHandler.TEST_RESULT_FILE_NAME);
+            writer = new FileWriter(resultFile);
+            String buildInfo = String.format(XML_BUILD_INFO, DEVICE_A,
+                    EXAMPLE_BUILD_ID, EXAMPLE_BUILD_PRODUCT);
+            String summary = String.format(XML_SUMMARY, 2, 1, 1);
+            String moduleATest = String.format(XML_TEST_PASS, METHOD_1);
+            String moduleACases = String.format(XML_CASE, CLASS_A, moduleATest);
+            String moduleA = String.format(XML_MODULE, NAME_A, ABI, DEVICE_A, RUNTIME_A, DONE_A,
+                    NOT_EXECUTED_A, moduleACases);
+            String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE,
+                    BUG_REPORT, LOGCAT, SCREENSHOT);
+            String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4, SUMMARY_SOURCE,
+                    SUMMARY_MESSAGE, ResultType.HIGHER_BETTER.toReportString(),
+                    ResultUnit.SCORE.toReportString(), Double.toString(SUMMARY_VALUE));
+            String moduleBTest5 = String.format(XML_TEST_SKIP, METHOD_5);
+            String moduleBTests = String.join("", moduleBTest3, moduleBTest4, moduleBTest5);
+            String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
+            String moduleB = String.format(XML_MODULE, NAME_B, ABI, DEVICE_B, RUNTIME_B, DONE_B,
+                    NOT_EXECUTED_B, moduleBCases);
+            String modules = String.join("", moduleA, moduleB);
+            String hostName = "";
+            try {
+                hostName = InetAddress.getLocalHost().getHostName();
+            } catch (UnknownHostException ignored) {}
+            String output = String.format(XML_BASE, START_MS, END_MS, START_DISPLAY, END_DISPLAY,
+                    SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD, REPORT_VERSION, DEVICES,
+                    hostName, OS_NAME, OS_VERSION, OS_ARCH, JAVA_VENDOR,
+                    JAVA_VERSION, REFERENCE_URL, LOG_URL, COMMAND_LINE_ARGS,
+                    buildInfo, summary, modules);
+            writer.write(output);
+            writer.flush();
+
+            // Parse the results and assert correctness
+            checkResult(ResultHandler.getResults(resultsDir), resultDir);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+            FileUtil.recursiveDelete(resultsDir);
+        }
+    }
+
+    private void checkResult(List<IInvocationResult> results, File resultDir) throws Exception {
+        assertEquals("Expected 1 result", 1, results.size());
+        IInvocationResult result = results.get(0);
+        assertEquals("Expected 3 passes", 3, result.countResults(TestStatus.PASS));
+        assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
+        assertEquals("Expected 1 not executed", 1, result.getNotExecuted());
+
+        Map<String, String> buildInfo = result.getInvocationInfo();
+        assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
+        assertEquals("Incorrect Build Product",
+            EXAMPLE_BUILD_PRODUCT, buildInfo.get(BUILD_PRODUCT));
+
+        Set<String> serials = result.getDeviceSerials();
+        assertTrue("Missing device", serials.contains(DEVICE_A));
+        assertTrue("Missing device", serials.contains(DEVICE_B));
+        assertEquals("Expected 2 devices", 2, serials.size());
+        assertTrue("Incorrect devices", serials.contains(DEVICE_A) && serials.contains(DEVICE_B));
+        assertEquals("Incorrect start time", START_MS, result.getStartTime());
+        assertEquals("Incorrect test plan", SUITE_PLAN, result.getTestPlan());
+
+        List<IModuleResult> modules = result.getModules();
+        assertEquals("Expected 2 modules", 2, modules.size());
+
+        IModuleResult moduleA = modules.get(0);
+        assertEquals("Expected 1 pass", 1, moduleA.countResults(TestStatus.PASS));
+        assertEquals("Expected 0 failures", 0, moduleA.countResults(TestStatus.FAIL));
+        assertEquals("Incorrect ABI", ABI, moduleA.getAbi());
+        assertEquals("Incorrect name", NAME_A, moduleA.getName());
+        assertEquals("Incorrect ID", ID_A, moduleA.getId());
+        assertEquals("Incorrect runtime", Integer.parseInt(RUNTIME_A), moduleA.getRuntime());
+        List<ICaseResult> moduleACases = moduleA.getResults();
+        assertEquals("Expected 1 test case", 1, moduleACases.size());
+        ICaseResult moduleACase = moduleACases.get(0);
+        assertEquals("Incorrect name", CLASS_A, moduleACase.getName());
+        List<ITestResult> moduleAResults = moduleACase.getResults();
+        assertEquals("Expected 1 result", 1, moduleAResults.size());
+        ITestResult moduleATest1 = moduleAResults.get(0);
+        assertEquals("Incorrect name", METHOD_1, moduleATest1.getName());
+        assertEquals("Incorrect result", TestStatus.PASS, moduleATest1.getResultStatus());
+        assertNull("Unexpected bugreport", moduleATest1.getBugReport());
+        assertNull("Unexpected log", moduleATest1.getLog());
+        assertNull("Unexpected screenshot", moduleATest1.getScreenshot());
+        assertNull("Unexpected message", moduleATest1.getMessage());
+        assertNull("Unexpected stack trace", moduleATest1.getStackTrace());
+        assertNull("Unexpected report", moduleATest1.getReportLog());
+
+        IModuleResult moduleB = modules.get(1);
+        assertEquals("Expected 2 passes", 2, moduleB.countResults(TestStatus.PASS));
+        assertEquals("Expected 1 failure", 1, moduleB.countResults(TestStatus.FAIL));
+        assertEquals("Incorrect ABI", ABI, moduleB.getAbi());
+        assertEquals("Incorrect name", NAME_B, moduleB.getName());
+        assertEquals("Incorrect ID", ID_B, moduleB.getId());
+        assertEquals("Incorrect runtime", Integer.parseInt(RUNTIME_B), moduleB.getRuntime());
+        List<ICaseResult> moduleBCases = moduleB.getResults();
+        assertEquals("Expected 1 test case", 1, moduleBCases.size());
+        ICaseResult moduleBCase = moduleBCases.get(0);
+        assertEquals("Incorrect name", CLASS_B, moduleBCase.getName());
+        List<ITestResult> moduleBResults = moduleBCase.getResults();
+        assertEquals("Expected 3 results", 3, moduleBResults.size());
+        ITestResult moduleBTest3 = moduleBResults.get(0);
+        assertEquals("Incorrect name", METHOD_3, moduleBTest3.getName());
+        assertEquals("Incorrect result", TestStatus.FAIL, moduleBTest3.getResultStatus());
+        assertEquals("Incorrect bugreport", BUG_REPORT, moduleBTest3.getBugReport());
+        assertEquals("Incorrect log", LOGCAT, moduleBTest3.getLog());
+        assertEquals("Incorrect screenshot", SCREENSHOT, moduleBTest3.getScreenshot());
+        assertEquals("Incorrect message", MESSAGE, moduleBTest3.getMessage());
+        assertEquals("Incorrect stack trace", STACK_TRACE, moduleBTest3.getStackTrace());
+        assertNull("Unexpected report", moduleBTest3.getReportLog());
+        ITestResult moduleBTest4 = moduleBResults.get(1);
+        assertEquals("Incorrect name", METHOD_4, moduleBTest4.getName());
+        assertEquals("Incorrect result", TestStatus.PASS, moduleBTest4.getResultStatus());
+        assertNull("Unexpected bugreport", moduleBTest4.getBugReport());
+        assertNull("Unexpected log", moduleBTest4.getLog());
+        assertNull("Unexpected screenshot", moduleBTest4.getScreenshot());
+        assertNull("Unexpected message", moduleBTest4.getMessage());
+        assertNull("Unexpected stack trace", moduleBTest4.getStackTrace());
+        ReportLog report = moduleBTest4.getReportLog();
+        assertNotNull("Expected report", report);
+        ReportLog.Metric summary = report.getSummary();
+        assertNotNull("Expected report summary", summary);
+        assertEquals("Incorrect source", SUMMARY_SOURCE, summary.getSource());
+        assertEquals("Incorrect message", SUMMARY_MESSAGE, summary.getMessage());
+        assertEquals("Incorrect type", ResultType.HIGHER_BETTER, summary.getType());
+        assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
+        assertTrue("Incorrect values", Arrays.equals(new double[] { SUMMARY_VALUE },
+                summary.getValues()));
+        ITestResult moduleBTest5 = moduleBResults.get(2);
+        assertEquals("Incorrect name", METHOD_5, moduleBTest5.getName());
+        assertEquals("Incorrect result", TestStatus.PASS, moduleBTest5.getResultStatus());
+        assertTrue("Expected skipped", moduleBTest5.isSkipped());
+        assertNull("Unexpected bugreport", moduleBTest5.getBugReport());
+        assertNull("Unexpected log", moduleBTest5.getLog());
+        assertNull("Unexpected screenshot", moduleBTest5.getScreenshot());
+        assertNull("Unexpected message", moduleBTest5.getMessage());
+        assertNull("Unexpected stack trace", moduleBTest5.getStackTrace());
+        assertNull("Unexpected report", moduleBTest5.getReportLog());
+    }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
index e6c6a87..96d67e6 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
@@ -27,15 +27,13 @@
 
     public UnitTests() {
         super();
-        addTestSuite(AbiUtilsTest.class);
         addTestSuite(CaseResultTest.class);
         addTestSuite(DynamicConfigTest.class);
         addTestSuite(MetricsXmlSerializerTest.class);
-        addTestSuite(ModuleResultTest.class);
         addTestSuite(MultipartFormTest.class);
         addTestSuite(ReportLogTest.class);
+        addTestSuite(ResultHandlerTest.class);
         addTestSuite(StatTest.class);
-        addTestSuite(TestFilterTest.class);
         addTestSuite(TestResultTest.class);
     }
 
diff --git a/hostsidetests/aadb/Android.mk b/hostsidetests/aadb/Android.mk
index f20f603..5cc2c10 100644
--- a/hostsidetests/aadb/Android.mk
+++ b/hostsidetests/aadb/Android.mk
@@ -22,7 +22,7 @@
 # Adb test cases, but name 'aadb' ensures adb tests run before all other modules depending on adb
 LOCAL_MODULE := CtsAadbHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.aadb
 
diff --git a/hostsidetests/abioverride/Android.mk b/hostsidetests/abioverride/Android.mk
index f77303b..88c44d9 100644
--- a/hostsidetests/abioverride/Android.mk
+++ b/hostsidetests/abioverride/Android.mk
@@ -27,9 +27,7 @@
 
 LOCAL_CTS_TEST_PACKAGE := android.host.abioverride
 
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/abioverride/AndroidTest.xml b/hostsidetests/abioverride/AndroidTest.xml
index 7819f9b..2a3a963 100644
--- a/hostsidetests/abioverride/AndroidTest.xml
+++ b/hostsidetests/abioverride/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAbiOverrideHostTestCases.jar" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
diff --git a/hostsidetests/abioverride/app/Android.mk b/hostsidetests/abioverride/app/Android.mk
index 56393c5..cdf063c 100755
--- a/hostsidetests/abioverride/app/Android.mk
+++ b/hostsidetests/abioverride/app/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsabioverride
 
diff --git a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
index 26d35a4..c2f14f0 100644
--- a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
+++ b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
@@ -16,7 +16,7 @@
 
 package android.abioverride.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -72,7 +72,8 @@
         super.setUp();
         ITestDevice device = getDevice();
         device.uninstallPackage(PACKAGE);
-        File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        File app = buildHelper.getTestFile(APK_NAME);
         String[] options = {};
         device.installPackage(app, false, options);
     }
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 258192d..6afcce8 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsAppSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_JAVA_RESOURCE_DIRS := res
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index b77eef2..881f5b8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -24,7 +24,6 @@
 import static android.appsecurity.cts.SplitTests.PKG;
 
 import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
-import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index e500b00..36b0921 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -16,8 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -25,6 +24,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.RunUtil;
 
 import java.io.BufferedReader;
@@ -103,7 +103,8 @@
     }
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
new file mode 100644
index 0000000..69ff55e
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.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 android.appsecurity.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.TestResult;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * Base class.
+ */
+public class BaseAppSecurityTest extends DeviceTestCase implements IBuildReceiver {
+    protected static final int USER_SYSTEM = 0; // From the UserHandle class.
+
+    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+
+    protected IBuildInfo mBuildInfo;
+
+    /** Whether multi-user is supported. */
+    protected boolean mSupportsMultiUser;
+    protected boolean mIsSplitSystemUser;
+    protected int mPrimaryUserId;
+    /** Users we shouldn't delete in the tests */
+    private ArrayList<Integer> mFixedUsers;
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuildInfo = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        assertNotNull(mBuildInfo); // ensure build has been set before test is run.
+
+        mSupportsMultiUser = getDevice().getMaxNumberOfUsersSupported() > 1;
+        mIsSplitSystemUser = checkIfSplitSystemUser();
+        mPrimaryUserId = getDevice().getPrimaryUserId();
+        mFixedUsers = new ArrayList();
+        mFixedUsers.add(mPrimaryUserId);
+        if (mPrimaryUserId != USER_SYSTEM) {
+            mFixedUsers.add(USER_SYSTEM);
+        }
+        getDevice().switchUser(mPrimaryUserId);
+        removeTestUsers();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        removeTestUsers();
+        super.tearDown();
+    }
+
+    /**
+     * @return the userid of the created user
+     */
+    protected int createUser() throws DeviceNotAvailableException, IllegalStateException {
+        final String command = "pm create-user "
+                + "TestUser_" + System.currentTimeMillis();
+        CLog.d("Starting command: " + command);
+        final String output = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + output);
+
+        if (output.startsWith("Success")) {
+            try {
+                return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
+            } catch (NumberFormatException e) {
+                CLog.e("Failed to parse result: %s", output);
+            }
+        } else {
+            CLog.e("Failed to create user: %s", output);
+        }
+        throw new IllegalStateException();
+    }
+
+    private void removeTestUsers() throws Exception {
+        for (int userId : getDevice().listUsers()) {
+            if (!mFixedUsers.contains(userId)) {
+                getDevice().removeUser(userId);
+            }
+        }
+    }
+
+    private boolean checkIfSplitSystemUser() throws DeviceNotAvailableException {
+        final String commandOuput = getDevice().executeShellCommand(
+                "getprop ro.fw.system_user_split");
+        return "y".equals(commandOuput) || "yes".equals(commandOuput)
+                || "1".equals(commandOuput) || "true".equals(commandOuput)
+                || "on".equals(commandOuput);
+    }
+
+    protected void installTestAppForUser(String apk, int userId) throws Exception {
+        if (userId < 0) {
+            userId = mPrimaryUserId;
+        }
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        assertNull(getDevice().installPackageForUser(
+                buildHelper.getTestFile(apk), true, false, userId, "-t"));
+    }
+
+    protected boolean isAppVisibleForUser(String packageName, int userId,
+            boolean matchUninstalled) throws DeviceNotAvailableException {
+        String command = "cmd package list packages --user " + userId;
+        if (matchUninstalled) command += " -u";
+        String output = getDevice().executeShellCommand(command);
+        return output.contains(packageName);
+    }
+
+    private void printTestResult(TestRunResult runResult) {
+        for (Map.Entry<TestIdentifier, TestResult> testEntry :
+                runResult.getTestResults().entrySet()) {
+            TestResult testResult = testEntry.getValue();
+            CLog.d("Test " + testEntry.getKey() + ": " + testResult.getStatus());
+            if (testResult.getStatus() != TestStatus.PASSED) {
+                CLog.d(testResult.getStackTrace());
+            }
+        }
+    }
+
+    protected boolean runDeviceTestsAsUser(String packageName,
+            String testClassName, String testMethodName, int userId) throws Exception {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = packageName + testClassName;
+        }
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                packageName, RUNNER, getDevice().getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        CollectingTestListener listener = new CollectingTestListener();
+        assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
+
+        TestRunResult runResult = listener.getCurrentRunResults();
+        printTestResult(runResult);
+        return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index d81abb6..a064287 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 
 /**
  * Set of tests that verify behavior of
@@ -31,9 +31,8 @@
         super.setUp();
 
         getDevice().uninstallPackage(PROVIDER_PKG);
-
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(PROVIDER_APK), false));
     }
 
     @Override
@@ -70,4 +69,20 @@
     public void testTransferDocument() throws Exception {
         runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testTransferDocument");
     }
+
+    public void testFindDocumentPathInScopedAccess() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testFindDocumentPathInScopedAccess");
+    }
+
+    public void testOpenDocumentAtInitialLocation() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenDocumentAtInitialLocation");
+    }
+
+    public void testOpenDocumentTreeAtInitialLocation() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testOpenDocumentTreeAtInitialLocation");
+    }
+
+    public void testCreateDocumentAtInitialLocation() throws Exception {
+        runDeviceTests(CLIENT_PKG, ".DocumentsClientTest", "testCreateDocumentAtInitialLocation");
+    }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index 009d81b..ceb7539 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -68,8 +68,7 @@
 
     protected void reinstallClientPackage() throws Exception {
         getDevice().uninstallPackage(CLIENT_PKG);
-
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(CLIENT_APK), false));
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index ae619fe..ed46225 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -16,8 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -25,6 +24,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -66,7 +66,8 @@
     }
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 53a54dd..1f7c6be 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -101,7 +101,8 @@
     private static final String LOG_TAG = "AppsecurityHostTests";
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     /**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
new file mode 100644
index 0000000..115ebf4
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.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.appsecurity.cts;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+/**
+ * Tests for visibility of packages installed in one user, in a different user.
+ */
+public class PackageVisibilityTest extends BaseAppSecurityTest {
+
+    private static final String TINY_APK = "CtsPkgInstallTinyApp.apk";
+    private static final String TINY_PKG = "android.appsecurity.cts.tinyapp";
+
+    private static final String TEST_APK = "CtsPkgAccessApp.apk";
+    private static final String TEST_PKG = "com.android.cts.packageaccessapp";
+
+    private static final boolean MATCH_UNINSTALLED = true;
+    private static final boolean MATCH_NORMAL = false;
+
+    private String mOldVerifierValue;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mOldVerifierValue =
+                getDevice().executeShellCommand("settings get global package_verifier_enable");
+        getDevice().executeShellCommand("settings put global package_verifier_enable 0");
+        installTestAppForUser(TEST_APK, mPrimaryUserId);
+    }
+
+    public void tearDown() throws Exception {
+        getDevice().uninstallPackage(TEST_PKG);
+        getDevice().executeShellCommand("settings put global package_verifier_enable "
+                + mOldVerifierValue);
+        super.tearDown();
+    }
+
+    public void testUninstalledPackageVisibility() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+
+        int userId = createUser();
+        assertTrue(userId > 0);
+        getDevice().startUser(userId);
+        installTestAppForUser(TEST_APK, userId);
+        installTestAppForUser(TEST_APK, mPrimaryUserId);
+
+        installTestAppForUser(TINY_APK, mPrimaryUserId);
+
+        // It is visible for the installed user, using shell commands
+        assertTrue(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_NORMAL));
+        assertTrue(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_UNINSTALLED));
+
+        // Try the same from an app
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_inUser", mPrimaryUserId));
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_inUserUninstalled", mPrimaryUserId));
+
+        // It is not visible for the other user using shell commands
+        assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
+        assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
+
+        // Try the same from an app
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_notInOtherUser", userId));
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled", userId));
+
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", userId));
+
+        getDevice().uninstallPackage(TINY_PKG);
+
+        // Install for the new user
+        installTestAppForUser(TINY_APK, userId);
+
+        // It is visible for the installed user
+        assertTrue(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
+        assertTrue(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
+
+        // It is not visible for the other user
+        assertFalse(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_NORMAL));
+        assertFalse(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_UNINSTALLED));
+
+        // Uninstall with keep data
+        uninstallWithKeepDataForUser(TINY_PKG, userId);
+
+        // It is visible for the installed user, but only if match uninstalled
+        assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
+        assertTrue(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
+
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCanSeeTiny", userId));
+
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled",
+                mPrimaryUserId));
+        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", mPrimaryUserId));
+
+        getDevice().uninstallPackage(TINY_PKG);
+        getDevice().uninstallPackage(TEST_PKG);
+    }
+
+    protected void uninstallWithKeepDataForUser(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        final String command = "pm uninstall -k --user " + userId + " " + packageName;
+        getDevice().executeShellCommand(command);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 072a533..0e53c46 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -36,7 +36,7 @@
     private static final String APK_24 = "CtsUsePermissionApp24.apk";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -45,7 +45,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -53,7 +53,7 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(PKG);
     }
@@ -67,8 +67,7 @@
 
     public void testFail() throws Exception {
         // Sanity check that remote failure is host failure
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testFail");
@@ -79,8 +78,7 @@
 
     public void testKill() throws Exception {
         // Sanity check that remote kill is host failure
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testKill");
@@ -90,17 +88,13 @@
     }
 
     public void testCompatDefault22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testCompatDefault");
     }
 
     public void testCompatRevoked22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                     "testCompatRevoked_part1");
@@ -112,72 +106,61 @@
     }
 
     public void testNoRuntimePrompt22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testNoRuntimePrompt");
     }
 
     public void testDefault23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testDefault");
     }
 
     public void testGranted23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testGranted");
     }
 
     public void testInteractiveGrant23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testInteractiveGrant");
     }
 
     public void testRuntimeGroupGrantSpecificity23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRuntimeGroupGrantSpecificity");
     }
 
     public void testRuntimeGroupGrantExpansion23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRuntimeGroupGrantExpansion");
     }
 
     public void testCancelledPermissionRequest23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testCancelledPermissionRequest");
     }
 
     public void testRequestGrantedPermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestGrantedPermission");
     }
 
     public void testDenialWithPrejudice23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testDenialWithPrejudice");
     }
 
     public void testRevokeAffectsWholeGroup23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testRevokeAffectsWholeGroup_part1");
@@ -188,8 +171,7 @@
     }
 
     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1");
@@ -201,89 +183,75 @@
     }
 
     public void testRequestNonRuntimePermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestNonRuntimePermission");
     }
 
     public void testRequestNonExistentPermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestNonExistentPermission");
     }
 
     public void testRequestPermissionFromTwoGroups23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestPermissionFromTwoGroups");
     }
 
 //    public void testOnlyRequestedPermissionsGranted24() throws Exception {
-//        assertNull(getDevice().installPackage(
-//                MigrationHelper.getTestFile(mCtsBuild, APK_24), false, false));
+//        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_24), false, false));
 //        runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest24",
 //                "testOnlyRequestedPermissionsGranted");
 //    }
 
     public void testUpgradeKeepsPermissions() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testAllPermissionsGrantedByDefault");
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testAllPermissionsGrantedOnUpgrade");
     }
 
     public void testNoDowngradePermissionModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
-            assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, APK_22), true, false));
+            assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), true, false));
             fail("Permission mode downgrade not allowed");
         } catch (AssertionError expected) {
         }
     }
 
     public void testNoResidualPermissionsOnUninstall() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testNoResidualPermissionsOnUninstall_part1");
         assertNull(getDevice().uninstallPackage(PKG));
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testNoResidualPermissionsOnUninstall_part2");
     }
 
     public void testRevokePropagatedOnUpgradeOldToNewModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                     "testRevokePropagatedOnUpgradeOldToNewModel_part1");
             fail("App must be killed on a permission revoke");
         } catch (AssertionError expected) {
         }
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeOldToNewModel_part2");
     }
 
     public void testRevokePropagatedOnUpgradeNewToNewModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeNewToNewModel_part1");
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeNewToNewModel_part2");
     }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index be3f83a..ca218ef 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -16,8 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -25,6 +24,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 /**
  * Tests that verify intent filters.
@@ -47,7 +47,7 @@
             + " com.android.cts.priv.ctsshim";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -56,7 +56,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -64,13 +64,12 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(SHIM_PKG);
         getDevice().uninstallPackage(TEST_PKG);
 
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(TEST_APK), false));
         getDevice().executeShellCommand("pm enable " + SHIM_PKG);
     }
 
@@ -86,7 +85,7 @@
     public void testPrivilegedAppUpgradeRestricted() throws Exception {
         getDevice().uninstallPackage(SHIM_PKG);
         assertEquals(RESTRICTED_UPGRADE_FAILURE, getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_FAIL_APK), true));
+                mBuildHelper.getTestFile(SHIM_UPDATE_FAIL_APK), true));
     }
 
     public void testSystemAppPriorities() throws Exception {
@@ -102,7 +101,7 @@
         
         try {
             assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+                    mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
             runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testPrivilegedAppUpgradePriorities");
         } finally {
             getDevice().uninstallPackage(SHIM_PKG);
@@ -121,7 +120,7 @@
         runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testPrivAppAndEnabled");
         try {
             assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+                    mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
             getDevice().executeShellCommand("pm disable-user " + SHIM_PKG);
             runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testUpdatedPrivAppAndDisabled");
             getDevice().executeShellCommand("pm enable " + SHIM_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index ad00adb..00ccd4c 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -16,8 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -25,6 +24,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -334,7 +334,8 @@
         }
 
         T addApk(String apk) throws FileNotFoundException {
-            mApks.add(MigrationHelper.getTestFile(mBuild, apk));
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+            mApks.add(buildHelper.getTestFile(apk));
             return (T) this;
         }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index c8e608e..cf8a354 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -35,7 +35,7 @@
     private static final String APK_COMPAT = "CtsUsesLibraryAppCompat.apk";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -44,7 +44,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -52,7 +52,7 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(PKG);
     }
@@ -65,20 +65,17 @@
     }
 
     public void testUsesLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testUsesLibrary");
     }
 
     public void testMissingLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testMissingLibrary");
     }
 
     public void testDuplicateLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testDuplicateLibrary");
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
index ce47e01..ec89ce9 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index acba1f4..1566066 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -33,6 +33,8 @@
 
 import com.android.cts.documentclient.MyActivity.Result;
 
+import java.util.List;
+
 /**
  * Tests for {@link DocumentsProvider} and interaction with platform intents
  * like {@link Intent#ACTION_OPEN_DOCUMENT}.
@@ -428,4 +430,98 @@
             cursorDst.close();
         }
     }
+
+    public void testFindDocumentPathInScopedAccess() throws Exception {
+        if (!supportedHardware()) return;
+
+        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+        mDevice.waitForIdle();
+        findRoot("CtsCreate").click();
+
+        mDevice.waitForIdle();
+        findDocument("DIR2").click();
+        mDevice.waitForIdle();
+        findSaveButton().click();
+
+        final Result result = mActivity.getResult();
+        final Uri uri = result.data.getData();
+
+        // We should have selected DIR2
+        Uri doc = DocumentsContract.buildDocumentUriUsingTree(uri,
+                DocumentsContract.getTreeDocumentId(uri));
+
+        assertEquals("DIR2", getColumn(doc, Document.COLUMN_DISPLAY_NAME));
+
+        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
+
+        // Create some documents
+        Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR, "my dir");
+        Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");
+
+        writeFully(dirPic, "dirPic".getBytes());
+
+        // Find the path of a document
+        final List<String> path = DocumentsContract.findDocumentPath(resolver, dirPic);
+        assertEquals(3, path.size());
+        assertEquals(DocumentsContract.getTreeDocumentId(uri), path.get(0));
+        assertEquals(DocumentsContract.getDocumentId(dir), path.get(1));
+        assertEquals(DocumentsContract.getDocumentId(dirPic), path.get(2));
+    }
+
+    public void testOpenDocumentAtInitialLocation() throws Exception {
+        if (!supportedHardware()) return;
+
+        // Clear DocsUI's storage to avoid it opening stored last location
+        // which may make this test pass "luckily".
+        clearDocumentsUi();
+
+        final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:file1");
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+
+        assertTrue(findDocument("FILE1").exists());
+    }
+
+    public void testOpenDocumentTreeAtInitialLocation() throws Exception {
+        if (!supportedHardware()) return;
+
+        // Clear DocsUI's storage to avoid it opening stored last location
+        // which may make this test pass "luckily".
+        clearDocumentsUi();
+
+        final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:dir2");
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_OPEN_DOCUMENT_TREE);
+        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+
+        assertTrue(findDocument("FILE4").exists());
+    }
+
+    public void testCreateDocumentAtInitialLocation() throws Exception {
+        if (!supportedHardware()) return;
+
+        // Clear DocsUI's storage to avoid it opening stored last location
+        // which may make this test pass "luckily".
+        clearDocumentsUi();
+
+        final Uri treeUri = DocumentsContract.buildTreeDocumentUri(PROVIDER_PACKAGE, "doc:local");
+        final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, "doc:file1");
+        final Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_CREATE_DOCUMENT);
+        intent.setType("plain/text");
+        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+        mDevice.waitForIdle();
+
+        assertTrue(findDocument("FILE1").exists());
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
index a26ec2d..be5efe6 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.documentclient;
 
-import static android.cts.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -46,6 +46,8 @@
 abstract class DocumentsClientTestCase extends InstrumentationTestCase {
     private static final String TAG = "DocumentsClientTestCase";
 
+    static final String PROVIDER_PACKAGE = "com.android.cts.documentprovider";
+
     protected UiDevice mDevice;
     protected MyActivity mActivity;
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
index ef51768..915d432 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
index 19ba2f7..eabf4ba 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
@@ -27,6 +27,7 @@
 import android.os.ParcelFileDescriptor;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Path;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
 import android.util.Log;
@@ -38,6 +39,7 @@
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -264,6 +266,43 @@
     }
 
     @Override
+    public Path findDocumentPath(String documentId, String parentDocumentId)
+            throws FileNotFoundException {
+        if (!mDocs.containsKey(documentId)) {
+            throw new FileNotFoundException(documentId + " is not found.");
+        }
+
+        final Map<String, String> parentMap = new HashMap<>();
+        for (Doc doc : mDocs.values()) {
+            for (Doc childDoc : doc.children) {
+                parentMap.put(childDoc.docId, doc.docId);
+            }
+        }
+
+        String currentDocId = documentId;
+        final LinkedList<String> path = new LinkedList<>();
+        while (!currentDocId.equals(parentDocumentId)
+                && !currentDocId.equals(mLocalRoot.docId)
+                && !currentDocId.equals(mCreateRoot.docId)) {
+            path.addFirst(currentDocId);
+            currentDocId = parentMap.get(currentDocId);
+        }
+
+        if (parentDocumentId != null && !currentDocId.equals(parentDocumentId)) {
+            throw new FileNotFoundException(documentId + " is not found under " + parentDocumentId);
+        }
+
+        // Add the root doc / parent doc
+        path.addFirst(currentDocId);
+
+        String rootId = null;
+        if (parentDocumentId == null) {
+            rootId = currentDocId.equals(mLocalRoot.docId) ? "local" : "create";
+        }
+        return new Path(rootId, path);
+    }
+
+    @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
index d362ed6..930ac82 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk b/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk
new file mode 100644
index 0000000..d038a70
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    ub-uiautomator
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsPkgAccessApp
+
+LOCAL_SDK_VERSION := test_current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml
new file mode 100644
index 0000000..8558b73
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.cts.packageaccessapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.packageaccessapp"
+                     android:label="Test to check package visibility."/>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/src/com/android/cts/packageaccessapp/PackageAccessTest.java b/hostsidetests/appsecurity/test-apps/PackageAccessApp/src/com/android/cts/packageaccessapp/PackageAccessTest.java
new file mode 100644
index 0000000..ad64806
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/src/com/android/cts/packageaccessapp/PackageAccessTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.packageaccessapp;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.internal.runners.statements.Fail;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class PackageAccessTest {
+
+    private String TINY_PKG = "android.appsecurity.cts.tinyapp";
+
+    private UiDevice mUiDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @Test
+    public void testPackageAccess_inUser() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        try {
+            PackageInfo pi = pm.getPackageInfo(TINY_PKG, 0);
+            assertNotNull(pi);
+        } catch (NameNotFoundException e) {
+            fail("Package must be found");
+        }
+    }
+
+    @Test
+    public void testPackageAccess_inUserUninstalled() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        try {
+            PackageInfo pi = pm.getPackageInfo(TINY_PKG, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+            assertNotNull(pi);
+        } catch (NameNotFoundException e) {
+            fail("Package must be found");
+        }
+    }
+
+    @Test
+    public void testPackageAccess_notInOtherUser() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        try {
+            PackageInfo pi = pm.getPackageInfo(TINY_PKG, 0);
+            // If it doesn't throw an exception, then at least it should be null
+            assertNull(pi); 
+        } catch (NameNotFoundException e) {
+        }
+    }
+
+    @Test
+    public void testPackageAccess_notInOtherUserUninstalled() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        try {
+            PackageInfo pi = pm.getPackageInfo(TINY_PKG, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+            // If it doesn't throw an exception, then at least it should be null
+            assertNull(pi);
+        } catch (NameNotFoundException e) {
+        }
+    }
+
+    @Test
+    public void testPackageAccess_getPackagesCantSeeTiny() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        List<PackageInfo> packages = pm.getInstalledPackages(
+                PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (PackageInfo pi : packages) {
+            if (TINY_PKG.equals(pi.packageName)) {
+                fail(TINY_PKG + " visible in user");
+            }
+        }
+    }
+
+    @Test
+    public void testPackageAccess_getPackagesCanSeeTiny() throws Exception {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        List<PackageInfo> packages = pm.getInstalledPackages(
+                PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (PackageInfo pi : packages) {
+            if (TINY_PKG.equals(pi.packageName)) {
+                return;
+            }
+        }
+        fail(TINY_PKG + " not found in getInstalledPackages()");
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
index 1ea4eba..bb171e2 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
index 9ee5921..34f4170 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
@@ -19,7 +19,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java \
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
index c8e05c5..e8aefb9 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
@@ -19,7 +19,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
index d280372..739f220 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
@@ -19,7 +19,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
index 2d5dd4f..581af78 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index d0b7ef5..c4a0913 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -21,9 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsAtraceHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.atrace
 
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
index b8aeb31..fe81705 100644
--- a/hostsidetests/atrace/AndroidTest.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -16,5 +16,6 @@
 <configuration description="Config for CTS atrace host test cases">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAtraceHostTestCases.jar" />
+        <option name="runtime-hint" value="9m" />
     </test>
 </configuration>
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 4fc041c..3ab7d95 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,7 +16,7 @@
 
 package android.atrace.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
@@ -201,7 +201,8 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+            File testAppFile = buildHelper.getTestFile(TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/compilation/Android.mk b/hostsidetests/compilation/Android.mk
index 64e7063..723e5c3 100644
--- a/hostsidetests/compilation/Android.mk
+++ b/hostsidetests/compilation/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_MODULE := CtsCompilationTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_STATIC_JAVA_LIBRARIES := guavalib
 
diff --git a/hostsidetests/compilation/AndroidTest.xml b/hostsidetests/compilation/AndroidTest.xml
index acae9b5..ec92bec 100644
--- a/hostsidetests/compilation/AndroidTest.xml
+++ b/hostsidetests/compilation/AndroidTest.xml
@@ -16,5 +16,6 @@
 <configuration description="Config for CTS Compilation Test">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsCompilationTestCases.jar" />
+        <option name="runtime-hint" value="9m45s" />
     </test>
 </configuration>
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/content/Android.mk b/hostsidetests/content/Android.mk
new file mode 100644
index 0000000..3d27776
--- /dev/null
+++ b/hostsidetests/content/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    ../appsecurity/src/android/appsecurity/cts/Utils.java
+
+LOCAL_MODULE := CtsSyncContentHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+
+LOCAL_JAVA_RESOURCE_DIRS := res
+
+LOCAL_CTS_TEST_PACKAGE := android.content
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH)/test-apps)
diff --git a/hostsidetests/content/AndroidTest.xml b/hostsidetests/content/AndroidTest.xml
new file mode 100644
index 0000000..4e87916
--- /dev/null
+++ b/hostsidetests/content/AndroidTest.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.
+-->
+<configuration description="Config for the CTS Content host tests">
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsSyncContentHostTestCases.jar" />
+        <option name="runtime-hint" value="2m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/content/src/android/content/cts/SyncAdapterAccountAccessHostTest.java b/hostsidetests/content/src/android/content/cts/SyncAdapterAccountAccessHostTest.java
new file mode 100644
index 0000000..7207732
--- /dev/null
+++ b/hostsidetests/content/src/android/content/cts/SyncAdapterAccountAccessHostTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.content.cts;
+
+import android.appsecurity.cts.Utils;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of the content framework.
+ */
+public class SyncAdapterAccountAccessHostTest extends DeviceTestCase
+        implements IAbiReceiver, IBuildReceiver {
+    private static final String ACCOUNT_ACCESS_TESTS_OTHER_CERT_APK =
+            "CtsSyncAccountAccessOtherCertTestCases.apk";
+    private static final String ACCOUNT_ACCESS_TESTS_OTHER_CERT_PKG =
+            "com.android.cts.content";
+
+    private static final String ACCOUNT_ACCESS_TESTS_SAME_CERT_APK =
+            "CtsSyncAccountAccessSameCertTestCases.apk";
+    private static final String ACCOUNT_ACCESS_TESTS_SAME_CERT_PKG =
+            "com.android.cts.content";
+
+    private static final String STUBS_APK =
+            "CtsSyncAccountAccessStubs.apk";
+    private static final String STUBS_PKG =
+            "com.android.cts.stub";
+
+    private IAbi mAbi;
+    private CompatibilityBuildHelper mBuildHelper;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        getDevice().uninstallPackage(STUBS_PKG);
+
+        assertNull(getDevice().installPackage(mBuildHelper
+                .getTestFile(STUBS_APK), false, false));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        getDevice().uninstallPackage(STUBS_APK);
+    }
+
+    public void testSameCertAuthenticatorCanSeeAccount() throws Exception {
+        getDevice().uninstallPackage(ACCOUNT_ACCESS_TESTS_SAME_CERT_PKG);
+
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+                ACCOUNT_ACCESS_TESTS_SAME_CERT_APK), false, false));
+        try {
+            runDeviceTests(ACCOUNT_ACCESS_TESTS_SAME_CERT_PKG,
+                    "com.android.cts.content.CtsSyncAccountAccessSameCertTestCases",
+                    "testAccountAccess_sameCertAsAuthenticatorCanSeeAccount");
+        } finally {
+            getDevice().uninstallPackage(ACCOUNT_ACCESS_TESTS_SAME_CERT_PKG);
+        }
+    }
+
+    public void testOtherCertAuthenticatorCanSeeAccount() throws Exception {
+        getDevice().uninstallPackage(ACCOUNT_ACCESS_TESTS_OTHER_CERT_PKG);
+
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(
+                ACCOUNT_ACCESS_TESTS_OTHER_CERT_APK), false, false));
+        try {
+            runDeviceTests(ACCOUNT_ACCESS_TESTS_OTHER_CERT_PKG,
+                    "com.android.cts.content.CtsSyncAccountAccessOtherCertTestCases",
+                    "testAccountAccess_otherCertAsAuthenticatorCanNotSeeAccount");
+        } finally {
+            getDevice().uninstallPackage(ACCOUNT_ACCESS_TESTS_OTHER_CERT_PKG);
+        }
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+            throws DeviceNotAvailableException {
+        Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+    }
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk
new file mode 100644
index 0000000..7ec8630
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/Android.mk
@@ -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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctstestrunner ub-uiautomator
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+  ../CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/StubActivity.java \
+  ../CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncAdapter.java \
+  ../CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncService.java
+
+LOCAL_PACKAGE_NAME := CtsSyncAccountAccessOtherCertTestCases
+
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.xml
new file mode 100644
index 0000000..cee1a50
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.content">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".StubActivity"/>
+
+        <service android:name=".SyncService">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter"/>
+            </intent-filter>
+            <meta-data android:name="android.content.SyncAdapter"
+                   android:resource="@xml/syncadapter" />
+        </service>
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.content" />
+
+</manifest>
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/res/xml/syncadapter.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/res/xml/syncadapter.xml
new file mode 100644
index 0000000..f55a19a
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/res/xml/syncadapter.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.
+-->
+
+<sync-adapter
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:contentAuthority="com.android.cts.stub.provider"
+    android:accountType="com.stub"
+    android:userVisible="false"
+    android:supportsUploading="false"
+    android:allowParallelSyncs="false"
+    android:isAlwaysSyncable="true">
+</sync-adapter>
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
new file mode 100644
index 0000000..fe4414b
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -0,0 +1,117 @@
+/*
+ * 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.content;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncRequest;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Tests whether a sync adapter can access accounts.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CtsSyncAccountAccessOtherCertTestCases {
+    private static final long SYNC_TIMEOUT_MILLIS = 10000; // 20 sec
+    private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec
+
+    public static final String TOKEN_TYPE_REMOVE_ACCOUNTS = "TOKEN_TYPE_REMOVE_ACCOUNTS";
+
+    @Test
+    public void testAccountAccess_otherCertAsAuthenticatorCanNotSeeAccount() throws Exception {
+        Intent intent = new Intent(getContext(), StubActivity.class);
+        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+
+        AccountManager accountManager = getContext().getSystemService(AccountManager.class);
+        Bundle result = accountManager.addAccount("com.stub", null, null, null, activity,
+                null, null).getResult();
+
+        Account addedAccount = new Account(
+                result.getString(AccountManager.KEY_ACCOUNT_NAME),
+                result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+
+        try {
+            CountDownLatch latch = new CountDownLatch(1);
+
+            SyncAdapter.setOnPerformSyncDelegate((Account account, Bundle extras,
+                    String authority, ContentProviderClient provider, SyncResult syncResult)
+                    -> latch.countDown());
+
+            Bundle extras = new Bundle();
+            extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
+            extras.putBoolean(ContentResolver.SYNC_EXTRAS_PRIORITY, true);
+            extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+            SyncRequest request = new SyncRequest.Builder()
+                    .setSyncAdapter(null, "com.android.cts.stub.provider")
+                    .syncOnce()
+                    .setExtras(extras)
+                    .setExpedited(true)
+                    .setManual(true)
+                    .build();
+            ContentResolver.requestSync(request);
+
+            assertFalse(latch.await(SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+
+            UiDevice uiDevice = getUiDevice();
+
+            uiDevice.openNotification();
+            uiDevice.wait(Until.hasObject(By.text("Permission requested")),
+                    UI_TIMEOUT_MILLIS);
+
+            uiDevice.findObject(By.text("Permission requested")).click();
+            uiDevice.wait(Until.hasObject(By.text("ALLOW")),
+                    UI_TIMEOUT_MILLIS);
+
+            uiDevice.findObject(By.text("ALLOW")).click();
+
+            ContentResolver.requestSync(request);
+
+            assertTrue(latch.await(SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+        } finally {
+            // Ask the differently signed authenticator to drop all accounts
+            accountManager.getAuthToken(addedAccount, TOKEN_TYPE_REMOVE_ACCOUNTS,
+                    null, false, null, null);
+        }
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    private UiDevice getUiDevice() {
+        return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+    }
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk
new file mode 100644
index 0000000..0b63c14
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSyncAccountAccessSameCertTestCases
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.xml
new file mode 100644
index 0000000..ea46d61
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.content">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".StubActivity"/>
+
+        <service android:name=".SyncService">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter"/>
+            </intent-filter>
+            <meta-data android:name="android.content.SyncAdapter"
+                android:resource="@xml/syncadapter" />
+        </service>
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.content" />
+
+</manifest>
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/res/xml/syncadapter.xml b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/res/xml/syncadapter.xml
new file mode 100644
index 0000000..f55a19a
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/res/xml/syncadapter.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.
+-->
+
+<sync-adapter
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:contentAuthority="com.android.cts.stub.provider"
+    android:accountType="com.stub"
+    android:userVisible="false"
+    android:supportsUploading="false"
+    android:allowParallelSyncs="false"
+    android:isAlwaysSyncable="true">
+</sync-adapter>
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java
new file mode 100644
index 0000000..17be8b6
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/CtsSyncAccountAccessSameCertTestCases.java
@@ -0,0 +1,88 @@
+/*
+ * 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.content;
+
+import static junit.framework.Assert.assertTrue;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncRequest;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests whether a sync adapter can access accounts.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CtsSyncAccountAccessSameCertTestCases {
+    private static final long SYNC_TIMEOUT_MILLIS = 10000; // 20 sec
+
+    @Test
+    public void testAccountAccess_sameCertAsAuthenticatorCanSeeAccount() throws Exception {
+        Intent intent = new Intent(getContext(), StubActivity.class);
+        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+
+        AccountManager accountManager = getContext().getSystemService(AccountManager.class);
+        Bundle result = accountManager.addAccount("com.stub", null, null, null, activity,
+                null, null).getResult();
+
+        Account addedAccount = new Account(
+                result.getString(AccountManager.KEY_ACCOUNT_NAME),
+                        result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+
+        try {
+            CountDownLatch latch = new CountDownLatch(1);
+
+            SyncAdapter.setOnPerformSyncDelegate((Account account, Bundle extras,
+                    String authority, ContentProviderClient provider, SyncResult syncResult)
+                    -> latch.countDown());
+
+            Bundle extras = new Bundle();
+            extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
+            extras.putBoolean(ContentResolver.SYNC_EXTRAS_PRIORITY, true);
+            extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+            SyncRequest request = new SyncRequest.Builder()
+                    .setSyncAdapter(null, "com.android.cts.stub.provider")
+                    .syncOnce()
+                    .setExtras(extras)
+                    .setExpedited(true)
+                    .setManual(true)
+                    .build();
+            ContentResolver.requestSync(request);
+
+            assertTrue(latch.await(SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+        } finally {
+            accountManager.removeAccount(addedAccount, activity, null, null);
+        }
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/StubActivity.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/StubActivity.java
new file mode 100644
index 0000000..caefd37
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/StubActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.content;
+
+import android.app.Activity;
+
+public class StubActivity extends Activity {
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncAdapter.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncAdapter.java
new file mode 100644
index 0000000..e93a070
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.content;
+
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+    private static final Object sLock = new Object();
+
+    private static OnPerformSyncDelegate sOnPerformSyncDelegate;
+
+    public interface OnPerformSyncDelegate {
+        void onPerformSync(Account account, Bundle extras, String authority,
+                ContentProviderClient provider, SyncResult syncResult);
+    }
+
+    public static void setOnPerformSyncDelegate(OnPerformSyncDelegate delegate) {
+        synchronized (sLock) {
+            sOnPerformSyncDelegate = delegate;
+        }
+    }
+
+    public SyncAdapter(Context context, boolean autoInitialize) {
+        super(context, autoInitialize);
+    }
+
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority,
+            ContentProviderClient provider, SyncResult syncResult) {
+        OnPerformSyncDelegate delegate;
+        synchronized (sLock) {
+            delegate = sOnPerformSyncDelegate;
+        }
+        if (delegate != null) {
+            delegate.onPerformSync(account, extras, authority, provider, syncResult);
+        }
+    }
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncService.java b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncService.java
new file mode 100644
index 0000000..e8da82c
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncAccountAccessSameCertTests/src/com/android/cts/content/SyncService.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 com.android.cts.content;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SyncService extends Service {
+    private SyncAdapter mInstance;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mInstance = new SyncAdapter(this, false);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mInstance.getSyncAdapterBinder();
+    }
+}
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk b/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk
new file mode 100644
index 0000000..4c817d9
--- /dev/null
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/Android.mk
@@ -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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSyncAccountAccessStubs
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/AndroidManifest.xml b/hostsidetests/content/test-apps/SyncAccountAccessStubs/AndroidManifest.xml
new file mode 100644
index 0000000..76c4fb4
--- /dev/null
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.stub">
+
+    <application>
+        <service
+                android:name=".StubAuthenticator">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator"/>
+            </intent-filter>
+            <meta-data
+                android:name="android.accounts.AccountAuthenticator"
+                android:resource="@xml/authenticator" />
+        </service>
+
+        <provider
+            android:name=".StubProvider"
+            android:authorities="com.android.cts.stub.provider"
+            android:exported="true"
+            android:syncable="true">
+        </provider>
+
+    </application>
+
+</manifest>
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/res/xml/authenticator.xml b/hostsidetests/content/test-apps/SyncAccountAccessStubs/res/xml/authenticator.xml
new file mode 100644
index 0000000..77ecd28
--- /dev/null
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/res/xml/authenticator.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<account-authenticator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="com.stub"/>
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubAuthenticator.java b/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubAuthenticator.java
new file mode 100644
index 0000000..eec9d21
--- /dev/null
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubAuthenticator.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.stub;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+public class StubAuthenticator extends Service {
+    public static final String TOKEN_TYPE_REMOVE_ACCOUNTS = "TOKEN_TYPE_REMOVE_ACCOUNTS";
+
+    private Authenticator mAuthenticator;
+
+    @Override
+    public void onCreate() {
+        mAuthenticator = new Authenticator(this);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mAuthenticator.getIBinder();
+    }
+
+    public class Authenticator extends AbstractAccountAuthenticator {
+        public Authenticator(Context context) {
+            super(context);
+            removeAccounts();
+        }
+
+        @Override
+        public Bundle editProperties(AccountAuthenticatorResponse response,
+                String accountType) {
+            return null;
+        }
+
+        @Override
+        public Bundle addAccount(AccountAuthenticatorResponse response,
+                String accountType, String tokenType, String[] strings,
+                Bundle bundle) throws NetworkErrorException {
+            AccountManager accountManager = getSystemService(AccountManager.class);
+            accountManager.addAccountExplicitly(new Account("foo", accountType), "bar", null);
+
+            Bundle result = new Bundle();
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, "foo");
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
+            response.onResult(result);
+
+            return null;
+        }
+
+        @Override
+        public Bundle confirmCredentials(AccountAuthenticatorResponse response,
+                Account account, Bundle bundle) throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle getAuthToken(AccountAuthenticatorResponse response,
+                Account account, String type, Bundle bundle) throws NetworkErrorException {
+            if (TOKEN_TYPE_REMOVE_ACCOUNTS.equals(type)) {
+                removeAccounts();
+            }
+            return null;
+        }
+
+        @Override
+        public String getAuthTokenLabel(String tokenName) {
+            return null;
+        }
+
+        @Override
+        public Bundle updateCredentials(AccountAuthenticatorResponse response,
+                Account account, String tokenType, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle hasFeatures(AccountAuthenticatorResponse response,
+                Account account, String[] options) throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
+                Account account) throws NetworkErrorException {
+            Bundle result = new Bundle();
+            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+            return result;
+        }
+
+        private void removeAccounts() {
+            AccountManager accountManager = getSystemService(AccountManager.class);
+            for (Account account : accountManager.getAccounts()) {
+                accountManager.removeAccountExplicitly(account);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubProvider.java b/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubProvider.java
new file mode 100644
index 0000000..8a21e0d
--- /dev/null
+++ b/hostsidetests/content/test-apps/SyncAccountAccessStubs/src/com/android/cts/stub/StubProvider.java
@@ -0,0 +1,60 @@
+/*
+ * 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.stub;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class StubProvider extends ContentProvider {
+    @Override
+    public boolean onCreate() {
+        return false;
+    }
+
+    @Override
+    public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable String selection, @Nullable String[] selectionArgs,
+            @Nullable String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(@NonNull Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(@NonNull Uri uri, @Nullable String selection,
+            @Nullable String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(@NonNull Uri uri, @Nullable ContentValues values,
+            @Nullable String selection, @Nullable String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
index 2c1f697..67acb25 100644
--- a/hostsidetests/cpptools/Android.mk
+++ b/hostsidetests/cpptools/Android.mk
@@ -23,7 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsCppToolsTestCases
 
-LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.tests.cpptools
 
diff --git a/hostsidetests/cpptools/AndroidTest.xml b/hostsidetests/cpptools/AndroidTest.xml
index 582c772..da96259 100644
--- a/hostsidetests/cpptools/AndroidTest.xml
+++ b/hostsidetests/cpptools/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsCppToolsTestCases.jar" />
+        <option name="runtime-hint" value="7m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index 2e585d7..1828e2c 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.adminhostside
 
diff --git a/hostsidetests/devicepolicy/AndroidTest.xml b/hostsidetests/devicepolicy/AndroidTest.xml
index 48b3b5b..bb0a13e 100644
--- a/hostsidetests/devicepolicy/AndroidTest.xml
+++ b/hostsidetests/devicepolicy/AndroidTest.xml
@@ -14,6 +14,18 @@
      limitations under the License.
 -->
 <configuration description="Config for the CTS Device Policy host tests">
+
+    <!-- Push the list of public APIs to device -->
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/device-policy-test" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/device-policy-test" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <!-- The source file current.api is prepared by //cts/tests/signature/api/Android.mk -->
+        <!-- The target path should be consistent with CurrentApiHelper#CURRENT_API_FILE -->
+        <option name="push" value="current.api->/data/local/tmp/device-policy-test/current.api" />
+    </target_preparer>
+
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsDevicePolicyManagerTestCases.jar" />
         <option name="runtime-hint" value="31m41s" />
diff --git a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
index b57a91a..b46f013 100644
--- a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
+++ b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
@@ -145,6 +145,14 @@
             case GAL_PHONE_LOOKUP:
             case GAL_CALLABLES_FILTER:
             case GAL_EMAIL_LOOKUP: {
+                // This parameter must always exist, and set to the device side app package name.
+                final String callerPackage = uri.getQueryParameter(
+                        Directory.CALLER_PACKAGE_PARAM_KEY);
+                if (!"com.android.cts.managedprofile".equals(callerPackage)) {
+                    throw new RuntimeException("Expected caller package name not set: uri="
+                            + uri);
+                }
+
                 // TODO: Add all CTS tests for these APIs
                 final MatrixCursor cursor = new MatrixCursor(projection);
                 final Object[] row = new Object[projection.length];
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
new file mode 100644
index 0000000..c24858d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
@@ -0,0 +1,71 @@
+# 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.
+
+# IMPORTANT: We build two apps from the same source but with different package name.
+# This allow us to have different device owner and profile owner, some APIs may behave differently
+# in this situation.
+
+# === App 1 ===
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
+
+# === App 2 ===
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile2
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.cts.comp2 \
+                    --rename-instrumentation-target-package com.android.cts.comp2
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
new file mode 100644
index 0000000..b049306
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.comp" >
+    <!-- package="com.android.cts.comp2"
+         We have com.android.cts.comp2 that have the exact same source but with different package
+         name, see Android.mk for details. -->
+    <application
+        android:testOnly="true">
+
+        <uses-library android:name="android.test.runner" />
+        <receiver
+                android:name="com.android.cts.comp.AdminReceiver"
+                android:exported="true"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data
+                    android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin"/>
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+                <action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
+            </intent-filter>
+        </receiver>
+        <activity android:name=".provisioning.StartProvisioningActivity"></activity>
+
+        <service android:name=".CrossUserService"
+                android:exported="false">
+        </service>
+
+        <service android:name=".ExportedCrossUserService"
+                android:exported="true">
+        </service>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.comp"
+            android:label="Corp owned managed profile CTS tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
new file mode 100644
index 0000000..ff086d6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
@@ -0,0 +1,4 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
new file mode 100644
index 0000000..62665f9
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * 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.comp;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class AdminReceiver extends DeviceAdminReceiver {
+    private static final String TAG = "AdminReceiver";
+    // These two apps are built with this source.
+    public static final String COMP_DPC_PACKAGE_NAME = "com.android.cts.comp";
+    public static final String COMP_DPC_2_PACKAGE_NAME = "com.android.cts.comp2";
+
+    public static ComponentName getComponentName(Context context) {
+        return new ComponentName(context, AdminReceiver.class);
+    }
+
+    @Override
+    public void onProfileProvisioningComplete(Context context, Intent intent) {
+        super.onProfileProvisioningComplete(context, intent);
+        Log.i(TAG, "onProfileProvisioningComplete");
+        // Enabled profile
+        getManager(context).setProfileName(getComponentName(context), "Corp owned Managed Profile");
+        getManager(context).setProfileEnabled(getComponentName(context));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java
new file mode 100644
index 0000000..8e1f0e6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.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.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for device-owner based tests.
+ */
+public abstract class BaseDeviceOwnerCompTest extends AndroidTestCase {
+
+    protected DevicePolicyManager mDevicePolicyManager;
+    protected List<UserHandle> mOtherProfiles;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertDeviceOwner(mDevicePolicyManager);
+
+        // A managed profile must have been created.
+        mOtherProfiles = mContext.getSystemService(UserManager.class)
+                .getUserProfiles();
+        mOtherProfiles.remove(Process.myUserHandle());
+        assertTrue(mOtherProfiles.size() > 0);
+    }
+
+    private void assertDeviceOwner(DevicePolicyManager dpm) {
+        assertNotNull(dpm);
+        assertTrue(dpm.isAdminActive(AdminReceiver.getComponentName(getContext())));
+        assertTrue(dpm.isDeviceOwnerApp(getContext().getPackageName()));
+        assertFalse(dpm.isManagedProfile(AdminReceiver.getComponentName(getContext())));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
new file mode 100644
index 0000000..6a3eb05
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for profile-owner based tests.
+ * <p>
+ * This class handles making sure that the test is the profile owner and that it has an active admin
+ * registered, so that all tests may assume these are done.
+ */
+public class BaseManagedProfileCompTest extends AndroidTestCase {
+
+    protected DevicePolicyManager mDevicePolicyManager;
+    protected List<UserHandle> mOtherProfiles;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertManagedProfile();
+
+        mOtherProfiles = mContext.getSystemService(UserManager.class)
+                .getUserProfiles();
+        mOtherProfiles.remove(Process.myUserHandle());
+        assertTrue(mOtherProfiles.size() > 0);  // The primary profile should be there.
+    }
+
+    private void assertManagedProfile() {
+        assertNotNull(mDevicePolicyManager);
+        assertTrue(mDevicePolicyManager.isAdminActive(
+                AdminReceiver.getComponentName(getContext())));
+        assertTrue(mDevicePolicyManager.isProfileOwnerApp(getContext().getPackageName()));
+        assertTrue(mDevicePolicyManager.isManagedProfile(
+                AdminReceiver.getComponentName(getContext())));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java
new file mode 100644
index 0000000..3b95b94
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.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 com.android.cts.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.UserHandle;
+
+/**
+ * Handle the cross user call from the device admin in other side.
+ */
+public class CrossUserService extends Service {
+
+    private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
+        public String echo(String msg) {
+            return msg;
+        }
+
+        public UserHandle getUserHandle() {
+            return Process.myUserHandle();
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..935a657
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a device owner tries to bind a service from profile owner.
+ */
+public class DeviceOwnerBindDeviceAdminServiceTest extends BaseDeviceOwnerCompTest {
+
+    public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // COMP mode - DO should be allowed to bind to the managed profile user.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(1, allowedTargetUsers.size());
+        UserHandle managedProfileUserHandle = allowedTargetUsers.get(0);
+        assertTrue(mOtherProfiles.contains(managedProfileUserHandle));
+
+        new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+                mContext, managedProfileUserHandle)
+                .execute();
+    }
+
+    public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(0, allowedTargetUsers.size());
+
+        for (UserHandle userHandle : mOtherProfiles) {
+            new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+                    mContext, userHandle, AdminReceiver.COMP_DPC_2_PACKAGE_NAME)
+                    .execute();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
new file mode 100644
index 0000000..e7a9e73
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Dummy service that is exported.
+ */
+public class ExportedCrossUserService extends Service {
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
new file mode 100644
index 0000000..bc8d3d3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.comp;
+
+interface ICrossUserService {
+    String echo(String msg);
+    android.os.UserHandle getUserHandle();
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..e301a4f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a profile owner from the managed profile tries to bind a service
+ * from the device owner.
+ */
+public class ManagedProfileBindDeviceAdminServiceTest extends BaseManagedProfileCompTest {
+
+    public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // COMP mode - Managed Profile PO should be allowed to bind to the DO.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(1, allowedTargetUsers.size());
+        UserHandle primaryProfileUserHandle = allowedTargetUsers.get(0);
+        assertTrue(mOtherProfiles.contains(primaryProfileUserHandle));
+
+        new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+                mContext, primaryProfileUserHandle).execute();
+    }
+
+    public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_2_PACKAGE_NAME, mContext.getPackageName());
+
+        // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(0, allowedTargetUsers.size());
+
+        for (UserHandle userHandle : mOtherProfiles) {
+            new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+                    mContext, userHandle, AdminReceiver.COMP_DPC_PACKAGE_NAME)
+                    .execute();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
new file mode 100644
index 0000000..fe739c1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
@@ -0,0 +1,107 @@
+/*
+ * 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.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case that device owner and profile owner are different packages.
+ */
+public class BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite {
+
+    private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {}
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {}
+    };
+
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+    private final String mDpcPackageInOtherSide;
+    private final UserHandle mTargetUserHandle;
+
+    /**
+     * @param context
+     * @param targetUserHandle      Which user are we talking to.
+     * @param dpcPackageInOtherSide The dpc package installed in other side, it must not be this
+     *                              package.
+     */
+    public BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+            Context context, UserHandle targetUserHandle, String dpcPackageInOtherSide) {
+        MoreAsserts.assertNotEqual(context.getPackageName(), dpcPackageInOtherSide);
+        mContext = context;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+        mDpcPackageInOtherSide = dpcPackageInOtherSide;
+        mTargetUserHandle = targetUserHandle;
+    }
+
+    public void execute() throws Exception {
+        checkCannotBind_deviceOwnerProfileOwnerDifferentPackage();
+        checkCannotBind_talkToNonManagingPackage();
+    }
+
+    /**
+     * Device owner and profile owner try to talk to each other. It should fail as they are
+     * different packages.
+     */
+    private void checkCannotBind_deviceOwnerProfileOwnerDifferentPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent();
+            serviceIntent.setClassName(mDpcPackageInOtherSide, CrossUserService.class.getName());
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex(
+                    "Not allowed to bind to target user id", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to our own instance in other end. It should fail as it is not the same app that
+     * is managing that profile.
+     */
+    private void checkCannotBind_talkToNonManagingPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex(
+                    "Not allowed to bind to target user id", ex.getMessage());
+        }
+    }
+
+    private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+            UserHandle userHandle) {
+        return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+                serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
new file mode 100644
index 0000000..c03c42f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
@@ -0,0 +1,207 @@
+/*
+ * 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.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+import com.android.cts.comp.ExportedCrossUserService;
+import com.android.cts.comp.ICrossUserService;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case where we have the same package for both device owner and profile owner.
+ */
+public class BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite {
+    private static final String TAG = "BindServiceTest";
+
+    private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {}
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {}
+    };
+
+    private final Context mContext;
+    private static final String NON_MANAGING_PACKAGE = AdminReceiver.COMP_DPC_2_PACKAGE_NAME;
+    private final UserHandle mTargetUserHandle;
+    private final DevicePolicyManager mDpm;
+
+    /**
+     * @param context
+     * @param targetUserHandle Which user we are talking to.
+     */
+    public BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+            Context context, UserHandle targetUserHandle) {
+        mContext = context;
+        mTargetUserHandle = targetUserHandle;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    public void execute() throws Exception {
+        checkCannotBind_implicitIntent();
+        checkCannotBind_notResolvableIntent();
+        checkCannotBind_exportedCrossUserService();
+        checkCannotBind_nonManagingPackage();
+        checkCannotBind_sameUser();
+        checkCrossProfileCall_echo();
+        checkCrossProfileCall_getUserHandle();
+    }
+
+    /**
+     * If the intent is implicit, expected to throw {@link IllegalArgumentException}.
+     */
+    private void checkCannotBind_implicitIntent() throws Exception {
+        try {
+            final Intent implicitIntent = new Intent(Intent.ACTION_VIEW);
+            bind(implicitIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("IllegalArgumentException should be thrown");
+        } catch (IllegalArgumentException ex) {
+            MoreAsserts.assertContainsRegex("Service intent must be explicit", ex.getMessage());
+        }
+    }
+
+    /**
+     * If the intent is not resolvable, it should return {@code {@code null}}.
+     */
+    private void checkCannotBind_notResolvableIntent() throws Exception {
+        final Intent notResolvableIntent = new Intent();
+        notResolvableIntent.setClassName(mContext, "NotExistService");
+        assertFalse(bind(notResolvableIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle));
+    }
+
+    /**
+     * Make sure we cannot bind exported service.
+     */
+    private void checkCannotBind_exportedCrossUserService() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, ExportedCrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex("must be unexported", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to a DPC package that is neither device owner nor profile owner.
+     */
+    private void checkCannotBind_nonManagingPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent();
+            serviceIntent.setClassName(NON_MANAGING_PACKAGE, CrossUserService.class.getName());
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex("Only allow to bind service", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to the same DPC in same user, that is talking to itself.
+     */
+    private void checkCannotBind_sameUser() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, Process.myUserHandle());
+            fail("IllegalArgumentException should be thrown");
+        } catch (IllegalArgumentException ex) {
+            MoreAsserts.assertContainsRegex("target user id must be different", ex.getMessage());
+        }
+    }
+
+    /**
+     * Send a String to other side and expect the exact same string is echoed back.
+     */
+    private void checkCrossProfileCall_echo() throws Exception {
+        final String ANSWER = "42";
+        assertCrossProfileCall(ANSWER, service -> service.echo(ANSWER), mTargetUserHandle);
+    }
+
+    /**
+     * Make sure we are talking to the target user.
+     */
+    private void checkCrossProfileCall_getUserHandle() throws Exception {
+        assertCrossProfileCall(
+                mTargetUserHandle, service -> service.getUserHandle(), mTargetUserHandle);
+    }
+
+    /**
+     * Convenient method for you to execute a cross user call and assert the return value of it.
+     * @param expected The expected result of the cross user call.
+     * @param callable It is called when the service is bound, use this to make the service call.
+     * @param targetUserHandle Which user are we talking to.
+     * @param <T> The return type of the service call.
+     */
+    private <T> void assertCrossProfileCall(
+            T expected, CrossUserCallable<T> callable, UserHandle targetUserHandle)
+            throws Exception {
+        final LinkedBlockingQueue<ICrossUserService> queue
+                = new LinkedBlockingQueue<ICrossUserService>();
+        final ServiceConnection serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                Log.d(TAG, "onServiceConnected is called");
+                queue.add(ICrossUserService.Stub.asInterface(service));
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                Log.d(TAG, "onServiceDisconnected is called");
+            }
+        };
+        final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+        assertTrue(bind(serviceIntent, serviceConnection, targetUserHandle));
+        ICrossUserService service = queue.poll(5, TimeUnit.SECONDS);
+        assertNotNull("binding to the target service timed out", service);
+        try {
+            assertEquals(expected, callable.call(service));
+        } finally {
+            mContext.unbindService(serviceConnection);
+        }
+    }
+
+    private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+            UserHandle userHandle) {
+        return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+                serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+    }
+
+    interface CrossUserCallable<T> {
+        T call(ICrossUserService service) throws RemoteException;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/ManagedProfileProvisioningTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/ManagedProfileProvisioningTest.java
new file mode 100644
index 0000000..7236746
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/ManagedProfileProvisioningTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.comp.provisioning;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+
+public class ManagedProfileProvisioningTest extends AndroidTestCase {
+    private static final String TAG = "ManagedProfileProvisioningTest";
+
+    public void testProvisioningCorpOwnedManagedProfile() throws Exception {
+        SilentProvisioningTestManager provisioningManager =
+                SilentProvisioningTestManager.getInstance();
+        provisioningManager.reset();
+        provisioningManager.startProvisioning(getContext());
+        Log.i(TAG, "Start provisioning");
+
+        assertTrue(provisioningManager.waitForProvisioningResult(getContext()));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/SilentProvisioningTestManager.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/SilentProvisioningTestManager.java
new file mode 100644
index 0000000..c8b68bb
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/SilentProvisioningTestManager.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 com.android.cts.comp.provisioning;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+class SilentProvisioningTestManager {
+
+    private static final long TIMEOUT_SECONDS = 60;
+    private static final String TAG = "SilentProvisioningTestManager";
+
+    private static final SilentProvisioningTestManager sInstance
+            = new SilentProvisioningTestManager();
+
+    private final LinkedBlockingQueue<Boolean> mProvisioningResults = new LinkedBlockingQueue(1);
+
+    public static SilentProvisioningTestManager getInstance() {
+        return sInstance;
+    }
+
+    private SilentProvisioningTestManager() {}
+
+    public void reset() {
+        mProvisioningResults.clear();
+    }
+
+    public void startProvisioning(Context context) {
+        context.startActivity(new Intent(context, StartProvisioningActivity.class));
+    }
+
+    public void notifyProvisioningResult(boolean result) throws InterruptedException {
+        mProvisioningResults.put(result);
+    }
+
+    public boolean waitForProvisioningResult(Context context) throws InterruptedException {
+        Boolean result = mProvisioningResults.poll(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        if (result == null) {
+            Log.i(TAG, "ManagedProvisioning doesn't return result within "
+                    + TIMEOUT_SECONDS + " seconds ");
+            return false;
+        }
+
+        if (!result) {
+            Log.i(TAG, "Failed to provision");
+            return false;
+        }
+
+        // Wait for profile enabled
+        ManagedProfileAddedReceiver receiver = new ManagedProfileAddedReceiver(context);
+        receiver.register();
+        return receiver.await();
+    }
+
+    private static class ManagedProfileAddedReceiver extends BroadcastReceiver {
+
+        private static final CountDownLatch mLatch = new CountDownLatch(1);
+
+        private final Context mContext;
+
+        private ManagedProfileAddedReceiver(Context context) {
+            mContext = context;
+        }
+
+        private void register() {
+            mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_MANAGED_PROFILE_ADDED));
+        }
+
+        private boolean await() throws InterruptedException {
+            return mLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mLatch.countDown();
+        }
+    }
+}
+
+
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/StartProvisioningActivity.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/StartProvisioningActivity.java
new file mode 100644
index 0000000..634f5da
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/provisioning/StartProvisioningActivity.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.comp.provisioning;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+import com.android.cts.comp.AdminReceiver;
+
+public class StartProvisioningActivity extends Activity {
+    private static final int REQUEST_CODE = 1;
+    private static final String TAG = "StartProvisionActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Reduce flakiness of the test
+        // Show activity on top of keyguard
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+        // Turn on screen to prevent activity being paused by system
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        // Only provision it if the activity is not re-created
+        if (savedInstanceState == null) {
+            Intent provisioningIntent = new Intent(ACTION_PROVISION_MANAGED_PROFILE)
+                    .putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+                            AdminReceiver.getComponentName(this))
+                    .putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION, true)
+                    // this flag for Corp owned only
+                    .putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_USER_CONSENT, true);
+
+            startActivityForResult(provisioningIntent, REQUEST_CODE);
+            Log.i(TAG, "Start provisioning intent");
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE) {
+            try {
+                SilentProvisioningTestManager.getInstance().notifyProvisioningResult(
+                        resultCode == RESULT_OK);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "notifyProvisioningResult", e);
+            }
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
index 7b29bd4..e33baab 100644
--- a/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java b/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java
index 11d8c78..75f0067 100644
--- a/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java
@@ -22,7 +22,7 @@
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
-import android.cts.util.BitmapUtils;
+import com.android.compatibility.common.util.BitmapUtils;
 import com.android.cts.customizationapp.R;
 
 /**
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
index b1c35aa..5a6794a 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
@@ -24,9 +24,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util 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..5e083f7 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
@@ -24,9 +24,9 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 compatibility-device-util 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 632899d..42d684e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -25,13 +25,15 @@
     <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" />
         <receiver
             android:name="com.android.cts.deviceandprofileowner.BaseDeviceAdminTest$BasicAdminReceiver"
-            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            android:permission="android.permission.BIND_DEVICE_ADMIN"
+            android:directBootAware="true">
             <meta-data android:name="android.app.device_admin"
                        android:resource="@xml/device_admin" />
             <intent-filter>
@@ -54,7 +56,9 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".SetPolicyActivity" >
+        <activity
+            android:name=".SetPolicyActivity"
+            android:launchMode="singleTop">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT"/>
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/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
new file mode 100644
index 0000000..4edf846
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.deviceandprofileowner;
+
+import android.content.ComponentName;
+import android.net.http.X509TrustManagerExtensions;
+
+import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import static com.android.compatibility.common.util.FakeKeys.FAKE_DSA_1;
+import static com.android.compatibility.common.util.FakeKeys.FAKE_RSA_1;
+
+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(mAdmin);
+        assertNotNull(caCerts);
+    }
+
+    /**
+     * Test: a valid cert should be installable and also removable.
+     */
+    public void testCanInstallAndUninstallACaCert()
+            throws CertificateException, GeneralSecurityException {
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
+        assertInstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+    }
+
+    /**
+     * Test: removing one certificate must not remove any others.
+     */
+    public void testUninstallationIsSelective()
+            throws CertificateException, GeneralSecurityException {
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_DSA_1.caCertificate));
+
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_DSA_1.caCertificate);
+        assertInstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+
+        mDevicePolicyManager.uninstallCaCert(mAdmin, FAKE_RSA_1.caCertificate);
+    }
+
+    /**
+     * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
+     * supplementary installed certificate.
+     */
+    public void testCanUninstallAllUserCaCerts()
+            throws CertificateException, GeneralSecurityException {
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_RSA_1.caCertificate));
+        assertTrue(mDevicePolicyManager.installCaCert(mAdmin, FAKE_DSA_1.caCertificate));
+
+        mDevicePolicyManager.uninstallAllUserCaCerts(mAdmin);
+        assertUninstalled(FAKE_RSA_1.caCertificate);
+        assertUninstalled(FAKE_DSA_1.caCertificate);
+    }
+
+    private void assertInstalled(byte[] caBytes)
+            throws CertificateException, GeneralSecurityException {
+        Certificate caCert = readCertificate(caBytes);
+        assertTrue(isCaCertInstalledAndTrusted(caCert));
+    }
+
+    private void assertUninstalled(byte[] caBytes)
+            throws CertificateException, GeneralSecurityException {
+        Certificate caCert = readCertificate(caBytes);
+        assertFalse(isCaCertInstalledAndTrusted(caCert));
+    }
+
+    private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) {
+        for (TrustManager trustManager : tmf.getTrustManagers()) {
+             if (trustManager instanceof X509TrustManager) {
+                 return (X509TrustManager) trustManager;
+             }
+        }
+        throw new RuntimeException("Unable to find X509TrustManager");
+    }
+
+    /**
+     * Whether a given cert, or one a lot like it, has been installed system-wide and is available
+     * to all apps.
+     *
+     * <p>A CA certificate is "installed" if it matches all of the following conditions:
+     * <ul>
+     *   <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
+     *   <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
+     *       necessarily exactly the same) in its response.</li>
+     *   <li>Any new instances of {@link TrustManager} should report the certificate among their
+     *       accepted issuer list -- older instances may keep the set of issuers they were created
+     *       with until explicitly refreshed.</li>
+     *
+     * @return {@code true} if installed by all metrics, {@code false} if not installed by any
+     *         metric. In any other case an {@link AssertionError} will be thrown.
+     */
+    private boolean isCaCertInstalledAndTrusted(Certificate caCert)
+            throws GeneralSecurityException, CertificateException {
+        boolean installed = mDevicePolicyManager.hasCaCertInstalled(mAdmin, caCert.getEncoded());
+
+        boolean listed = false;
+        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(mAdmin)) {
+            if (caCert.equals(readCertificate(certBuffer))) {
+                listed = true;
+            }
+        }
+
+        // Verify that the user added CA is reflected in the default X509TrustManager.
+        final TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        // Use platform provided CA store.
+        tmf.init((KeyStore) null);
+        X509TrustManager tm = getFirstX509TrustManager(tmf);
+        boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
+        X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm);
+        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 fail now, loudly.
+        assertEquals(installed, listed);
+        assertEquals(installed, trusted);
+        assertEquals(installed, userAddedCertificate);
+        return installed;
+    }
+
+    /**
+     * Convert an encoded certificate back into a {@link Certificate}.
+     *
+     * Instantiates a fresh CertificateFactory every time for repeatability.
+     */
+    private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
+        final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+        return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java
index 021aace..dc85600 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java
@@ -25,7 +25,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.cts.util.BitmapUtils;
+import com.android.compatibility.common.util.BitmapUtils;
 import com.android.cts.deviceandprofileowner.R;
 
 import java.io.Closeable;
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FbeHelper.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FbeHelper.java
new file mode 100644
index 0000000..4ba4be5
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FbeHelper.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 com.android.cts.deviceandprofileowner;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.uiautomator.UiDevice;
+import android.view.KeyEvent;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper class to lock and unlock file-based encryption (FBE) in CTS tests.
+ */
+public class FbeHelper extends BaseDeviceAdminTest {
+
+    private static final String NUMERIC_PASSWORD = "12345";
+
+    private UiDevice mUiDevice;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        assertTrue("Only numerical password is allowed", NUMERIC_PASSWORD.matches("\\d+"));
+
+        mUiDevice = UiDevice.getInstance(getInstrumentation());
+        assertNotNull(mUiDevice);
+    }
+
+    /**
+     * Set password to activate FBE.
+     * <p>
+     * <b>Note:</b> FBE is only locked after device reboot.
+     */
+    public void testSetPassword() {
+        assertTrue("Failed to set password " + NUMERIC_PASSWORD,
+                mDevicePolicyManager.resetPassword(NUMERIC_PASSWORD, 0));
+    }
+
+    /**
+     * Unlock FBE by entering the password in the Keyguard UI. This method blocks until an
+     * {@code ACTION_USER_UNLOCKED} intent is received within 1 minute. Otherwise the method fails.
+     */
+    public void testUnlockFbe() throws Exception {
+        // Register receiver for FBE unlocking broadcast intent
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        };
+        mContext.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+
+        // Unlock FBE
+        enterPassword(NUMERIC_PASSWORD);
+
+        // Wait for FBE to fully unlock
+        assertTrue("Failed to dismiss keyguard", latch.await(1, TimeUnit.MINUTES));
+    }
+
+    private void enterPassword(String password) throws Exception {
+        mUiDevice.wakeUp();
+        mUiDevice.waitForIdle();
+        mUiDevice.pressMenu();
+        mUiDevice.waitForIdle();
+        pressNumericKeys(password);
+        mUiDevice.waitForIdle();
+        mUiDevice.pressEnter();
+        mUiDevice.waitForIdle();
+    }
+
+    private void pressNumericKeys(String numericKeys) {
+        for (char key : numericKeys.toCharArray()) {
+            if (key >= '0' && key <= '9') {
+                mUiDevice.pressKeyCode(KeyEvent.KEYCODE_0 + key - '0');
+            } else {
+                throw new IllegalArgumentException(key + " is not a numeric key.");
+            }
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
index 635ff6d..17d934e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
@@ -15,17 +15,73 @@
  */
 package com.android.cts.deviceandprofileowner;
 
-public class ResetPasswordTest extends BaseDeviceAdminTest {
-    public void testResetPassword() {
-        try {
-            // DO/PO can set a password.
-            mDevicePolicyManager.resetPassword("12345abcdef!!##1", 0);
+import android.util.Log;
 
-            // DO/PO can change the password, even if one is set already.
-            mDevicePolicyManager.resetPassword("12345abcdef!!##2", 0);
+import java.lang.IllegalStateException;
+
+/**
+ * Test cases for {@link android.app.admin.DevicePolicyManager#resetPassword(String, int)}.
+ *
+ * <p>These tests verify that the device password:
+ * <ul>
+ *     <li>can be created, changed and cleared when FBE is not locked, and
+ *     <li>cannot be changed or cleared when FBE is locked.
+ * </ul>
+ */
+public class ResetPasswordTest extends BaseDeviceAdminTest {
+
+    private static final String TAG = "ResetPasswordTest";
+
+    private static final String PASSWORD_1 = "12345";
+    private static final String PASSWORD_2 = "12345abcdef!!##1";
+
+    /**
+     * Test: a Device Owner or (un-managed) Profile Owner can create, change and remove a password.
+     */
+    public void testResetPassword() {
+        testResetPasswordEnabled(true, true);
+    }
+
+    /**
+     * Test: a managed Profile Owner can create and change, but not remove, a password.
+     */
+    public void testResetPasswordManagedProfile() {
+        testResetPasswordEnabled(true, false);
+    }
+
+    /**
+     * Test: a Device Owner or Profile Owner (managed or un-managed) cannot change or remove the
+     * password when FBE is locked.
+     */
+    public void testResetPasswordDisabled() throws Exception {
+        assertFalse("Failed to lock FBE", mUserManager.isUserUnlocked());
+        testResetPasswordEnabled(false, false);
+    }
+
+    private void testResetPasswordEnabled(boolean canChange, boolean canRemove) {
+        try {
+            assertResetPasswordEnabled(canChange, PASSWORD_1);
+            assertResetPasswordEnabled(canChange, PASSWORD_2);
         } finally {
-            // DO/PO can clear the password.
-            mDevicePolicyManager.resetPassword("", 0);
+            assertResetPasswordEnabled(canRemove, "");
+        }
+    }
+
+    private void assertResetPasswordEnabled(boolean enabled, String password) {
+        boolean passwordChanged;
+        try {
+            passwordChanged = mDevicePolicyManager.resetPassword(password, 0);
+        } catch (IllegalStateException | SecurityException e) {
+            passwordChanged = false;
+            if (enabled) {
+                Log.d(TAG, e.getMessage(), e);
+            }
+        }
+
+        if (enabled) {
+            assertTrue("Failed to change password", passwordChanged);
+        } else {
+            assertFalse("Failed to prevent password change", passwordChanged);
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
index a0740fb..25474c5 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/BaseUserRestrictionsTest.java
@@ -35,12 +35,14 @@
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
+            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             UserManager.DISALLOW_DEBUGGING_FEATURES,
             UserManager.DISALLOW_CONFIG_VPN,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             UserManager.ENSURE_VERIFY_APPS,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -140,6 +142,12 @@
         assertOwnerRestriction(restriction, false);
     }
 
+    protected void assertClearDefaultRestrictions() {
+        for (String restriction : getDefaultEnabledRestrictions()) {
+            assertClearUserRestriction(restriction);
+        }
+    }
+
     /**
      * Test that the given restriction *cannot* be set (or clear).
      */
@@ -181,10 +189,30 @@
     /** For {@link #testSetAllRestrictions} */
     protected abstract String[] getDisallowedRestrictions();
 
+    /** For {@link #testDefaultRestrictions()} */
+    protected abstract String[] getDefaultEnabledRestrictions();
+
+    /**
+     * Test restrictions that should be enabled by default
+     */
+    public void testDefaultRestrictions() {
+        for (String restriction : getDefaultEnabledRestrictions()) {
+            assertOwnerRestriction(restriction, true);
+        }
+
+        Set<String> offByDefaultRestrictions = new HashSet<>(Arrays.asList(ALL_USER_RESTRICTIONS));
+        offByDefaultRestrictions.removeAll(
+                new HashSet<>(Arrays.asList(getDefaultEnabledRestrictions())));
+        for (String restriction : offByDefaultRestrictions) {
+            assertOwnerRestriction(restriction, false);
+        }
+    }
+
     /**
      * Set only one restriction, and make sure only that's set, and then clear it.
      */
     public void testSetAllRestrictionsIndividually() {
+        assertClearDefaultRestrictions();
         for (String r : getAllowedRestrictions()) {
             // Set it.
             assertSetClearUserRestriction(r);
@@ -200,6 +228,7 @@
      * Make sure all allowed restrictions can be set, and the others can't.
      */
     public void testSetAllRestrictions() {
+        assertClearDefaultRestrictions();
         for (String r : getAllowedRestrictions()) {
             assertSetClearUserRestriction(r);
         }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/CheckNoOwnerRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/CheckNoOwnerRestrictionsTest.java
index 14e5f84..d7bfcc0 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/CheckNoOwnerRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/CheckNoOwnerRestrictionsTest.java
@@ -24,7 +24,8 @@
  */
 public class CheckNoOwnerRestrictionsTest extends AndroidTestCase {
     public void testNoOwnerRestrictions() {
-        assertFalse(mContext.getSystemService(UserManager.class).hasUserRestriction(
+        assertFalse("DISALLOW_UNMUTE_MICROPHONE is still set",
+                mContext.getSystemService(UserManager.class).hasUserRestriction(
                 UserManager.DISALLOW_UNMUTE_MICROPHONE));
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
index 5fca606..7c2312b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/DeviceOwnerUserRestrictionsTest.java
@@ -29,12 +29,14 @@
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_CREDENTIALS,
             UserManager.DISALLOW_REMOVE_USER,
+            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             // UserManager.DISALLOW_DEBUGGING_FEATURES, // Need for CTS
             UserManager.DISALLOW_CONFIG_VPN,
             UserManager.DISALLOW_CONFIG_TETHERING,
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             // UserManager.ENSURE_VERIFY_APPS, // Has unrecoverable side effects.
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -59,6 +61,10 @@
             // DO can set all public restrictions.
     };
 
+    public static final String[] DEFAULT_ENABLED = new String[] {
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE
+    };
+
     @Override
     protected String[] getAllowedRestrictions() {
         return ALLOWED;
@@ -68,5 +74,8 @@
     protected String[] getDisallowedRestrictions() {
         return DISALLOWED;
     }
+
+    @Override
+    protected String[] getDefaultEnabledRestrictions() { return DEFAULT_ENABLED; }
 }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/PrimaryProfileOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/PrimaryProfileOwnerUserRestrictionsTest.java
index 57c49cf..340fc9b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/PrimaryProfileOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/PrimaryProfileOwnerUserRestrictionsTest.java
@@ -26,4 +26,9 @@
     protected String[] getDisallowedRestrictions() {
         return DeviceOwnerUserRestrictionsTest.DISALLOWED;
     }
+
+    @Override
+    protected String[] getDefaultEnabledRestrictions() {
+        return new String[0];
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
index 407e90b..dc71968 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/userrestrictions/SecondaryProfileOwnerUserRestrictionsTest.java
@@ -50,6 +50,8 @@
             UserManager.DISALLOW_NETWORK_RESET,
             UserManager.DISALLOW_FACTORY_RESET,
             UserManager.DISALLOW_ADD_USER,
+            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
+            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
             UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
@@ -71,6 +73,9 @@
         return DISALLOWED;
     }
 
+    @Override
+    protected String[] getDefaultEnabledRestrictions() { return new String[0]; }
+
     /**
      * This is called after DO setting all DO restrictions.  Global restrictions should be
      * visible on other users.
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..91b710e 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
@@ -61,11 +61,13 @@
     // IP address reserved for documentation by rfc5737
     public static final String TEST_ADDRESS = "192.0.2.4";
 
+    // HACK (TODO issue 31585407) to wait for the network to actually be usable
+    private static final int NETWORK_SETTLE_GRACE_MS = 200;
+
     private static final int SOCKET_TIMEOUT_MS = 5000;
     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,7 +95,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);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 18d1b8b..8683ed5 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,7 +26,10 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    compatibility-device-util \
+    android-support-v4
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 10711ad..37c46ee 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -27,8 +27,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 
-    <!-- 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/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
new file mode 100644
index 0000000..d86a27a
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import java.lang.reflect.Method;
+
+public class AdminActionBookkeepingTest extends BaseDeviceOwnerTest {
+
+    /**
+     * Test: Retrieving security logs should update the corresponding timestamp.
+     */
+    public void testRetrieveSecurityLogs() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+        long timeBefore = System.currentTimeMillis();
+        mDevicePolicyManager.retrieveSecurityLogs(getWho());
+        long timeAfter = System.currentTimeMillis();
+
+        final long firstTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+        assertTrue(firstTimestamp > previousTimestamp);
+        assertTrue(firstTimestamp >= timeBefore);
+        assertTrue(firstTimestamp <= timeAfter);
+
+        Thread.sleep(2);
+        timeBefore = System.currentTimeMillis();
+        final boolean preBootSecurityLogsRetrieved =
+                mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho()) != null;
+        timeAfter = System.currentTimeMillis();
+
+        final long secondTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+        if (preBootSecurityLogsRetrieved) {
+            // If the device supports pre-boot security logs, verify that retrieving them updates
+            // the timestamp.
+            assertTrue(secondTimestamp > firstTimestamp);
+            assertTrue(secondTimestamp >= timeBefore);
+            assertTrue(secondTimestamp <= timeAfter);
+        } else {
+            // If the device does not support pre-boot security logs, verify that the attempt to
+            // retrieve them does not update the timestamp.
+            assertEquals(firstTimestamp, secondTimestamp);
+        }
+    }
+
+    /**
+     * Test: Requesting a bug report should update the corresponding timestamp.
+     */
+    public void testRequestBugreport() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+
+        final long timeBefore = System.currentTimeMillis();
+        mDevicePolicyManager.requestBugreport(getWho());
+        final long timeAfter = System.currentTimeMillis();
+
+        final long newTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+        assertTrue(newTimestamp > previousTimestamp);
+        assertTrue(newTimestamp >= timeBefore);
+        assertTrue(newTimestamp <= timeAfter);
+    }
+
+    /**
+     * Test: Retrieving network logs should update the corresponding timestamp.
+     */
+    public void testGetLastNetworkLogRetrievalTime() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+        // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+        // un-hiding happens.
+        final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), true);
+
+        long timeBefore = System.currentTimeMillis();
+        final Method retrieveNetworkLogsMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "retrieveNetworkLogs", ComponentName.class, long.class);
+        retrieveNetworkLogsMethod.invoke(mDevicePolicyManager, getWho(), 0 /* batchToken */);
+        long timeAfter = System.currentTimeMillis();
+
+        final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
+        assertTrue(newTimestamp > previousTimestamp);
+        assertTrue(newTimestamp >= timeBefore);
+        assertTrue(newTimestamp <= timeAfter);
+
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+    }
+
+    /**
+     * Test: The Device Owner should be able to set and retrieve the name of the organization
+     * managing the device.
+     */
+    public void testDeviceOwnerOrganizationName() throws Exception {
+        mDevicePolicyManager.setOrganizationName(getWho(), null);
+        assertNull(mDevicePolicyManager.getDeviceOwnerOrganizationName());
+
+        mDevicePolicyManager.setOrganizationName(getWho(), "organization");
+        assertEquals("organization", mDevicePolicyManager.getDeviceOwnerOrganizationName());
+
+        mDevicePolicyManager.setOrganizationName(getWho(), null);
+        assertNull(mDevicePolicyManager.getDeviceOwnerOrganizationName());
+    }
+
+    /**
+     * Test: When a Device Owner is set, isDeviceManaged() should return true.
+     */
+    public void testIsDeviceManaged() throws Exception {
+        assertTrue(mDevicePolicyManager.isDeviceManaged());
+    }
+
+    /**
+     * Helper that allows the host-side test harness to disable network logging after running the
+     * other tests in this file.
+     */
+    public void testDisablingNetworkLogging() throws Exception {
+        // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+        // un-hiding happens.
+        final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
index b49f923..204b9b4 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
@@ -22,6 +22,8 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Process;
+import android.os.UserHandle;
+import android.support.v4.content.LocalBroadcastManager;
 import android.test.AndroidTestCase;
 
 /**
@@ -34,6 +36,10 @@
  */
 public abstract class BaseDeviceOwnerTest extends AndroidTestCase {
 
+    final static String ACTION_USER_ADDED = "com.android.cts.deviceowner.action.USER_ADDED";
+    final static String ACTION_USER_REMOVED = "com.android.cts.deviceowner.action.USER_REMOVED";
+    final static String EXTRA_USER_HANDLE = "com.android.cts.deviceowner.extra.USER_HANDLE";
+
     public static class BasicAdminReceiver extends DeviceAdminReceiver {
         @Override
         public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
@@ -43,6 +49,23 @@
             }
             return uri.getQueryParameter("alias");
         }
+
+        @Override
+        public void onUserAdded(Context context, Intent intent, UserHandle userHandle) {
+            sendUserAddedOrRemovedBroadcast(context, ACTION_USER_ADDED, userHandle);
+        }
+
+        @Override
+        public void onUserRemoved(Context context, Intent intent, UserHandle userHandle) {
+            sendUserAddedOrRemovedBroadcast(context, ACTION_USER_REMOVED, userHandle);
+        }
+
+        private void sendUserAddedOrRemovedBroadcast(Context context, String action,
+                UserHandle userHandle) {
+            Intent intent = new Intent(action);
+            intent.putExtra(EXTRA_USER_HANDLE, userHandle);
+            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+        }
     }
 
     public static final String PACKAGE_NAME = BaseDeviceOwnerTest.class.getPackage().getName();
@@ -62,6 +85,7 @@
         assertNotNull(dpm);
         assertTrue(dpm.isAdminActive(getWho()));
         assertTrue(dpm.isDeviceOwnerApp(PACKAGE_NAME));
+        assertFalse(dpm.isManagedProfile(getWho()));
     }
 
     protected static ComponentName getWho() {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
deleted file mode 100644
index 3e692c3..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
+++ /dev/null
@@ -1,172 +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.deviceowner;
-
-import android.net.http.X509TrustManagerExtensions;
-import android.security.NetworkSecurityPolicy;
-
-import java.io.ByteArrayInputStream;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
-
-public class CaCertManagementTest extends BaseDeviceOwnerTest {
-    /**
-     * Test: device admins should be able to list all installed certs.
-     *
-     * <p>The list of certificates must never be {@code null}.
-     */
-    public void testCanRetrieveListOfInstalledCaCerts() {
-        List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
-        assertNotNull(caCerts);
-    }
-
-    /**
-     * Test: a valid cert should be installable and also removable.
-     */
-    public void testCanInstallAndUninstallACaCert()
-            throws CertificateException, GeneralSecurityException {
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertInstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-    }
-
-    /**
-     * Test: removing one certificate must not remove any others.
-     */
-    public void testUninstallationIsSelective()
-            throws CertificateException, GeneralSecurityException {
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
-
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
-        assertInstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-
-        mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
-    }
-
-    /**
-     * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
-     * supplementary installed certificate.
-     */
-    public void testCanUninstallAllUserCaCerts()
-            throws CertificateException, GeneralSecurityException {
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
-        assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
-
-        mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
-        assertUninstalled(FAKE_RSA_1.caCertificate);
-        assertUninstalled(FAKE_DSA_1.caCertificate);
-    }
-
-    private void assertInstalled(byte[] caBytes)
-            throws CertificateException, GeneralSecurityException {
-        Certificate caCert = readCertificate(caBytes);
-        assertTrue(isCaCertInstalledAndTrusted(caCert));
-    }
-
-    private void assertUninstalled(byte[] caBytes)
-            throws CertificateException, GeneralSecurityException {
-        Certificate caCert = readCertificate(caBytes);
-        assertFalse(isCaCertInstalledAndTrusted(caCert));
-    }
-
-    private static X509TrustManager getFirstX509TrustManager(TrustManagerFactory tmf) {
-        for (TrustManager trustManager : tmf.getTrustManagers()) {
-             if (trustManager instanceof X509TrustManager) {
-                 return (X509TrustManager) trustManager;
-             }
-        }
-        throw new RuntimeException("Unable to find X509TrustManager");
-    }
-
-    /**
-     * Whether a given cert, or one a lot like it, has been installed system-wide and is available
-     * to all apps.
-     *
-     * <p>A CA certificate is "installed" if it matches all of the following conditions:
-     * <ul>
-     *   <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
-     *   <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
-     *       necessarily exactly the same) in its response.</li>
-     *   <li>Any new instances of {@link TrustManager} should report the certificate among their
-     *       accepted issuer list -- older instances may keep the set of issuers they were created
-     *       with until explicitly refreshed.</li>
-     *
-     * @return {@code true} if installed by all metrics, {@code false} if not installed by any
-     *         metric. In any other case an {@link AssertionError} will be thrown.
-     */
-    private boolean isCaCertInstalledAndTrusted(Certificate caCert)
-            throws GeneralSecurityException, CertificateException {
-        boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
-
-        boolean listed = false;
-        for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
-            if (caCert.equals(readCertificate(certBuffer))) {
-                listed = true;
-            }
-        }
-
-        NetworkSecurityPolicy.getInstance().handleTrustStorageUpdate();
-
-        // Verify that the user added CA is reflected in the default X509TrustManager.
-        final TrustManagerFactory tmf =
-                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        // Use platform provided CA store.
-        tmf.init((KeyStore) null);
-        X509TrustManager tm = getFirstX509TrustManager(tmf);
-        boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
-        X509TrustManagerExtensions xtm = new X509TrustManagerExtensions(tm);
-        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 
-        assertEquals(installed, listed);
-        assertEquals(installed, trusted);
-        assertEquals(installed, userAddedCertificate);
-        return installed;
-    }
-
-    /**
-     * Convert an encoded certificate back into a {@link Certificate}.
-     *
-     * Instantiates a fresh CertificateFactory every time for repeatability.
-     */
-    private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
-        final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-        return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index 1bf4d45..a540c27 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -31,13 +31,17 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
 import java.lang.reflect.Field;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link DevicePolicyManager#createAndManageUser}.
  */
 public class CreateAndManageUserTest extends BaseDeviceOwnerTest {
+    private static final String TAG = "CreateAndManageUserTest";
 
     private static final String BROADCAST_EXTRA = "broadcastExtra";
     private static final String ACTION_EXTRA = "actionExtra";
@@ -270,6 +274,48 @@
         assertNotNull(mUserHandle);
 
         boolean removed = mDevicePolicyManager.removeUser(getWho(), mUserHandle);
-        assertFalse(removed);
+        // When the device owner itself has set the user restriction, it should still be allowed
+        // to remove a user.
+        assertTrue(removed);
+    }
+
+    public void testUserAddedOrRemovedBroadcasts() throws InterruptedException {
+        LocalBroadcastReceiver receiver = new LocalBroadcastReceiver();
+        LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(
+                getContext());
+        localBroadcastManager.registerReceiver(receiver, new IntentFilter(ACTION_USER_ADDED));
+        try {
+            mUserHandle = mDevicePolicyManager.createAndManageUser(getWho(), "Test User", getWho(),
+                    null, 0);
+            assertNotNull(mUserHandle);
+            assertEquals(mUserHandle, receiver.waitForBroadcastReceived());
+        } finally {
+            localBroadcastManager.unregisterReceiver(receiver);
+        }
+        localBroadcastManager.registerReceiver(receiver, new IntentFilter(ACTION_USER_REMOVED));
+        try {
+            assertTrue(mDevicePolicyManager.removeUser(getWho(), mUserHandle));
+            assertEquals(mUserHandle, receiver.waitForBroadcastReceived());
+            mUserHandle = null;
+        } finally {
+            localBroadcastManager.unregisterReceiver(receiver);
+        }
+    }
+
+    static class LocalBroadcastReceiver extends BroadcastReceiver {
+        private SynchronousQueue<UserHandle> mQueue = new SynchronousQueue<UserHandle>();
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            UserHandle userHandle = intent.getParcelableExtra(EXTRA_USER_HANDLE);
+            Log.d(TAG, "broadcast receiver received " + intent + " with userHandle "
+                    + userHandle);
+            mQueue.offer(userHandle);
+
+        }
+
+        public UserHandle waitForBroadcastReceived() throws InterruptedException {
+            return mQueue.poll(BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS);
+        }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java
deleted file mode 100644
index 11df8e5..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/FakeKeys.java
+++ /dev/null
@@ -1,469 +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.deviceowner;
-
-// Copied from cts/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
-
-public class FakeKeys {
-    /*
-     * The keys and certificates below are generated with:
-     *
-     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
-     * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
-     * mkdir -p demoCA/newcerts
-     * touch demoCA/index.txt
-     * echo "01" > demoCA/serial
-     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
-     */
-    public static class FAKE_RSA_1 {
-        /**
-         * Generated from above and converted with:
-         *
-         * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
-         */
-        public static final byte[] privateKey = {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
-            (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
-            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
-            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
-            (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
-            (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
-            (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
-            (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
-            (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
-            (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
-            (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
-            (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
-            (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
-            (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
-            (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
-            (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
-            (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
-            (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
-            (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
-            (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
-            (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
-            (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
-            (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
-            (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
-            (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
-            (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
-            (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
-            (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
-            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
-            (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
-            (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
-            (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
-            (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
-            (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
-            (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
-            (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
-            (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
-            (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
-            (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
-            (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
-            (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
-            (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
-            (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
-            (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
-            (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
-            (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
-            (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
-            (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
-            (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
-            (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
-            (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
-            (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
-            (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
-            (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
-            (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
-            (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
-            (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
-            (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
-            (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
-            (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
-            (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
-            (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
-            (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
-            (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
-            (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
-            (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
-            (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
-            (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
-            (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
-            (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
-            (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
-            (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
-            (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
-            (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
-            (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
-            (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
-            (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
-            (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
-            (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
-            (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
-            (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
-            (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
-            (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
-            (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
-            (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
-            (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
-            (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
-            (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
-            (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
-            (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
-            (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
-            (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
-            (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
-            (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
-            (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
-            (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
-            (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
-            (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
-            (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
-            (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
-            (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
-            (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
-            (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
-            (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
-            (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
-        };
-
-        /**
-         * Generated from above and converted with:
-         *
-         * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-         */
-        public static final byte[] caCertificate = {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82,
-            (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a,
-            (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53,
-            (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43,
-            (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d,
-            (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61,
-            (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
-            (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12,
-            (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69,
-            (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
-            (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73,
-            (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32,
-            (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36,
-            (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17,
-            (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31,
-            (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34,
-            (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41,
-            (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d,
-            (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69,
-            (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77,
-            (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41,
-            (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64,
-            (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20,
-            (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30,
-            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
-            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
-            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72,
-            (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7,
-            (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c,
-            (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64,
-            (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42,
-            (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb,
-            (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01,
-            (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03,
-            (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7,
-            (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d,
-            (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00,
-            (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9,
-            (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41,
-            (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60,
-            (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56,
-            (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f,
-            (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92,
-            (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62,
-            (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6,
-            (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb,
-            (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f,
-            (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51,
-            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
-            (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30,
-            (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e,
-            (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05,
-            (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9,
-            (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d,
-            (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51,
-            (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
-            (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80,
-            (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f,
-            (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73,
-            (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97,
-            (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4,
-            (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
-            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
-            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
-            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
-            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
-            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
-            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
-            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
-            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09,
-            (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e,
-            (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05,
-            (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30,
-            (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
-            (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
-            (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
-            (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a,
-            (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2,
-            (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda,
-            (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe,
-            (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b,
-            (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19,
-            (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3,
-            (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85,
-            (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5,
-            (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80,
-            (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd,
-            (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38,
-            (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2,
-            (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50,
-            (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f,
-            (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12,
-            (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14,
-            (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb,
-            (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74,
-            (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0,
-            (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e,
-            (byte) 0xf1, (byte) 0x61
-        };
-    }
-
-    /*
-     * The keys and certificates below are generated with:
-     *
-     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
-     * openssl dsaparam -out dsaparam.pem 1024
-     * openssl req -newkey dsa:dsaparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req
-     * mkdir -p demoCA/newcerts
-     * touch demoCA/index.txt
-     * echo "01" > demoCA/serial
-     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
-     */
-    public static class FAKE_DSA_1 {
-        /**
-         * Generated from above and converted with: openssl pkcs8 -topk8 -outform d
-         * -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
-         */
-        public static final byte[] privateKey = {
-            (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x4c, (byte) 0x02, (byte) 0x01,
-            (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2c, (byte) 0x06,
-            (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x38,
-            (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1f,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xb3, (byte) 0x23,
-            (byte) 0xf7, (byte) 0x86, (byte) 0xbd, (byte) 0x3b, (byte) 0x86, (byte) 0xcc,
-            (byte) 0xc3, (byte) 0x91, (byte) 0xc0, (byte) 0x30, (byte) 0x32, (byte) 0x02,
-            (byte) 0x47, (byte) 0x35, (byte) 0x01, (byte) 0xef, (byte) 0xee, (byte) 0x98,
-            (byte) 0x13, (byte) 0x56, (byte) 0x49, (byte) 0x47, (byte) 0xb5, (byte) 0x20,
-            (byte) 0xa8, (byte) 0x60, (byte) 0xcb, (byte) 0xc0, (byte) 0xd5, (byte) 0x77,
-            (byte) 0xc1, (byte) 0x69, (byte) 0xcd, (byte) 0x18, (byte) 0x34, (byte) 0x92,
-            (byte) 0xf2, (byte) 0x6a, (byte) 0x2a, (byte) 0x10, (byte) 0x59, (byte) 0x1c,
-            (byte) 0x91, (byte) 0x20, (byte) 0x51, (byte) 0xca, (byte) 0x37, (byte) 0xb2,
-            (byte) 0x87, (byte) 0xa6, (byte) 0x8a, (byte) 0x02, (byte) 0xfd, (byte) 0x45,
-            (byte) 0x46, (byte) 0xf9, (byte) 0x76, (byte) 0xb1, (byte) 0x35, (byte) 0x38,
-            (byte) 0x8d, (byte) 0xff, (byte) 0x4c, (byte) 0x5d, (byte) 0x75, (byte) 0x8f,
-            (byte) 0x66, (byte) 0x15, (byte) 0x7d, (byte) 0x7b, (byte) 0xda, (byte) 0xdb,
-            (byte) 0x57, (byte) 0x39, (byte) 0xff, (byte) 0x91, (byte) 0x3f, (byte) 0xdd,
-            (byte) 0xe2, (byte) 0xb4, (byte) 0x22, (byte) 0x60, (byte) 0x4c, (byte) 0x32,
-            (byte) 0x3b, (byte) 0x9d, (byte) 0x34, (byte) 0x9f, (byte) 0xb9, (byte) 0x5d,
-            (byte) 0x75, (byte) 0xb9, (byte) 0xd3, (byte) 0x7f, (byte) 0x11, (byte) 0xba,
-            (byte) 0xb7, (byte) 0xc8, (byte) 0x32, (byte) 0xc6, (byte) 0xce, (byte) 0x71,
-            (byte) 0x91, (byte) 0xd3, (byte) 0x32, (byte) 0xaf, (byte) 0x4d, (byte) 0x7e,
-            (byte) 0x7c, (byte) 0x15, (byte) 0xf7, (byte) 0x71, (byte) 0x2c, (byte) 0x52,
-            (byte) 0x65, (byte) 0x4d, (byte) 0xa9, (byte) 0x81, (byte) 0x25, (byte) 0x35,
-            (byte) 0xce, (byte) 0x0b, (byte) 0x5b, (byte) 0x56, (byte) 0xfe, (byte) 0xf1,
-            (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xeb, (byte) 0x4e, (byte) 0x7f,
-            (byte) 0x7a, (byte) 0x31, (byte) 0xb3, (byte) 0x7d, (byte) 0x8d, (byte) 0xb2,
-            (byte) 0xf7, (byte) 0xaf, (byte) 0xad, (byte) 0xb1, (byte) 0x42, (byte) 0x92,
-            (byte) 0xf3, (byte) 0x6c, (byte) 0xe4, (byte) 0xed, (byte) 0x8b, (byte) 0x02,
-            (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x81, (byte) 0xc8, (byte) 0x36,
-            (byte) 0x48, (byte) 0xdb, (byte) 0x71, (byte) 0x2b, (byte) 0x91, (byte) 0xce,
-            (byte) 0x6d, (byte) 0xbc, (byte) 0xb8, (byte) 0xf9, (byte) 0xcb, (byte) 0x50,
-            (byte) 0x91, (byte) 0x10, (byte) 0x8a, (byte) 0xf8, (byte) 0x37, (byte) 0x50,
-            (byte) 0xda, (byte) 0x4f, (byte) 0xc8, (byte) 0x4d, (byte) 0x73, (byte) 0xcb,
-            (byte) 0x4d, (byte) 0xb0, (byte) 0x19, (byte) 0x54, (byte) 0x5a, (byte) 0xf3,
-            (byte) 0x6c, (byte) 0xc9, (byte) 0xd8, (byte) 0x96, (byte) 0xd9, (byte) 0xb0,
-            (byte) 0x54, (byte) 0x7e, (byte) 0x7d, (byte) 0xe2, (byte) 0x58, (byte) 0x0e,
-            (byte) 0x5f, (byte) 0xc0, (byte) 0xce, (byte) 0xb9, (byte) 0x5c, (byte) 0xe3,
-            (byte) 0xd3, (byte) 0xdf, (byte) 0xcf, (byte) 0x45, (byte) 0x74, (byte) 0xfb,
-            (byte) 0xe6, (byte) 0x20, (byte) 0xe7, (byte) 0xfc, (byte) 0x0f, (byte) 0xca,
-            (byte) 0xdb, (byte) 0xc0, (byte) 0x0b, (byte) 0xe1, (byte) 0x5a, (byte) 0x16,
-            (byte) 0x1d, (byte) 0xb3, (byte) 0x2e, (byte) 0xe5, (byte) 0x5f, (byte) 0x89,
-            (byte) 0x17, (byte) 0x73, (byte) 0x50, (byte) 0xd1, (byte) 0x4a, (byte) 0x60,
-            (byte) 0xb7, (byte) 0xaa, (byte) 0xf0, (byte) 0xc7, (byte) 0xc5, (byte) 0x03,
-            (byte) 0x4e, (byte) 0x36, (byte) 0x51, (byte) 0x9e, (byte) 0x2f, (byte) 0xfa,
-            (byte) 0xf3, (byte) 0xd6, (byte) 0x58, (byte) 0x14, (byte) 0x02, (byte) 0xb4,
-            (byte) 0x41, (byte) 0xd6, (byte) 0x72, (byte) 0x6f, (byte) 0x58, (byte) 0x5b,
-            (byte) 0x2d, (byte) 0x23, (byte) 0xc0, (byte) 0x75, (byte) 0x4f, (byte) 0x39,
-            (byte) 0xa8, (byte) 0x6a, (byte) 0xdf, (byte) 0x79, (byte) 0x21, (byte) 0xf2,
-            (byte) 0x77, (byte) 0x91, (byte) 0x3f, (byte) 0x1c, (byte) 0x4d, (byte) 0x48,
-            (byte) 0x78, (byte) 0xcd, (byte) 0xed, (byte) 0x79, (byte) 0x23, (byte) 0x04,
-            (byte) 0x17, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xc7, (byte) 0xe7,
-            (byte) 0xe2, (byte) 0x6b, (byte) 0x14, (byte) 0xe6, (byte) 0x31, (byte) 0x12,
-            (byte) 0xb2, (byte) 0x1e, (byte) 0xd4, (byte) 0xf2, (byte) 0x9b, (byte) 0x2c,
-            (byte) 0xf6, (byte) 0x54, (byte) 0x4c, (byte) 0x12, (byte) 0xe8, (byte) 0x22
-
-        };
-
-        /**
-         * Generated from above and converted with:
-         *
-         * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-         */
-        public static final byte[] caCertificate = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8a, (byte) 0x30, (byte) 0x82,
-            (byte) 0x01, (byte) 0xf3, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0x87, (byte) 0xc0,
-            (byte) 0x68, (byte) 0x7f, (byte) 0x42, (byte) 0x92, (byte) 0x0b, (byte) 0x7a,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x5e, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
-            (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
-            (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
-            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
-            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
-            (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
-            (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
-            (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
-            (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17, (byte) 0x30, (byte) 0x15,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c,
-            (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
-            (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
-            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
-            (byte) 0x0d, (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32,
-            (byte) 0x37, (byte) 0x32, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x32,
-            (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33,
-            (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x32, (byte) 0x33,
-            (byte) 0x33, (byte) 0x31, (byte) 0x32, (byte) 0x39, (byte) 0x5a, (byte) 0x30,
-            (byte) 0x5e, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
-            (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c,
-            (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d,
-            (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
-            (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e,
-            (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74,
-            (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
-            (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
-            (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17,
-            (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x03, (byte) 0x0c, (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e,
-            (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c,
-            (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30,
-            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
-            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
-            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa4, (byte) 0xc7,
-            (byte) 0x06, (byte) 0xba, (byte) 0xdf, (byte) 0x2b, (byte) 0xee, (byte) 0xd2,
-            (byte) 0xb9, (byte) 0xe4, (byte) 0x52, (byte) 0x21, (byte) 0x68, (byte) 0x2b,
-            (byte) 0x83, (byte) 0xdf, (byte) 0xe3, (byte) 0x9c, (byte) 0x08, (byte) 0x73,
-            (byte) 0xdd, (byte) 0x90, (byte) 0xea, (byte) 0x97, (byte) 0x0c, (byte) 0x96,
-            (byte) 0x20, (byte) 0xb1, (byte) 0xee, (byte) 0x11, (byte) 0xd5, (byte) 0xd4,
-            (byte) 0x7c, (byte) 0x44, (byte) 0x96, (byte) 0x2e, (byte) 0x6e, (byte) 0xa2,
-            (byte) 0xb2, (byte) 0xa3, (byte) 0x4b, (byte) 0x0f, (byte) 0x32, (byte) 0x90,
-            (byte) 0xaf, (byte) 0x5c, (byte) 0x6f, (byte) 0x00, (byte) 0x88, (byte) 0x45,
-            (byte) 0x4e, (byte) 0x9b, (byte) 0x26, (byte) 0xc1, (byte) 0x94, (byte) 0x3c,
-            (byte) 0xfe, (byte) 0x10, (byte) 0xbd, (byte) 0xda, (byte) 0xf2, (byte) 0x8d,
-            (byte) 0x03, (byte) 0x52, (byte) 0x32, (byte) 0x11, (byte) 0xff, (byte) 0xf6,
-            (byte) 0xf9, (byte) 0x6e, (byte) 0x8f, (byte) 0x0f, (byte) 0xc8, (byte) 0x0a,
-            (byte) 0x48, (byte) 0x39, (byte) 0x33, (byte) 0xb9, (byte) 0x0c, (byte) 0xb3,
-            (byte) 0x2b, (byte) 0xab, (byte) 0x7d, (byte) 0x79, (byte) 0x6f, (byte) 0x57,
-            (byte) 0x5b, (byte) 0xb8, (byte) 0x84, (byte) 0xb6, (byte) 0xcc, (byte) 0xe8,
-            (byte) 0x30, (byte) 0x78, (byte) 0xff, (byte) 0x92, (byte) 0xe5, (byte) 0x43,
-            (byte) 0x2e, (byte) 0xef, (byte) 0x66, (byte) 0x98, (byte) 0xb4, (byte) 0xfe,
-            (byte) 0xa2, (byte) 0x40, (byte) 0xf2, (byte) 0x1f, (byte) 0xd0, (byte) 0x86,
-            (byte) 0x16, (byte) 0xc8, (byte) 0x45, (byte) 0xc4, (byte) 0x52, (byte) 0xcb,
-            (byte) 0x31, (byte) 0x5c, (byte) 0x9f, (byte) 0x32, (byte) 0x3b, (byte) 0xf7,
-            (byte) 0x19, (byte) 0x08, (byte) 0xc7, (byte) 0x00, (byte) 0x21, (byte) 0x7d,
-            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
-            (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16,
-            (byte) 0x04, (byte) 0x14, (byte) 0x47, (byte) 0x82, (byte) 0xa3, (byte) 0xf1,
-            (byte) 0xc2, (byte) 0x7e, (byte) 0x3a, (byte) 0xde, (byte) 0x4f, (byte) 0x30,
-            (byte) 0x4c, (byte) 0x7f, (byte) 0x72, (byte) 0x81, (byte) 0x15, (byte) 0x32,
-            (byte) 0xda, (byte) 0x7f, (byte) 0x58, (byte) 0x18, (byte) 0x30, (byte) 0x1f,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04,
-            (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x47,
-            (byte) 0x82, (byte) 0xa3, (byte) 0xf1, (byte) 0xc2, (byte) 0x7e, (byte) 0x3a,
-            (byte) 0xde, (byte) 0x4f, (byte) 0x30, (byte) 0x4c, (byte) 0x7f, (byte) 0x72,
-            (byte) 0x81, (byte) 0x15, (byte) 0x32, (byte) 0xda, (byte) 0x7f, (byte) 0x58,
-            (byte) 0x18, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03,
-            (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
-            (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
-            (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00,
-            (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x08, (byte) 0x7f,
-            (byte) 0x6a, (byte) 0x48, (byte) 0x90, (byte) 0x7b, (byte) 0x9b, (byte) 0x72,
-            (byte) 0x13, (byte) 0xa7, (byte) 0xef, (byte) 0x6b, (byte) 0x0b, (byte) 0x59,
-            (byte) 0xe5, (byte) 0x49, (byte) 0x72, (byte) 0x3a, (byte) 0xc8, (byte) 0x84,
-            (byte) 0xcc, (byte) 0x23, (byte) 0x18, (byte) 0x4c, (byte) 0xec, (byte) 0xc7,
-            (byte) 0xef, (byte) 0xcb, (byte) 0xa7, (byte) 0xbe, (byte) 0xe4, (byte) 0xef,
-            (byte) 0x8f, (byte) 0xc6, (byte) 0x06, (byte) 0x8c, (byte) 0xc0, (byte) 0xe4,
-            (byte) 0x2f, (byte) 0x2a, (byte) 0xc0, (byte) 0x35, (byte) 0x7d, (byte) 0x5e,
-            (byte) 0x19, (byte) 0x29, (byte) 0x8c, (byte) 0xb9, (byte) 0xf1, (byte) 0x1e,
-            (byte) 0xaf, (byte) 0x82, (byte) 0xd8, (byte) 0xe3, (byte) 0x88, (byte) 0xe1,
-            (byte) 0x31, (byte) 0xc8, (byte) 0x82, (byte) 0x1f, (byte) 0x83, (byte) 0xa9,
-            (byte) 0xde, (byte) 0xfe, (byte) 0x4b, (byte) 0xe2, (byte) 0x78, (byte) 0x64,
-            (byte) 0xed, (byte) 0xa4, (byte) 0x7b, (byte) 0xee, (byte) 0x8d, (byte) 0x71,
-            (byte) 0x1b, (byte) 0x44, (byte) 0xe6, (byte) 0xb7, (byte) 0xe8, (byte) 0xc5,
-            (byte) 0x9a, (byte) 0x93, (byte) 0x92, (byte) 0x6f, (byte) 0x6f, (byte) 0xdb,
-            (byte) 0xbd, (byte) 0xd7, (byte) 0x03, (byte) 0x85, (byte) 0xa9, (byte) 0x5f,
-            (byte) 0x53, (byte) 0x5f, (byte) 0x5d, (byte) 0x30, (byte) 0xc6, (byte) 0xd9,
-            (byte) 0xce, (byte) 0x34, (byte) 0xa8, (byte) 0xbe, (byte) 0x31, (byte) 0x47,
-            (byte) 0x1c, (byte) 0xa4, (byte) 0x7f, (byte) 0xc0, (byte) 0x2c, (byte) 0xbc,
-            (byte) 0xfe, (byte) 0x1a, (byte) 0x31, (byte) 0xd8, (byte) 0x77, (byte) 0x4d,
-            (byte) 0xfc, (byte) 0x45, (byte) 0x84, (byte) 0xfc, (byte) 0x45, (byte) 0x12,
-            (byte) 0xab, (byte) 0x50, (byte) 0xe4, (byte) 0x45, (byte) 0xe5, (byte) 0x11
-        };
-    }
-}
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..8aae258 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 com.android.compatibility.common.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/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
index f6f8dbbc..15dd07f 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
@@ -22,8 +22,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.provider.Settings;
 import android.os.Bundle;
+import android.util.Log;
 
 // This is not a standard test of an android activity (such as
 // ActivityInstrumentationTestCase2) as it is attempting to test the actual
@@ -31,6 +31,8 @@
 // and setup.
 public class LockTaskTest extends BaseDeviceOwnerTest {
 
+    private static final String TAG = "LockTaskTest";
+
     private static final String TEST_PACKAGE = "com.google.android.example.somepackage";
 
     private static final String UTILITY_ACTIVITY
@@ -48,7 +50,6 @@
     private static final int ACTIVITY_RESUMED_TIMEOUT_MILLIS = 20000;  // 20 seconds
     private static final int ACTIVITY_RUNNING_TIMEOUT_MILLIS = 10000;  // 10 seconds
     private static final int ACTIVITY_DESTROYED_TIMEOUT_MILLIS = 60000;  // 60 seconds
-    private static final int UPDATE_LOCK_TASK_TIMEOUT_MILLIS = 1000; // 1 second
     public static final String RECEIVING_ACTIVITY_CREATED_ACTION
             = "com.android.cts.deviceowner.RECEIVING_ACTIVITY_CREATED_ACTION";
     /**
@@ -63,6 +64,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            Log.d(TAG, "onReceive: " + action);
             if (LockTaskUtilityActivity.CREATE_ACTION.equals(action)) {
                 synchronized (mActivityRunningLock) {
                     mIsActivityRunning = true;
@@ -107,13 +109,13 @@
         }
     }
 
-    private boolean mIsActivityRunning;
-    private boolean mIsActivityResumed;
-    private boolean mReceivingActivityWasCreated;
+    private volatile boolean mIsActivityRunning;
+    private volatile boolean mIsActivityResumed;
+    private volatile boolean mReceivingActivityWasCreated;
+    private volatile boolean mIntentHandled;
     private final Object mActivityRunningLock = new Object();
     private final Object mActivityResumedLock = new Object();
     private final Object mReceivingActivityCreatedLock = new Object();
-    private Boolean mIntentHandled;
 
     private ActivityManager mActivityManager;
 
@@ -149,7 +151,7 @@
     }
 
     // Start lock task, verify that ActivityManager knows thats what is going on.
-    public void testStartLockTask() {
+    public void testStartLockTask() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
         waitForResume();
@@ -164,7 +166,7 @@
 
     // Verifies that the act of finishing is blocked by ActivityManager in lock task.
     // This results in onDestroy not being called until stopLockTask is called before finish.
-    public void testCannotFinish() {
+    public void testCannotFinish() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
 
@@ -177,17 +179,14 @@
     }
 
     // Verifies that updating the whitelisting during lock task mode finishes the locked task.
-    public void testUpdateWhitelisting() {
+    public void testUpdateWhitelisting() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
 
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[0]);
 
         synchronized (mActivityRunningLock) {
-            try {
-                mActivityRunningLock.wait(UPDATE_LOCK_TASK_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
         }
 
         assertLockTaskModeInactive();
@@ -197,7 +196,7 @@
 
     // This launches an activity that is in the current task.
     // This should always be permitted as a part of lock task (since it isn't a new task).
-    public void testStartActivity_withinTask() {
+    public void testStartActivity_withinTask() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
         waitForResume();
@@ -209,10 +208,7 @@
         mContext.startActivity(lockTaskUtility);
 
         synchronized (mReceivingActivityCreatedLock) {
-            try {
-                mReceivingActivityCreatedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            mReceivingActivityCreatedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
             assertTrue(mReceivingActivityWasCreated);
         }
         stopAndFinish(UTILITY_ACTIVITY);
@@ -220,7 +216,7 @@
 
     // This launches a whitelisted activity that is not part of the current task.
     // This should be permitted as a part of lock task.
-    public void testStartActivity_outsideTaskWhitelisted() {
+    public void testStartActivity_outsideTaskWhitelisted() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME,
                 RECEIVING_ACTIVITY_PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
@@ -231,10 +227,7 @@
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         mContext.startActivity(launchIntent);
         synchronized (mReceivingActivityCreatedLock) {
-            try {
-                mReceivingActivityCreatedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            mReceivingActivityCreatedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
             assertTrue(mReceivingActivityWasCreated);
         }
         stopAndFinish(UTILITY_ACTIVITY);
@@ -242,7 +235,7 @@
 
     // This launches a non-whitelisted activity that is not part of the current task.
     // This should be blocked.
-    public void testStartActivity_outsideTaskNonWhitelisted() {
+    public void testStartActivity_outsideTaskNonWhitelisted() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startLockTask(UTILITY_ACTIVITY);
         waitForResume();
@@ -250,10 +243,7 @@
         Intent launchIntent = getIntentReceivingActivityIntent(Intent.FLAG_ACTIVITY_NEW_TASK);
         mContext.startActivity(launchIntent);
         synchronized (mActivityResumedLock) {
-            try {
-                mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
             assertFalse(mReceivingActivityWasCreated);
         }
         stopAndFinish(UTILITY_ACTIVITY);
@@ -261,7 +251,7 @@
 
     // Test the lockTaskMode flag for an activity declaring if_whitelisted.
     // Whitelist the activity and verify that lock task mode is started.
-    public void testManifestArgument_whitelisted() {
+    public void testManifestArgument_whitelisted() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
         waitForResume();
@@ -275,7 +265,7 @@
 
     // Test the lockTaskMode flag for an activity declaring if_whitelisted.
     // Don't whitelist the activity and verify that lock task mode is not started.
-    public void testManifestArgument_nonWhitelisted() {
+    public void testManifestArgument_nonWhitelisted() throws Exception {
         startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
         waitForResume();
 
@@ -288,7 +278,7 @@
 
     // Test the lockTaskMode flag for an activity declaring if_whitelisted.
     // An activity locked via manifest argument cannot finish without calling stopLockTask.
-    public void testManifestArgument_cannotFinish() {
+    public void testManifestArgument_cannotFinish() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
         waitForResume();
@@ -303,7 +293,7 @@
 
     // Test the lockTaskMode flag for an activity declaring if_whitelisted.
     // Verifies that updating the whitelisting during lock task mode finishes the locked task.
-    public void testManifestArgument_updateWhitelisting() {
+    public void testManifestArgument_updateWhitelisting() throws Exception {
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[] { PACKAGE_NAME });
         startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
         waitForResume();
@@ -311,10 +301,7 @@
         mDevicePolicyManager.setLockTaskPackages(getWho(), new String[0]);
 
         synchronized (mActivityRunningLock) {
-            try {
-                mActivityRunningLock.wait(UPDATE_LOCK_TASK_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
         }
 
         assertLockTaskModeInactive();
@@ -347,7 +334,7 @@
      * If activityManager is not null then verify that the ActivityManager
      * is no longer in lock task mode.
      */
-    private void stopAndFinish(String className) {
+    private void stopAndFinish(String className) throws InterruptedException {
         stopLockTask(className);
         finishAndWait(className);
         assertLockTaskModeInactive();
@@ -358,14 +345,11 @@
      * Call finish on the LockTaskUtilityActivity and wait for
      * onDestroy to be called.
      */
-    private void finishAndWait(String className) {
+    private void finishAndWait(String className) throws InterruptedException {
         synchronized (mActivityRunningLock) {
             finish(className);
             if (mIsActivityRunning) {
-                try {
-                    mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
-                } catch (InterruptedException e) {
-                }
+                mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
             }
         }
     }
@@ -373,14 +357,11 @@
     /**
      * Wait for onResume to be called on the LockTaskUtilityActivity.
      */
-    private void waitForResume() {
+    private void waitForResume() throws InterruptedException {
         // It may take a moment for the resume to come in.
         synchronized (mActivityResumedLock) {
             if (!mIsActivityResumed) {
-                try {
-                    mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
-                } catch (InterruptedException e) {
-                }
+                mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
             }
         }
     }
@@ -388,7 +369,7 @@
     /**
      * Calls startLockTask on the LockTaskUtilityActivity
      */
-    private void startLockTask(String className) {
+    private void startLockTask(String className) throws InterruptedException {
         Intent intent = getLockTaskUtility(className);
         intent.putExtra(LockTaskUtilityActivity.START_LOCK_TASK, true);
         startAndWait(intent);
@@ -397,7 +378,7 @@
     /**
      * Calls stopLockTask on the LockTaskUtilityActivity
      */
-    private void stopLockTask(String className) {
+    private void stopLockTask(String className) throws InterruptedException {
         Intent intent = getLockTaskUtility(className);
         intent.putExtra(LockTaskUtilityActivity.STOP_LOCK_TASK, true);
         startAndWait(intent);
@@ -406,7 +387,7 @@
     /**
      * Calls finish on the LockTaskUtilityActivity
      */
-    private void finish(String className) {
+    private void finish(String className) throws InterruptedException {
         Intent intent = getLockTaskUtility(className);
         intent.putExtra(LockTaskUtilityActivity.FINISH, true);
         startAndWait(intent);
@@ -417,15 +398,12 @@
      * to receive the broadcast back confirming it has finished processing
      * the command.
      */
-    private void startAndWait(Intent intent) {
+    private void startAndWait(Intent intent) throws InterruptedException {
         mIntentHandled = false;
         synchronized (this) {
             mContext.startActivity(intent);
             // Give 20 secs to finish.
-            try {
-                wait(ACTIVITY_RUNNING_TIMEOUT_MILLIS);
-            } catch (InterruptedException e) {
-            }
+            wait(ACTIVITY_RUNNING_TIMEOUT_MILLIS);
             assertTrue(mIntentHandled);
         }
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java
index 2901f5b..aeb8abd 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java
@@ -18,8 +18,10 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.util.Log;
 
 public class LockTaskUtilityActivity extends Activity {
+    private static final String TAG = "LockTaskUtilityActivity";
 
     public static final String START_LOCK_TASK = "startLockTask";
     public static final String STOP_LOCK_TASK = "stopLockTask";
@@ -41,25 +43,25 @@
     @Override
     protected void onCreate(android.os.Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        sendBroadcast(new Intent(CREATE_ACTION));
+        sendLocalBroadcast(new Intent(CREATE_ACTION));
         handleIntent(getIntent());
     }
 
     @Override
     protected void onDestroy() {
-        sendBroadcast(new Intent(DESTROY_ACTION));
+        sendLocalBroadcast(new Intent(DESTROY_ACTION));
         super.onDestroy();
     }
 
     @Override
     protected void onResume() {
-        sendBroadcast(new Intent(RESUME_ACTION));
+        sendLocalBroadcast(new Intent(RESUME_ACTION));
         super.onResume();
     }
 
     @Override
     protected void onPause() {
-        sendBroadcast(new Intent(PAUSE_ACTION));
+        sendLocalBroadcast(new Intent(PAUSE_ACTION));
         super.onPause();
     }
 
@@ -77,7 +79,13 @@
         if (intent.getBooleanExtra(FINISH, false)) {
             finish();
         }
-        sendBroadcast(new Intent(INTENT_ACTION));
+        sendLocalBroadcast(new Intent(INTENT_ACTION));
     }
 
+    private void sendLocalBroadcast(Intent intent) {
+        Log.d(TAG, "sendLocalBroadcast: " + intent.getAction());
+        intent.setPackage(this.getPackageName());
+        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        sendBroadcast(intent);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java
new file mode 100644
index 0000000..ea5b751
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.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.deviceowner;
+
+import android.app.admin.NetworkEvent;
+
+import java.util.List;
+
+public class NetworkLoggingTest extends BaseDeviceOwnerTest {
+
+    private static final String MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED =
+            "There should only be one user, managed by Device Owner";
+    private static final int FAKE_BATCH_TOKEN = -666; // batch tokens are always non-negative
+
+    /**
+     * Test: setting network logging can only be done if there's one user on the device.
+     */
+    public void testSetNetworkLoggingEnabledNotPossibleIfMoreThanOneUserPresent() {
+        try {
+            mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
+        }
+    }
+
+    /**
+     * Test: retrieving network logs can only be done if there's one user on the device.
+     */
+    public void testRetrievingNetworkLogsNotPossibleIfMoreThanOneUserPresent() {
+        try {
+            mDevicePolicyManager.retrieveNetworkLogs(getWho(), FAKE_BATCH_TOKEN);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
+        }
+    }
+
+    /**
+     * Test: Test enabling and disabling of network logging.
+     */
+    public void testEnablingAndDisablingNetworkLogging() {
+        mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), true);
+        assertTrue(mDevicePolicyManager.isNetworkLoggingEnabled(getWho()));
+        // TODO: here test that facts about logging are shown in the UI
+        mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), false);
+        assertFalse(mDevicePolicyManager.isNetworkLoggingEnabled(getWho()));
+    }
+
+    /**
+     * Test: when a wrong batch token id (not a token of the current batch) is provided, null should
+     * be returned.
+     */
+    public void testProvidingWrongBatchTokenReturnsNull() {
+        assertNull(mDevicePolicyManager.retrieveNetworkLogs(getWho(), FAKE_BATCH_TOKEN));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java
index c70ed16..1751244 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PreDeviceOwnerTest.java
@@ -39,8 +39,8 @@
         assertFalse(mDevicePolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE));
     }
 
-    public void testIsProvisioningAllowedFalseForManagedProfileAction() {
-        assertFalse(mDevicePolicyManager
+    public void testIsProvisioningAllowedTrueForManagedProfileAction() {
+        assertTrue(mDevicePolicyManager
                 .isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE));
     }
 
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml b/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
index 1512bb2..da0e16c 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/AndroidManifest.xml
@@ -21,7 +21,8 @@
 
     <uses-permission android:name="com.android.cts.managedprofile.permission.SAMPLE"/>
 
-    <application>
+    <application
+        android:testOnly="true">
 
         <uses-library android:name="android.test.runner" />
 
@@ -31,6 +32,8 @@
                 <action android:name="com.android.cts.action.READ_FROM_URI" />
                 <action android:name="com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION" />
                 <action android:name="com.android.cts.action.WRITE_TO_URI" />
+                <action android:name="com.android.cts.action.NOTIFY_URI_CHANGE"/>
+                <action android:name="com.android.cts.action.OBSERVE_URI_CHANGE"/>
                 <action android:name="com.android.cts.action.JUST_CREATE" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
index 9aa948e..a645a87 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
@@ -16,11 +16,14 @@
 package com.android.cts.intent.receiver;
 
 import android.app.Activity;
-import android.content.ClipboardManager;
 import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.util.Log;
 
 import java.io.BufferedReader;
@@ -28,6 +31,8 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Class to receive intents sent across profile boundaries, and read/write to content uri specified
@@ -55,6 +60,12 @@
     public static final String RECEIVING_ACTIVITY_CREATED_ACTION
             = "com.android.cts.deviceowner.RECEIVING_ACTIVITY_CREATED_ACTION";
 
+    public static final String ACTION_NOTIFY_URI_CHANGE
+            = "com.android.cts.action.NOTIFY_URI_CHANGE";
+
+    public static final String ACTION_OBSERVE_URI_CHANGE
+            = "com.android.cts.action.OBSERVE_URI_CHANGE";
+
     private static final String EXTRA_CAUGHT_SECURITY_EXCEPTION = "extra_caught_security_exception";
 
     public void onCreate(Bundle savedInstanceState) {
@@ -103,12 +114,54 @@
                 Log.i(TAG, "Caught a IOException while trying to write to " + uri, e);
             }
             setResult(Activity.RESULT_OK, result);
+        } else if (ACTION_NOTIFY_URI_CHANGE.equals(action)) {
+            Log.i(TAG, "Notifying a uri change to " + uri);
+            getContentResolver().notifyChange(uri, null);
+            setResult(Activity.RESULT_OK);
+        } else if (ACTION_OBSERVE_URI_CHANGE.equals(action)) {
+            Log.i(TAG, "Observing a uri change to " + uri);
+            HandlerThread handlerThread = new HandlerThread("observer");
+            handlerThread.start();
+            UriObserver uriObserver = new UriObserver(new Handler(handlerThread.getLooper()));
+            try {
+                getContentResolver().registerContentObserver(uri, false, uriObserver);
+                uriObserver.waitForNotify();
+                setResult(Activity.RESULT_OK, new Intent());
+            } finally {
+                getContentResolver().unregisterContentObserver(uriObserver);
+                handlerThread.quit();
+            }
         } else if (ACTION_JUST_CREATE.equals(action)) {
             sendBroadcast(new Intent(RECEIVING_ACTIVITY_CREATED_ACTION));
         }
         finish();
     }
 
+    private class UriObserver extends ContentObserver {
+        private final Semaphore mNotificationReceived = new Semaphore(0);
+        public UriObserver(Handler handler) {
+           super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            // Here, we can't test that uri is the uri that was called with registerContentObserver
+            // because it doesn't have the userId in the userInfo part.
+            mNotificationReceived.release(1);
+        }
+
+        private boolean waitForNotify() {
+            // The uri notification may not come immediately.
+            try {
+                return mNotificationReceived.tryAcquire(1, 30, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Interrupted while waiting for notification change", e);
+                return false;
+            }
+        }
+    }
+
     /**
      * Returns the first line of the file associated with uri.
      */
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index 74509d2..b0abc23 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner ub-uiautomator
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/AppLinkTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/AppLinkTest.java
index fb22ab3..1da1202 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/AppLinkTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/AppLinkTest.java
@@ -16,13 +16,11 @@
 
 package com.android.cts.intent.sender;
 
-import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.test.InstrumentationTestCase;
-import android.util.Log;
 
 public class AppLinkTest extends InstrumentationTestCase {
 
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/ContentTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/ContentTest.java
index 1aaa5ab..6fe733b 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/ContentTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/ContentTest.java
@@ -20,7 +20,10 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.support.v4.content.FileProvider;
 import android.test.InstrumentationTestCase;
 import android.util.Log;
@@ -31,6 +34,10 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
 
 public class ContentTest extends InstrumentationTestCase {
 
@@ -43,6 +50,12 @@
     private static final String ACTION_TAKE_PERSISTABLE_URI_PERMISSION =
             "com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION";
 
+    public static final String ACTION_NOTIFY_URI_CHANGE
+            = "com.android.cts.action.NOTIFY_URI_CHANGE";
+
+    public static final String ACTION_OBSERVE_URI_CHANGE
+            = "com.android.cts.action.OBSERVE_URI_CHANGE";
+
     private static final String TAG = "CrossProfileContentTest";
 
     private Context mContext;
@@ -68,7 +81,7 @@
      */
     public void testReceiverCanRead() throws Exception {
         Uri uri = getUriWithTextInFile("reading_test", MESSAGE);
-        assertTrue(uri != null);
+        assertNotNull(uri);
         Intent intent = new Intent(ACTION_READ_FROM_URI);
         intent.setClipData(ClipData.newRawUri("", uri));
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -165,6 +178,79 @@
         }
     }
 
+    /**
+     * Test that an app can notify a uri change across profiles.
+     */
+    public void testCanNotifyAcrossProfiles() throws Exception {
+        Uri uri = getUriWithTextInFile("notifying_test", "");
+        assertNotNull(uri);
+        Intent intent = new Intent(ACTION_NOTIFY_URI_CHANGE);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        HandlerThread handlerThread = new HandlerThread("observer");
+        handlerThread.start();
+        UriObserver uriObserver = new UriObserver(new Handler(handlerThread.getLooper()));
+        try {
+            mContext.getContentResolver().registerContentObserver(uri, false, uriObserver);
+            // ask the cross-profile receiver to notify the uri
+            mActivity.getCrossProfileResult(intent);
+            assertEquals(uri, uriObserver.waitForNotify());
+        } finally {
+            mContext.getContentResolver().unregisterContentObserver(uriObserver);
+            handlerThread.quit();
+        }
+    }
+
+    /**
+     * Test that an app can observe a uri change across profiles.
+     */
+    public void testCanObserveAcrossProfiles() throws Exception {
+        final Uri uri = getUriWithTextInFile("observing_test", "");
+        assertNotNull(uri);
+        Intent intent = new Intent(ACTION_OBSERVE_URI_CHANGE);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        Timer timer = new Timer();
+        timer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                mContext.getContentResolver().notifyChange(uri, null);
+            }
+        }, 5000 /* 5 seconds */);
+
+        // Check that the app in the other profile could be notified of the change.
+        // A non-null result intent indicates success.
+        assertNotNull(mActivity.getCrossProfileResult(intent));
+    }
+
+    private class UriObserver extends ContentObserver {
+        private final SynchronousQueue<Uri> mSynchronousQueue;
+
+        public UriObserver(Handler handler) {
+           super(handler);
+           mSynchronousQueue = new SynchronousQueue<Uri>();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            try {
+                if (!mSynchronousQueue.offer(uri, 5, TimeUnit.SECONDS)) {
+                    Log.e(TAG, "Failed to offer uri " + uri + " to synchronous queue");
+                }
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Interrupted while receiving onChange for " + uri, e);
+            }
+        }
+
+        private Uri waitForNotify() throws InterruptedException {
+            // The uri notification may not come immediately.
+            return mSynchronousQueue.poll(30, TimeUnit.SECONDS);
+        }
+    }
+
     private void grantPersistableReadPermission(Uri uri) throws Exception {
         Intent grantPersistable = new Intent(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
         grantPersistable.setClipData(ClipData.newRawUri("", uri));
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
index 18cb3ee..68e9e8b 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
@@ -3,15 +3,31 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
 import android.test.InstrumentationTestCase;
 
 public class SuspendPackageTest extends InstrumentationTestCase {
+    private static final int WAIT_DIALOG_TIMEOUT_IN_MS = 5000;
+    private static final BySelector POPUP_IMAGE_SELECTOR = By
+            .clazz(android.widget.ImageView.class.getName())
+            .res("com.android.settings:id/admin_support_icon")
+            .pkg("com.android.settings");
+
+    private static final BySelector POPUP_BUTTON_SELECTOR = By
+            .clazz(android.widget.Button.class.getName())
+            .res("android:id/button1")
+            .pkg("com.android.settings");
+
     private IntentSenderActivity mActivity;
     private Context mContext;
     private PackageManager mPackageManager;
 
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
-    private static final String TARGET_ACTIVTIY_NAME
+    private static final String TARGET_ACTIVITY_NAME
             = "com.android.cts.intent.receiver.SimpleIntentReceiverActivity";
 
     @Override
@@ -37,19 +53,34 @@
     }
 
     /**
-     * Verify the package is suspended by trying start the activity inside it. If the package
-     * is not suspended, the target activity will return the result.
+     * Verify that the package is suspended by trying to start the activity inside it. If the
+     * package is not suspended, the target activity will return the result.
      */
     private void assertPackageSuspended(boolean suspended) throws Exception {
         Intent intent = new Intent();
-        intent.setClassName(INTENT_RECEIVER_PKG, TARGET_ACTIVTIY_NAME);
+        intent.setClassName(INTENT_RECEIVER_PKG, TARGET_ACTIVITY_NAME);
         Intent result = mActivity.getResult(intent);
         if (suspended) {
+            dismissPolicyTransparencyDialog();
             assertNull(result);
         } else {
             assertNotNull(result);
         }
-        // No matter it is suspended or not, we should able to resolve the activity.
+        // No matter if it is suspended or not, we should be able to resolve the activity.
         assertNotNull(mPackageManager.resolveActivity(intent, 0));
     }
+
+    /**
+     * Wait for the policy transparency dialog and dismiss it.
+     */
+    private void dismissPolicyTransparencyDialog() {
+        final UiDevice device = UiDevice.getInstance(getInstrumentation());
+        device.wait(Until.hasObject(POPUP_IMAGE_SELECTOR), WAIT_DIALOG_TIMEOUT_IN_MS);
+        final UiObject2 icon = device.findObject(POPUP_IMAGE_SELECTOR);
+        assertNotNull("Policy transparency dialog icon not found", icon);
+        // "OK" button only present in the dialog if it is blocked by policy.
+        final UiObject2 button = device.findObject(POPUP_BUTTON_SELECTOR);
+        assertNotNull("OK button not found", button);
+        button.click();
+    }
 }
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/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
index 195a18b..a5e8da1 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -68,7 +68,7 @@
             = new LinkedBlockingQueue();
 
     private TestCallback mCallback;
-    private Object mCallbackLock = new Object();
+    private final Object mCallbackLock = new Object();
     private final Messenger mMessenger = new Messenger(new CheckHandler());
     private final HandlerThread mCallbackThread = new HandlerThread("callback");
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index 85c74f9..109804a 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 guava
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index a2c7219..e5786dd 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <uses-sdk android:minSdkVersion="20"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -78,7 +79,9 @@
                 <action android:name="com.android.cts.managedprofile.ACTION_TEST_ALL_ACTIVITY" />
             </intent-filter>
         </activity>
-        <activity android:name=".SetPolicyActivity" >
+        <activity
+            android:name=".SetPolicyActivity"
+            android:launchMode="singleTop">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BaseManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BaseManagedProfileTest.java
index 45d540e..905f7d5 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BaseManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BaseManagedProfileTest.java
@@ -51,13 +51,10 @@
                 mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
         assertNotNull(mDevicePolicyManager);
 
-        // TODO: Only check the below if we are running as the profile user. If running under the
-        // user owner, can we check that there is a profile and that the below holds for it? If we
-        // don't want to do these checks every time we could get rid of this class altogether and
-        // just have a single test case running under the profile user that do them.
         assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
         assertTrue(mDevicePolicyManager.isProfileOwnerApp(
                 ADMIN_RECEIVER_COMPONENT.getPackageName()));
+        assertTrue(mDevicePolicyManager.isManagedProfile(ADMIN_RECEIVER_COMPONENT));
     }
 
     protected DevicePolicyManager getDevicePolicyManager(boolean isParent) {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
index 6a63cea..ab3c5d5 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
@@ -49,6 +49,10 @@
 
     private static String ACTION_COPY_TO_CLIPBOARD = "com.android.cts.action.COPY_TO_CLIPBOARD";
 
+    private static String ACTION_NOTIFY_URI_CHANGE = "com.android.cts.action.NOTIFY_URI_CHANGE";
+
+    private static String ACTION_OBSERVE_URI_CHANGE = "com.android.cts.action.OBSERVE_URI_CHANGE";
+
     public void testAddParentCanAccessManagedFilters() {
         testRemoveAllFilters();
 
@@ -73,6 +77,8 @@
         intentFilter.addAction(ACTION_WRITE_TO_URI);
         intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
         intentFilter.addAction(ACTION_COPY_TO_CLIPBOARD);
+        intentFilter.addAction(ACTION_NOTIFY_URI_CHANGE);
+        intentFilter.addAction(ACTION_OBSERVE_URI_CHANGE);
         return intentFilter;
     }
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelper.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelper.java
new file mode 100644
index 0000000..550f1d3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelper.java
@@ -0,0 +1,202 @@
+/*
+ * 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.managedprofile;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.primitives.Primitives;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.io.File;
+import java.lang.reflect.Method;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+/**
+ * Helper class for retrieving the current list of API methods.
+ */
+public class CurrentApiHelper {
+
+    /**
+     * Location of the XML file that lists the current public APIs.
+     *
+     * <p><b>Note:</b> must be consistent with
+     * {@code cts/hostsidetests/devicepolicy/AndroidTest.xml}
+     */
+    private static final String CURRENT_API_FILE = "/data/local/tmp/device-policy-test/current.api";
+
+    private static final String LOG_TAG = "CurrentApiHelper";
+
+    private static final ImmutableMap<String, Class> PRIMITIVE_TYPES = getPrimitiveTypes();
+    private static final ImmutableMap<String, String> PRIMITIVE_ENCODINGS =
+            new ImmutableMap.Builder<String, String>()
+                    .put("boolean", "Z")
+                    .put("byte", "B")
+                    .put("char", "C")
+                    .put("double", "D")
+                    .put("float", "F")
+                    .put("int", "I")
+                    .put("long", "J")
+                    .put("short", "S")
+                    .build();
+
+    private static final String TAG_PACKAGE = "package";
+    private static final String TAG_CLASS = "class";
+    private static final String TAG_METHOD = "method";
+    private static final String TAG_PARAMETER = "parameter";
+
+    private static final String ATTRIBUTE_NAME = "name";
+    private static final String ATTRIBUTE_TYPE = "type";
+
+    /**
+     * Get public API methods of a specific class as defined in the API document.
+     *
+     * @param packageName The name of the package containing the class, e.g. {@code android.app}.
+     * @param className The name of the class, e.g. {@code Application}.
+     * @return an immutable list of {@link Method} instances.
+     */
+    public static ImmutableList<Method> getPublicApis(String packageName, String className)
+            throws Exception {
+        Document apiDocument = parseXmlFile(CURRENT_API_FILE);
+        Element rootElement = apiDocument.getDocumentElement();
+        Element packageElement = getChildElementByName(rootElement, TAG_PACKAGE, packageName);
+        Element classElement = getChildElementByName(packageElement, TAG_CLASS, className);
+
+        ImmutableList.Builder<Method> builder = new ImmutableList.Builder<>();
+
+        NodeList nodes = classElement.getElementsByTagName(TAG_METHOD);
+        if (nodes != null && nodes.getLength() > 0) {
+            Class clazz = Class.forName(packageName + "." + className);
+
+            for (int i = 0; i < nodes.getLength(); ++i) {
+                Element element = (Element) nodes.item(i);
+                String name = element.getAttribute(ATTRIBUTE_NAME);
+                Class[] paramTypes = getParamTypes(element);
+                builder.add(clazz.getMethod(name, paramTypes));
+            }
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Given a {@link Class} object, get the default value if the {@link Class} refers to a
+     * primitive type, or null if it refers to an object.
+     *
+     * <p><ul>
+     *     <li>For boolean type, return {@code false}
+     *     <li>For other primitive types, return {@code 0}
+     *     <li>For all other types, return {@code null}
+     * </ul>
+     * @param clazz The desired class to instantiate.
+     * @return Default instance as described above.
+     */
+    public static Object instantiate(Class clazz) {
+        if (clazz.isPrimitive()) {
+            if (boolean.class.equals(clazz)) {
+                return false;
+            } else {
+                return 0;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private static Document parseXmlFile(String filePath) throws Exception {
+        File apiFile = new File(filePath);
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        Document dom = db.parse(apiFile.toURI().toString());
+
+        return dom;
+    }
+
+    private static Element getChildElementByName(Element parent,
+            String childTag, String childName) {
+        NodeList nodeList = parent.getElementsByTagName(childTag);
+        if (nodeList != null && nodeList.getLength() > 0) {
+            for (int i = 0; i < nodeList.getLength(); ++i) {
+                Element el = (Element) nodeList.item(i);
+                if (childName.equals(el.getAttribute(ATTRIBUTE_NAME))) {
+                    return el;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Class[] getParamTypes(Element methodElement) throws Exception {
+        NodeList nodes = methodElement.getElementsByTagName(TAG_PARAMETER);
+        if (nodes != null && nodes.getLength() > 0) {
+            int paramCount = nodes.getLength();
+            Class[] paramTypes = new Class[paramCount];
+            for (int i = 0; i < paramCount; ++i) {
+                String typeName = ((Element) nodes.item(i)).getAttribute(ATTRIBUTE_TYPE);
+                paramTypes[i] = getClassByName(typeName);
+            }
+            return paramTypes;
+        } else {
+            return new Class[0];
+        }
+    }
+
+    private static Class getClassByName(String typeName) throws ClassNotFoundException {
+        // Check if typeName represents an array
+        int arrayDim = 0;
+        while (typeName.endsWith("[]")) {
+            arrayDim++;
+            typeName = typeName.substring(0, typeName.length() - 2);
+        }
+
+        // Remove type parameters, if any
+        typeName = typeName.replaceAll("<.*>$", "");
+
+        if (arrayDim == 0) {
+            if (isPrimitiveTypeName(typeName)) {
+                return PRIMITIVE_TYPES.get(typeName);
+            } else {
+                return Class.forName(typeName);
+            }
+
+        } else {
+            String prefix = Strings.repeat("[", arrayDim);
+            if (isPrimitiveTypeName(typeName)) {
+                return Class.forName(prefix + PRIMITIVE_ENCODINGS.get(typeName));
+            } else {
+                return Class.forName(prefix + "L" + typeName + ";");
+            }
+        }
+    }
+
+    private static ImmutableMap<String, Class> getPrimitiveTypes() {
+        ImmutableMap.Builder<String, Class> builder = new ImmutableMap.Builder<>();
+        for (Class type : Primitives.allPrimitiveTypes()) {
+            builder.put(type.getName(), type);
+        }
+        return builder.build();
+    }
+
+    private static boolean isPrimitiveTypeName(String typeName) {
+        return PRIMITIVE_TYPES.containsKey(typeName);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelperTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelperTest.java
new file mode 100644
index 0000000..c858677
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CurrentApiHelperTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.managedprofile;
+
+import static com.android.cts.managedprofile.CurrentApiHelper.getPublicApis;
+import static com.android.cts.managedprofile.CurrentApiHelper.instantiate;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.test.AndroidTestCase;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests for {@link CurrentApiHelper}.
+ */
+public class CurrentApiHelperTest extends AndroidTestCase {
+
+    private Class<DevicePolicyManager> mClazz;
+    private Set<Method> mPublicApis;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mClazz = DevicePolicyManager.class;
+        String testPackage = mClazz.getPackage().getName();
+        String testClass = mClazz.getSimpleName();
+        mPublicApis = new HashSet<>(getPublicApis(testPackage, testClass));
+        assertTrue(mPublicApis.size() > 0);
+    }
+
+    /**
+     * Test: {@link CurrentApiHelper#getPublicApis} includes public API methods.
+     */
+    public void testGetPublicApisIncludeMethods() throws Exception {
+        Method publicMethod = mClazz.getMethod("lockNow");
+        assertTrue(mPublicApis.contains(publicMethod));
+        publicMethod = mClazz.getMethod("isProfileOwnerApp", String.class);
+        assertTrue(mPublicApis.contains(publicMethod));
+        publicMethod = mClazz.getMethod("resetPassword", String.class, int.class);
+        assertTrue(mPublicApis.contains(publicMethod));
+        publicMethod = mClazz.getMethod("hasGrantedPolicy", ComponentName.class, int.class);
+        assertTrue(mPublicApis.contains(publicMethod));
+        publicMethod = mClazz.getMethod("installCaCert", ComponentName.class, Class.forName("[B"));
+        assertTrue(mPublicApis.contains(publicMethod));
+    }
+
+    /**
+     * Test: {@link CurrentApiHelper#getPublicApis} excludes private, hidden or {@code @SystemApi}
+     * methods.
+     */
+    public void testGetPublicApisExcludeMethods() throws Exception {
+        Method privateMethod = mClazz.getDeclaredMethod("throwIfParentInstance", String.class);
+        assertFalse(mPublicApis.contains(privateMethod));
+        Method hiddenMethod = mClazz.getMethod("isDeviceProvisioned");
+        assertFalse(mPublicApis.contains(hiddenMethod));
+        Method systemMethod = mClazz.getMethod("getProfileOwnerNameAsUser", int.class);
+        assertFalse(mPublicApis.contains(systemMethod));
+    }
+
+    /** Test for {@link CurrentApiHelper#instantiate}. */
+    public void testInstantiate() {
+        assertEquals(false, instantiate(boolean.class));
+        assertEquals(0, instantiate(byte.class));
+        assertEquals(0, instantiate(char.class));
+        assertEquals(0, instantiate(double.class));
+        assertEquals(0, instantiate(float.class));
+        assertEquals(0, instantiate(int.class));
+        assertEquals(0, instantiate(long.class));
+        assertEquals(0, instantiate(short.class));
+        assertNull(instantiate(String.class));
+        assertNull(instantiate(Integer.class));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
new file mode 100644
index 0000000..0ac50d5
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.app.admin.DevicePolicyManager;
+import android.util.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Tests related to the parent profile of a managed profile.
+ *
+ * The parent profile is obtained by
+ * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
+ */
+public class ParentProfileTest extends BaseManagedProfileTest {
+
+    /**
+     * A whitelist of public API methods in {@link android.app.admin.DevicePolicyManager}
+     * that are supported on a parent profile.
+     */
+    public static final ImmutableSet<String> SUPPORTED_APIS = new ImmutableSet.Builder<String>()
+            .add("getPasswordQuality")
+            .add("setPasswordQuality")
+            .add("getPasswordMinimumLength")
+            .add("setPasswordMinimumLength")
+            .add("getPasswordMinimumUpperCase")
+            .add("setPasswordMinimumUpperCase")
+            .add("getPasswordMinimumLowerCase")
+            .add("setPasswordMinimumLowerCase")
+            .add("getPasswordMinimumLetters")
+            .add("setPasswordMinimumLetters")
+            .add("getPasswordMinimumNumeric")
+            .add("setPasswordMinimumNumeric")
+            .add("getPasswordMinimumSymbols")
+            .add("setPasswordMinimumSymbols")
+            .add("getPasswordMinimumNonLetter")
+            .add("setPasswordMinimumNonLetter")
+            .add("getPasswordHistoryLength")
+            .add("setPasswordHistoryLength")
+            .add("getPasswordExpirationTimeout")
+            .add("setPasswordExpirationTimeout")
+            .add("getPasswordExpiration")
+            .add("getPasswordMaximumLength")
+            .add("isActivePasswordSufficient")
+            .add("getCurrentFailedPasswordAttempts")
+            .add("getMaximumFailedPasswordsForWipe")
+            .add("setMaximumFailedPasswordsForWipe")
+            .add("getMaximumTimeToLock")
+            .add("setMaximumTimeToLock")
+            .add("lockNow")
+            .add("getKeyguardDisabledFeatures")
+            .add("setKeyguardDisabledFeatures")
+            .add("getTrustAgentConfiguration")
+            .add("setTrustAgentConfiguration")
+            .add("getRequiredStrongAuthTimeout")
+            .add("setRequiredStrongAuthTimeout")
+            .build();
+
+    private static final String LOG_TAG = "ParentProfileTest";
+
+    private static final String PACKAGE_NAME = DevicePolicyManager.class.getPackage().getName();
+    private static final String CLASS_NAME = DevicePolicyManager.class.getSimpleName();
+
+    /**
+     * Verify that all public API methods of {@link android.app.admin.DevicePolicyManager},
+     * except those explicitly whitelisted in {@link #SUPPORTED_APIS},
+     * throw a {@link SecurityException} when called on a parent profile.
+     *
+     * <p><b>Note:</b> System API methods (i.e. those with the
+     * {@link android.annotation.SystemApi} annotation) are NOT tested.
+     */
+    public void testParentProfileApiDisabled() throws Exception {
+        List<Method> methods = CurrentApiHelper.getPublicApis(PACKAGE_NAME, CLASS_NAME);
+        assertValidMethodNames(SUPPORTED_APIS, methods);
+
+        boolean failed = false;
+
+        for (Method method : methods) {
+            String methodName = method.getName();
+            if (SUPPORTED_APIS.contains(methodName)) {
+                continue;
+            }
+
+            try {
+                int paramCount = method.getParameterCount();
+                Object[] params = new Object[paramCount];
+                Class[] paramTypes = method.getParameterTypes();
+                for (int i = 0; i < paramCount; ++i) {
+                    params[i] = CurrentApiHelper.instantiate(paramTypes[i]);
+                }
+                method.invoke(mParentDevicePolicyManager, params);
+
+            } catch (InvocationTargetException e) {
+                if (e.getCause() instanceof SecurityException) {
+                    // Method throws SecurityException as expected
+                    continue;
+                } else {
+                    Log.e(LOG_TAG, e.getMessage(), e);
+                }
+            }
+
+            // Either no exception is thrown, or the exception thrown is not a SecurityException
+            failed = true;
+            Log.e(LOG_TAG, methodName + " failed to throw SecurityException");
+        }
+
+        assertFalse("Some method(s) failed to throw SecurityException", failed);
+    }
+
+    private void assertValidMethodNames(Collection<String> names, Collection<Method> allMethods) {
+        Set<String> allNames = allMethods.stream()
+                .map(Method::getName)
+                .collect(Collectors.toSet());
+
+        for (String name : names) {
+            assertTrue(name + " is not found in the API list", allNames.contains(name));
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
index 47f8716..e092888 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserAdminHelper.java
@@ -46,6 +46,6 @@
                 Thread.sleep(1000);  // 1 second.
             }
         }
-        assertFalse(mDpm.isAdminActive(cn));
+        assertFalse("Clear device admin failed", mDpm.isAdminActive(cn));
     }
 }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/RingtoneSyncTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/RingtoneSyncTest.java
new file mode 100644
index 0000000..336a0c2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/RingtoneSyncTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.managedprofile;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.provider.Settings;
+
+/**
+ * Tests that managed profile ringtones work, as well as the "sync from parent profile" feature
+ */
+public class RingtoneSyncTest extends BaseManagedProfileTest {
+
+    private ContentResolver mContentResolver;
+
+    private static final int[] RINGTONE_TYPES = {
+            RingtoneManager.TYPE_RINGTONE, RingtoneManager.TYPE_NOTIFICATION,
+            RingtoneManager.TYPE_ALARM
+    };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContentResolver = mContext.getContentResolver();
+    }
+
+    /**
+     * Checks that the ringtone set in the settings provider and the ringtone retrieved from
+     * RingtoneManager are identical.
+     *
+     * Used to test that the ringtone sync setting is enabled by default, and that managed profile
+     * ringtones are kept in sync with parent profile ringtones, despite the setting being kept in
+     * another user from the caller.
+     */
+    public void testRingtoneSync() throws Exception {
+        final String SETTING_SYNC_PARENT_SOUNDS = "sync_parent_sounds";
+
+        // Managed profile was just created, so sync should be active by default
+        assertEquals(1, Settings.Secure.getInt(mContentResolver, SETTING_SYNC_PARENT_SOUNDS));
+
+        String defaultRingtone = Settings.System.getString(mContentResolver,
+                Settings.System.RINGTONE);
+        String defaultNotification = Settings.System.getString(mContentResolver,
+                Settings.System.NOTIFICATION_SOUND);
+        String defaultAlarm = Settings.System.getString(mContentResolver,
+                Settings.System.ALARM_ALERT);
+
+        // RingtoneManager API should retrieve the same ringtones
+        validateRingtoneManagerGetRingtone(defaultRingtone, RingtoneManager.TYPE_RINGTONE);
+        validateRingtoneManagerGetRingtone(defaultNotification, RingtoneManager.TYPE_NOTIFICATION);
+        validateRingtoneManagerGetRingtone(defaultAlarm, RingtoneManager.TYPE_ALARM);
+    }
+
+    private void validateRingtoneManagerGetRingtone(String actualRingtone, int type) {
+        Uri ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(mContext, type);
+        if (ringtoneUri == null) {
+            assertNull(actualRingtone);
+        } else {
+            assertEquals(ringtoneUri.toString(), actualRingtone);
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
index 685ad82..124ebe8 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
@@ -23,6 +23,7 @@
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
 
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import static com.android.compatibility.common.util.WifiConfigCreator.ACTION_CREATE_WIFI_CONFIG;
@@ -50,10 +51,27 @@
     // Shared WifiManager instance.
     private WifiManager mWifiManager;
 
+    // Original setting of WifiManager.isWifiEnabled() before setup.
+    private boolean mWifiEnabled;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        mWifiEnabled = mWifiManager.isWifiEnabled();
+        if (!mWifiEnabled) {
+            mWifiManager.setWifiEnabled(true);
+            awaitWifiEnabledState(true);
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (!mWifiEnabled) {
+            mWifiManager.setWifiEnabled(false);
+            awaitWifiEnabledState(false);
+        }
+        super.tearDown();
     }
 
     /**
@@ -92,7 +110,6 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             getContext().startActivity(intent);
         }
-
         assertTrue(awaitNetworkState(NETWORK_SSID, /* exists */ false));
     }
 
@@ -123,6 +140,23 @@
     }
 
     /**
+     * Block until {@link WifiManager#isWifiEnabled()} returns {@param enabled}. Wait for up to
+     * {@link WifiTest#UPDATE_TIMEOUT_MS} milliseconds, in increments of
+     * {@link WifiTest#UPDATE_INTERVAL_MS}.
+     */
+    private void awaitWifiEnabledState(boolean enabled) throws RuntimeException {
+        for (int probes = 0; probes * UPDATE_INTERVAL_MS <= UPDATE_TIMEOUT_MS; probes++) {
+            if (probes != 0) {
+                SystemClock.sleep(UPDATE_INTERVAL_MS);
+            }
+            if (mWifiManager.isWifiEnabled() == enabled) {
+                return;
+            }
+        }
+        throw new RuntimeException("Waited too long for wifi enabled state = " + enabled);
+    }
+
+    /**
      * Internal method to find an existing {@link WifiConfiguration} with the given SSID.
      *
      * @return A {@link WifiConfiguration} matching the specification, or {@code null} if no such
@@ -132,9 +166,12 @@
         if (!ssid.startsWith("\"")) {
             ssid = '"' + ssid + '"';
         }
-        for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
-            if (ssid.equals(config.SSID)) {
-                return config;
+        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        if (configs != null) {
+            for (WifiConfiguration config : configs) {
+                if (ssid.equals(config.SSID)) {
+                    return config;
+                }
             }
         }
         return null;
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
index 9646e61..7ef3a0a 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WipeDataTest.java
@@ -15,12 +15,6 @@
  */
 package com.android.cts.managedprofile;
 
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
 
 import com.android.cts.managedprofile.BaseManagedProfileTest.BasicAdminReceiver;
 
@@ -32,8 +26,6 @@
  */
 public class WipeDataTest extends BaseManagedProfileTest {
 
-    private UserManager mUserManager;
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -41,27 +33,10 @@
         // data.
         assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
         assertTrue(mDevicePolicyManager.isProfileOwnerApp(ADMIN_RECEIVER_COMPONENT.getPackageName()));
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
     }
 
     public void testWipeData() throws InterruptedException {
-        UserHandle currentUser = Process.myUserHandle();
-        assertTrue(mUserManager.getUserProfiles().contains(currentUser));
-
         mDevicePolicyManager.wipeData(0);
-
-        // ACTION_MANAGED_PROFILE_REMOVED is only sent to parent user.
-        // As a result, we have to poll in order to know when the profile
-        // is actually removed.
-        long epoch = System.currentTimeMillis();
-        while (System.currentTimeMillis() - epoch <= 10 * 1000) {
-            if (!mUserManager.getUserProfiles().contains(currentUser)) {
-                break;
-            }
-            Thread.sleep(250);
-        }
-
-        // Verify the profile is deleted
-        assertFalse(mUserManager.getUserProfiles().contains(currentUser));
+        // the test that the profile will indeed be removed is done in the host.
     }
 }
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
index 791ae56..d7eaf92 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
@@ -45,6 +45,8 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <service android:name=".SimpleService" android:exported="true">
+        </service>
     </application>
 
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService.java
new file mode 100644
index 0000000..107261c
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleService.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 com.android.cts.launcherapps.simpleapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.RemoteException;
+
+public class SimpleService extends Service {
+    final Binder mBinder = new Binder() {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            switch (code) {
+                case FIRST_CALL_TRANSACTION:
+                    Process.killProcess(Process.myPid());
+                    return true;
+            }
+            return super.onTransact(code, data, reply, flags);
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
index 3d2c2ff..7a5dee3 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
+++ b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.vpnfirewall;
 
+import android.R;
+import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -33,6 +35,7 @@
 public class ReflectorVpnService extends VpnService {
 
     private static String TAG = "ReflectorVpnService";
+    private static final int NOTIFICATION_ID = 1;
     private static int MTU = 1799;
 
     private ParcelFileDescriptor mFd = null;
@@ -45,8 +48,13 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        // Put ourself in the foreground to stop the system killing us while we wait for orders from
+        // the hostside test.
+        startForeground(NOTIFICATION_ID, new Notification.Builder(this)
+                .setSmallIcon(R.drawable.ic_dialog_alert)
+                .build());
         start();
-        return START_NOT_STICKY;
+        return START_REDELIVER_INTENT;
     }
 
     @Override
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
index 93e8503..6541146 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AccountCheckHostSideTest.java
@@ -63,7 +63,7 @@
     }
 
     private void runTest(String method) throws Exception {
-        assertTrue(runDeviceTests(PACKAGE_AUTH, TEST_CLASS, method));
+        runDeviceTests(PACKAGE_AUTH, TEST_CLASS, method);
     }
 
     private void runCleanupTestOnlyOwner() throws Exception {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceAdminHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceAdminHostSideTest.java
index 9262894e..c5e022b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceAdminHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDeviceAdminHostSideTest.java
@@ -93,15 +93,15 @@
         super.tearDown();
     }
 
-    protected boolean runTests(@Nonnull String apk, @Nonnull String className,
+    protected void runTests(@Nonnull String apk, @Nonnull String className,
             @Nullable String method) throws DeviceNotAvailableException {
-        return runDeviceTestsAsUser(apk,
+        runDeviceTestsAsUser(apk,
                 getDeviceAdminJavaPackage() + "." + className, method, mUserId);
     }
 
-    protected boolean runTests(@Nonnull String apk, @Nonnull String className)
+    protected void runTests(@Nonnull String apk, @Nonnull String className)
             throws DeviceNotAvailableException {
-        return runTests(apk, className, null);
+        runTests(apk, className, null);
     }
 
     /**
@@ -111,14 +111,11 @@
         if (!mHasFeature) {
             return;
         }
-
-        assertTrue("Some of device side tests failed",
-                runTests(getDeviceAdminApkPackage(), "DeviceAdminTest"));
+        runTests(getDeviceAdminApkPackage(), "DeviceAdminTest");
     }
 
     private void clearPasswordForDeviceOwner() throws Exception {
-        assertTrue("Failed to clear password",
-                runTests(getDeviceAdminApkPackage(), "ClearPasswordTest"));
+        runTests(getDeviceAdminApkPackage(), "ClearPasswordTest");
     }
 
     private void makeDoAndClearPassword() throws Exception {
@@ -142,8 +139,8 @@
         // If there's a password, clear it.
         makeDoAndClearPassword();
         try {
-            assertTrue(runTests(getDeviceAdminApkPackage(), "DeviceAdminPasswordTest",
-                            "testResetPassword_nycRestrictions"));
+            runTests(getDeviceAdminApkPackage(), "DeviceAdminPasswordTest",
+                            "testResetPassword_nycRestrictions");
         } finally {
             makeDoAndClearPassword();
         }
@@ -162,8 +159,7 @@
         clearPasswordForDeviceOwner();
 
         try {
-            assertTrue("Some of device side tests failed",
-                    runTests(getDeviceAdminApkPackage(), "DeviceOwnerPasswordTest"));
+            runTests(getDeviceAdminApkPackage(), "DeviceOwnerPasswordTest");
         } finally {
             clearPasswordForDeviceOwner();
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 2d9b5a1..a195a15 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -35,6 +35,9 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
@@ -54,6 +57,7 @@
     protected static final int FLAG_PRIMARY = 0x00000001;
     protected static final int FLAG_GUEST = 0x00000004;
     protected static final int FLAG_EPHEMERAL = 0x00000100;
+    protected static final int FLAG_MANAGED_PROFILE = 0x00000020;
 
     protected static interface Settings {
         public static final String GLOBAL_NAMESPACE = "global";
@@ -67,6 +71,9 @@
     private String mPackageVerifier;
     private HashSet<String> mAvailableFeatures;
 
+    /** Packages installed as part of the tests */
+    private Set<String> mFixedPackages;
+
     /** Whether DPM is supported. */
     protected boolean mHasFeature;
     protected int mPrimaryUserId;
@@ -74,6 +81,9 @@
     /** Whether multi-user is supported. */
     protected boolean mSupportsMultiUser;
 
+    /** Whether file-based encryption (FBE) is supported. */
+    protected boolean mSupportsFbe;
+
     /** Users we shouldn't delete in the tests */
     private ArrayList<Integer> mFixedUsers;
 
@@ -89,6 +99,8 @@
         mHasFeature = getDevice().getApiLevel() >= 21 /* Build.VERSION_CODES.L */
                 && hasDeviceFeature("android.software.device_admin");
         mSupportsMultiUser = getMaxNumberOfUsersSupported() > 1;
+        mSupportsFbe = hasDeviceFeature("android.software.file_based_encryption");
+        mFixedPackages = getDevice().getInstalledPackageNames();
 
         // disable the package verifier to avoid the dialog when installing an app
         mPackageVerifier = getDevice().executeShellCommand(
@@ -113,6 +125,7 @@
                 + mPackageVerifier);
         removeOwners();
         removeTestUsers();
+        removeTestPackages();
         super.tearDown();
     }
 
@@ -124,9 +137,9 @@
     protected void installAppAsUser(String appFileName, boolean grantPermissions, int userId)
             throws FileNotFoundException, DeviceNotAvailableException {
         CLog.d("Installing app " + appFileName + " for user " + userId);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
         String result = getDevice().installPackageForUser(
-                MigrationHelper.getTestFile(mCtsBuild, appFileName), true, grantPermissions,
-                userId, "-t");
+                buildHelper.getTestFile(appFileName), true, grantPermissions, userId, "-t");
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
@@ -136,7 +149,7 @@
         executeShellCommand("am force-stop --user " + userId + " " + packageName);
     }
 
-    private void executeShellCommand(final String command) throws Exception {
+    protected void executeShellCommand(final String command) throws Exception {
         CLog.d("Starting command " + command);
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.d("Output for command " + command + ": " + commandOutput);
@@ -182,6 +195,16 @@
         return getDevice().listUsers();
     }
 
+    protected int getFirstManagedProfileUserId() throws DeviceNotAvailableException {
+        for (int userId : listUsers()) {
+            if ((getUserFlags(userId) & FLAG_MANAGED_PROFILE) != 0) {
+                return userId;
+            }
+        }
+        fail("Managed profile not found");
+        return 0;
+    }
+
     protected void stopUser(int userId) throws Exception  {
         String stopUserCommand = "am stop-user -w -f " + userId;
         CLog.d("starting command \"" + stopUserCommand + "\" and waiting.");
@@ -208,28 +231,38 @@
         }
     }
 
-    /** Returns true if the specified tests passed. Tests are run as given user. */
-    protected boolean runDeviceTestsAsUser(
-            String pkgName, @Nullable String testClassName, int userId)
-            throws DeviceNotAvailableException {
-        return runDeviceTestsAsUser(pkgName, testClassName, null /*testMethodName*/, userId);
+    /** Removes any packages that were installed during the test. */
+    protected void removeTestPackages() throws Exception {
+        for (String packageName : getDevice().getUninstallablePackageNames()) {
+            if (mFixedPackages.contains(packageName)) {
+                continue;
+            }
+            CLog.w("removing leftover package: " + packageName);
+            getDevice().uninstallPackage(packageName);
+        }
     }
 
-    /** Returns true if the specified tests passed. Tests are run as given user. */
-    protected boolean runDeviceTestsAsUser(
+    protected void runDeviceTestsAsUser(
+            String pkgName, @Nullable String testClassName, int userId)
+            throws DeviceNotAvailableException {
+        runDeviceTestsAsUser(pkgName, testClassName, null /*testMethodName*/, userId);
+    }
+
+    protected void runDeviceTestsAsUser(
             String pkgName, @Nullable String testClassName, String testMethodName, int userId)
             throws DeviceNotAvailableException {
         Map<String, String> params = Collections.emptyMap();
-        return runDeviceTestsAsUser(pkgName, testClassName, testMethodName, userId, params);
+        runDeviceTestsAsUser(pkgName, testClassName, testMethodName, userId, params);
     }
 
-    protected boolean runDeviceTests(
+    protected void runDeviceTests(
             String pkgName, @Nullable String testClassName, String testMethodName)
             throws DeviceNotAvailableException {
-        return runDeviceTestsAsUser(pkgName, testClassName, testMethodName, mPrimaryUserId);
+        runDeviceTestsAsUser(pkgName, testClassName, testMethodName, mPrimaryUserId);
     }
 
-    protected boolean runDeviceTestsAsUser(String pkgName, @Nullable String testClassName,
+    protected void runDeviceTestsAsUser(
+            String pkgName, @Nullable String testClassName,
             @Nullable String testMethodName, int userId,
             Map<String, String> params) throws DeviceNotAvailableException {
         if (testClassName != null && testClassName.startsWith(".")) {
@@ -251,9 +284,28 @@
         CollectingTestListener listener = new CollectingTestListener();
         assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
 
-        TestRunResult runResult = listener.getCurrentRunResults();
-        printTestResult(runResult);
-        return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new AssertionError("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+        if (result.getNumTests() == 0) {
+            throw new AssertionError("No tests were run on the device");
+        }
+
+        if (result.hasFailedTests()) {
+            // build a meaningful error message
+            StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
+            for (Map.Entry<TestIdentifier, TestResult> resultEntry :
+                    result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
     }
 
     /** Reboots the device and block until the boot complete flag is set. */
@@ -292,17 +344,6 @@
         return listUsers().size() + numberOfUsers <= getMaxNumberOfUsersSupported();
     }
 
-    private void printTestResult(TestRunResult runResult) {
-        for (Map.Entry<TestIdentifier, TestResult> testEntry :
-                runResult.getTestResults().entrySet()) {
-            TestResult testResult = testEntry.getValue();
-            CLog.d("Test " + testEntry.getKey() + ": " + testResult.getStatus());
-            if (testResult.getStatus() != TestStatus.PASSED) {
-                CLog.d(testResult.getStackTrace());
-            }
-        }
-    }
-
     protected boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
         if (mAvailableFeatures == null) {
             // TODO: Move this logic to ITestDevice.
@@ -535,4 +576,26 @@
             }
         }
     }
+
+    /**
+     * Runs pm enable command to enable a package or component. Returns the command result.
+     */
+    protected String enableComponentOrPackage(int userId, String packageOrComponent)
+            throws DeviceNotAvailableException {
+        String command = "pm enable --user " + userId + " " + packageOrComponent;
+        String result = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + result);
+        return result;
+    }
+
+    /**
+     * Runs pm disable command to disable a package or component. Returns the command result.
+     */
+    protected String disableComponentOrPackage(int userId, String packageOrComponent)
+            throws DeviceNotAvailableException {
+        String command = "pm disable --user " + userId + " " + packageOrComponent;
+        String result = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + result);
+        return result;
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index c361531..bb1811f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,8 +16,8 @@
 
 package com.android.cts.devicepolicy;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.cts.devicepolicy.BaseDevicePolicyTest.Settings;
-import com.android.cts.migration.MigrationHelper;
 
 import java.io.File;
 import java.lang.Exception;
@@ -77,8 +77,8 @@
 
             // Running this test also gets the intent receiver app out of the stopped state, so it
             // can receive broadcast intents.
-            assertTrue(runDeviceTestsAsUser(INTENT_RECEIVER_PKG, testClass,
-                    "testOwnerChangedBroadcastNotReceived", mPrimaryUserId));
+            runDeviceTestsAsUser(INTENT_RECEIVER_PKG, testClass,
+                    "testOwnerChangedBroadcastNotReceived", mPrimaryUserId);
 
             // Setting the device owner should send the owner changed broadcast.
             assertTrue(setDeviceOwner(DEVICE_OWNER_ADMIN_COMPONENT, mPrimaryUserId,
@@ -86,8 +86,8 @@
 
             // Waiting for the broadcast idle state.
             Thread.sleep(BROADCAST_WAIT_TIME_MILLIS);
-            assertTrue(runDeviceTestsAsUser(INTENT_RECEIVER_PKG, testClass,
-                    "testOwnerChangedBroadcastReceived", mPrimaryUserId));
+            runDeviceTestsAsUser(INTENT_RECEIVER_PKG, testClass,
+                    "testOwnerChangedBroadcastReceived", mPrimaryUserId);
         } finally {
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
             assertTrue("Failed to remove device owner.",
@@ -119,15 +119,15 @@
         installAppAsUser(ACCOUNT_MANAGEMENT_APK, mPrimaryUserId);
         installAppAsUser(DEVICE_OWNER_APK, mPrimaryUserId);
         try {
-            assertTrue(runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountUtilsTest",
-                    "testAddAccountExplicitly", mPrimaryUserId));
+            runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountUtilsTest",
+                    "testAddAccountExplicitly", mPrimaryUserId);
             assertFalse(setDeviceOwner(DEVICE_OWNER_ADMIN_COMPONENT, mPrimaryUserId,
                     /*expectFailure*/ true));
         } finally {
             // make sure we clean up in case we succeeded in setting the device owner
             removeAdmin(DEVICE_OWNER_ADMIN_COMPONENT, mPrimaryUserId);
-            assertTrue(runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountUtilsTest",
-                    "testRemoveAccountExplicitly", mPrimaryUserId));
+            runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountUtilsTest",
+                    "testRemoveAccountExplicitly", mPrimaryUserId);
         }
     }
 
@@ -135,7 +135,8 @@
         if (!mHasFeature) {
             return;
         }
-        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File apk = buildHelper.getTestFile(TEST_APP_APK);
         try {
             // Install the test and prepare the test apk.
             installAppAsUser(PACKAGE_INSTALLER_APK, mPrimaryUserId);
@@ -144,8 +145,8 @@
 
             getDevice().uninstallPackage(TEST_APP_PKG);
             assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
-            assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG,
-                    PACKAGE_INSTALLER_PKG + ".SilentPackageInstallTest", mPrimaryUserId));
+            runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG,
+                    PACKAGE_INSTALLER_PKG + ".SilentPackageInstallTest", mPrimaryUserId);
         } finally {
             assertTrue("Failed to remove device owner.",
                     removeAdmin(PACKAGE_INSTALLER_ADMIN_COMPONENT, mPrimaryUserId));
@@ -163,8 +164,8 @@
             // When CTS runs, setupwizard is complete. Expects it has to return false as DO can
             // only be provisioned before setupwizard is completed.
 
-            assertTrue(runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".PreDeviceOwnerTest",
-                    "testIsProvisioningAllowedFalse", /* deviceOwnerUserId */ 0));
+            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".PreDeviceOwnerTest",
+                    "testIsProvisioningAllowedFalse", /* deviceOwnerUserId */ 0);
         } finally {
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java
index 53e9138..51420ea 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomManagedProfileTest.java
@@ -52,7 +52,6 @@
             throws DeviceNotAvailableException {
         final String testName = expected ? "testIsProvisioningAllowedTrue"
                 : "testIsProvisioningAllowedFalse";
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest", testName,
-                userId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest", testName, userId);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi23.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi23.java
index 862a933..3a74953 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi23.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminHostSideTestApi23.java
@@ -36,8 +36,7 @@
         try {
             setDeviceAdmin(getUnprotectedAdminReceiverComponent(), mUserId);
         } finally {
-            assertTrue("Failed to remove device admin", runTests(
-                    getDeviceAdminApkPackage(), "ClearDeviceAdminWithNoProtectionTest"));
+            runTests(getDeviceAdminApkPackage(), "ClearDeviceAdminWithNoProtectionTest");
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index a3d104f..036bf40 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -16,13 +16,17 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.cts.migration.MigrationHelper;
-import com.android.ddmlib.Log.LogLevel;
+import android.platform.test.annotations.RequiresDevice;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Set of tests for use cases that apply to profile and device owner.
@@ -39,6 +43,9 @@
     protected static final String ADMIN_RECEIVER_TEST_CLASS
             = ".BaseDeviceAdminTest$BasicAdminReceiver";
 
+    protected static final String RESET_PASSWORD_TEST_CLASS = ".ResetPasswordTest";
+    protected static final String FBE_HELPER_CLASS = ".FbeHelper";
+
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
@@ -82,12 +89,16 @@
     private static final String COMMAND_UNBLOCK_ACCOUNT_TYPE = "unblock-accounttype";
 
     private static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    private static final String DISALLOW_REMOVE_USER = "no_remove_user";
     private static final String ACCOUNT_TYPE
             = "com.android.cts.devicepolicy.accountmanagement.account.type";
 
     private static final String CUSTOMIZATION_APP_PKG = "com.android.cts.customizationapp";
     private static final String CUSTOMIZATION_APP_APK = "CtsCustomizationApp.apk";
 
+    private static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES
+            = "enabled_notification_policy_access_packages";
+
     // ID of the user all tests are run as. For device owner this will be the primary user, for
     // profile owner it is the user id of the created profile.
     protected int mUserId;
@@ -114,11 +125,35 @@
         super.tearDown();
     }
 
+    public void testCaCertManagement() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        executeDeviceTestClass(".CaCertManagementTest");
+    }
+
+    /** Test for resetPassword for all devices. */
     public void testResetPassword() throws Exception {
         if (!mHasFeature) {
             return;
         }
-        executeDeviceTestClass(".ResetPasswordTest");
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPassword");
+    }
+
+    /** Additional test for resetPassword for FBE-enabled devices. */
+    public void testResetPasswordFbe() throws Exception {
+        if (!mHasFeature || !mSupportsFbe) {
+            return;
+        }
+
+        // Lock FBE and verify resetPassword is disabled
+        executeDeviceTestMethod(FBE_HELPER_CLASS, "testSetPassword");
+        rebootAndWaitUntilReady();
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPasswordDisabled");
+
+        // Unlock FBE and verify resetPassword is enabled again
+        executeDeviceTestMethod(FBE_HELPER_CLASS, "testUnlockFbe");
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPassword");
     }
 
     public void testApplicationRestrictions() throws Exception {
@@ -147,9 +182,9 @@
             if (parentUserId != mUserId) {
                 installAppAsUser(APP_RESTRICTIONS_MANAGING_APP_APK, parentUserId);
                 installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, parentUserId);
-                assertTrue(runDeviceTestsAsUser(
+                runDeviceTestsAsUser(
                         APP_RESTRICTIONS_MANAGING_APP_PKG, ".ApplicationRestrictionsManagerTest",
-                        "testCannotManageAppRestrictions", parentUserId));
+                        "testCannotManageAppRestrictions", parentUserId);
             }
 
             // Revoking the permission for APP_RESTRICTIONS_MANAGING_APP_PKG to manage restrictions.
@@ -179,6 +214,7 @@
         executeDeviceTestClass(".AlwaysOnVpnTest");
     }
 
+    @RequiresDevice
     public void testAlwaysOnVpnLockDown() throws Exception {
         if (!mHasFeature) {
             return;
@@ -194,6 +230,7 @@
         }
     }
 
+    @RequiresDevice
     public void testAlwaysOnVpnPackageUninstalled() throws Exception {
         if (!mHasFeature) {
             return;
@@ -400,15 +437,14 @@
         try {
             // Set a non-empty device lockscreen password, which is a precondition for installing
             // private key pairs.
-            assertTrue("Set lockscreen password failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                    ".ResetPasswordHelper", "testSetPassword", mUserId));
-            assertTrue("DelegatedCertInstaller failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                    ".DelegatedCertInstallerTest", mUserId));
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ResetPasswordHelper", "testSetPassword",
+                    mUserId);
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DelegatedCertInstallerTest", mUserId);
         } finally {
             if (!isManagedProfile) {
                 // Skip managed profile as dpm doesn't allow clear password
-                assertTrue("Clear lockscreen password failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                        ".ResetPasswordHelper", "testClearPassword", mUserId));
+                runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
+                        ".ResetPasswordHelper", "testClearPassword", mUserId);
             }
         }
     }
@@ -426,8 +462,8 @@
         try {
             changeUserRestrictionForUser(DISALLOW_SET_WALLPAPER, COMMAND_ADD_USER_RESTRICTION,
                     mUserId);
-            assertTrue(runDeviceTestsAsUser(CUSTOMIZATION_APP_PKG, ".CustomizationTest",
-                "testSetWallpaper_disallowed", mUserId));
+            runDeviceTestsAsUser(CUSTOMIZATION_APP_PKG, ".CustomizationTest",
+                "testSetWallpaper_disallowed", mUserId);
         } finally {
             changeUserRestrictionForUser(DISALLOW_SET_WALLPAPER, COMMAND_CLEAR_USER_RESTRICTION,
                     mUserId);
@@ -467,7 +503,8 @@
         final String PACKAGE_VERIFIER_ENABLE_SETTING = "package_verifier_enable";
         final String SECURE_SETTING_CATEGORY = "secure";
         final String GLOBAL_SETTING_CATEGORY = "global";
-        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File apk = buildHelper.getTestFile(TEST_APP_APK);
         String unknownSourceSetting = null;
         String packageVerifierEnableSetting = null;
         String packageVerifierUserConsentSetting = null;
@@ -480,8 +517,8 @@
             getDevice().uninstallPackage(TEST_APP_PKG);
             changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
                     COMMAND_ADD_USER_RESTRICTION, mUserId);
-            assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
-                    "testManualInstallBlocked", mUserId));
+            runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+                    "testManualInstallBlocked", mUserId);
 
             // Clear restrictions and test if we can install the apk.
             changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
@@ -500,8 +537,8 @@
                     mUserId);
             putSettings(GLOBAL_SETTING_CATEGORY, PACKAGE_VERIFIER_ENABLE_SETTING, "0", mUserId);
             // Skip verifying above setting values as some of them may be overrided.
-            assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
-                    "testManualInstallSucceeded", mUserId));
+            runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+                    "testManualInstallSucceeded", mUserId);
         } finally {
             String command = "rm " + TEST_APP_LOCATION + apk.getName();
             getDevice().executeShellCommand(command);
@@ -526,7 +563,13 @@
         if (!mHasFeature) {
             return;
         }
-        executeDeviceTestClass(".AudioRestrictionTest");
+        // This package may need to toggle zen mode for this test, so allow it to do so.
+        allowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+        try {
+            executeDeviceTestClass(".AudioRestrictionTest");
+        } finally {
+            disallowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+        }
     }
 
     public void testSuspendPackage() throws Exception {
@@ -554,12 +597,54 @@
         executeDeviceTestClass(".TrustAgentInfoTest");
     }
 
+    public void testCannotRemoveUserIfRestrictionSet() throws Exception {
+        // Outside of the primary user, setting DISALLOW_REMOVE_USER would not work.
+        if (!mHasFeature || !canCreateAdditionalUsers(1) || mUserId != getPrimaryUser()) {
+            return;
+        }
+        final int userId = createUser();
+        try {
+            changeUserRestrictionForUser(DISALLOW_REMOVE_USER, COMMAND_ADD_USER_RESTRICTION,
+                    mUserId);
+            assertFalse(getDevice().removeUser(userId));
+        } finally {
+            changeUserRestrictionForUser(DISALLOW_REMOVE_USER, COMMAND_CLEAR_USER_RESTRICTION,
+                    mUserId);
+            assertTrue(getDevice().removeUser(userId));
+        }
+    }
+
+    public void testCannotEnableOrDisableDeviceOwnerOrProfileOwner() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        // Try to disable a component in device owner/ profile owner.
+        String result = disableComponentOrPackage(
+                mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to disable the device owner/ profile owner package.
+        result = disableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to enable a component in device owner/ profile owner.
+        result = enableComponentOrPackage(
+                mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to enable the device owner/ profile owner package.
+        result = enableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+
+    }
+
     protected void executeDeviceTestClass(String className) throws Exception {
-        assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId));
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
     }
 
     protected void executeDeviceTestMethod(String className, String testName) throws Exception {
-        assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, testName, mUserId));
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, testName, mUserId);
     }
 
     private void installAppPermissionAppAsUser()
@@ -568,13 +653,13 @@
     }
 
     private void executeSuspendPackageTestMethod(String testName) throws Exception {
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".SuspendPackageTest",
-                testName, mUserId));
+        runDeviceTestsAsUser(INTENT_SENDER_PKG, ".SuspendPackageTest",
+                testName, mUserId);
     }
 
     private void executeAccountTest(String testName) throws DeviceNotAvailableException {
-        assertTrue(runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountManagementTest",
-                testName, mUserId));
+        runDeviceTestsAsUser(ACCOUNT_MANAGEMENT_PKG, ".AccountManagementTest",
+                testName, mUserId);
         // Send a home intent to dismiss an error dialog.
         String command = "am start -a android.intent.action.MAIN"
                 + " -c android.intent.category.HOME";
@@ -582,8 +667,8 @@
     }
 
     private void executeAppRestrictionsManagingPackageTest(String testName) throws Exception {
-        assertTrue(runDeviceTestsAsUser(APP_RESTRICTIONS_MANAGING_APP_PKG,
-                ".ApplicationRestrictionsManagerTest", testName, mUserId));
+        runDeviceTestsAsUser(APP_RESTRICTIONS_MANAGING_APP_PKG,
+                ".ApplicationRestrictionsManagerTest", testName, mUserId);
     }
 
     private void changeUserRestrictionForUser(String key, String command, int userId)
@@ -619,7 +704,7 @@
     /**
      * Start SimpleActivity synchronously in a particular user.
      */
-    protected void startScreenCaptureDisabledActivity(int userId) throws Exception {
+    protected void startSimpleActivityAsUser(int userId) throws Exception {
         installAppAsUser(TEST_APP_APK, userId);
         String command = "am start -W --user " + userId + " " + TEST_APP_PKG + "/"
                 + TEST_APP_PKG + ".SimpleActivity";
@@ -640,7 +725,7 @@
                 ? "testSetScreenCaptureDisabled_true"
                 : "testSetScreenCaptureDisabled_false";
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", testMethodName);
-        startScreenCaptureDisabledActivity(userId);
+        startSimpleActivityAsUser(userId);
         // [b/28995242], dump windows to make sure the top window is
         // ScreenCaptureDisabledActivity.
         runDumpsysWindow();
@@ -649,4 +734,46 @@
                 : "testScreenCapturePossible";
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", testMethodName);
     }
+
+    /**
+     * Allows packageName to manage notification policy configuration, which
+     * includes toggling zen mode.
+     */
+    private void allowNotificationPolicyAccess(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+        if (!enabledPackages.contains(packageName)) {
+            enabledPackages.add(packageName);
+            setEnabledNotificationPolicyPackages(enabledPackages, userId);
+        }
+    }
+
+    /**
+     * Disallows packageName to manage notification policy configuration, which
+     * includes toggling zen mode.
+     */
+    private void disallowNotificationPolicyAccess(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+        if (enabledPackages.contains(packageName)) {
+            enabledPackages.remove(packageName);
+            setEnabledNotificationPolicyPackages(enabledPackages, userId);
+        }
+    }
+
+    private void setEnabledNotificationPolicyPackages(List<String> packages, int userId)
+            throws DeviceNotAvailableException {
+        getDevice().setSetting(userId, "secure", ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+                String.join(":", packages));
+    }
+
+    private List<String> getEnabledNotificationPolicyPackages(int userId)
+            throws DeviceNotAvailableException {
+        String settingValue = getDevice().getSetting(userId, "secure",
+                ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+        if (settingValue == null) {
+            return new ArrayList<String>();
+        }
+        return new ArrayList<String>(Arrays.asList(settingValue.split(":|\n")));
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
new file mode 100644
index 0000000..45a9bab
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.devicepolicy;
+
+/**
+ * Tests for having both device owner and profile owner. Device owner is setup for you in
+ * {@link #setUp()} and it is always the {@link #COMP_DPC_PKG}. You are required to call
+ * {@link #createManagedProfile(int)} yourself to create managed profile on each test case.
+ */
+public class DeviceOwnerPlusManagedProfileTest extends BaseDevicePolicyTest {
+    private static final String DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST =
+            "com.android.cts.comp.DeviceOwnerBindDeviceAdminServiceTest";
+    private static final String DEVICE_OWNER_PROVISIONING_TEST =
+            "com.android.cts.comp.provisioning.ManagedProfileProvisioningTest";
+    private static final String MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST =
+            "com.android.cts.comp.ManagedProfileBindDeviceAdminServiceTest";
+
+    private int mProfileUserId;
+
+    private static final String COMP_DPC_PKG = "com.android.cts.comp";
+    private static final String COMP_DPC_APK = "CtsCorpOwnedManagedProfile.apk";
+    private static final String COMP_DPC_ADMIN =
+            COMP_DPC_PKG + "/com.android.cts.comp.AdminReceiver";
+    private static final String COMP_DPC_PKG2 = "com.android.cts.comp2";
+    private static final String COMP_DPC_APK2 = "CtsCorpOwnedManagedProfile2.apk";
+    private static final String COMP_DPC_ADMIN2 =
+            COMP_DPC_PKG2 + "/com.android.cts.comp.AdminReceiver";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // We need managed user to be supported in order to create a profile of the user owner.
+        mHasFeature = mHasFeature && hasDeviceFeature("android.software.managed_users");
+        if (mHasFeature) {
+            // Set device owner.
+            installAppAsUser(COMP_DPC_APK, mPrimaryUserId);
+            if (!setDeviceOwner(COMP_DPC_ADMIN, mPrimaryUserId, /*expectFailure*/ false)) {
+                removeAdmin(COMP_DPC_ADMIN, mPrimaryUserId);
+                fail("Failed to set device owner");
+            }
+        }
+    }
+
+    /**
+     * Both device owner and profile are the same package ({@link #COMP_DPC_PKG}).
+     */
+    public void testBindDeviceAdminServiceAsUser_corpOwnedManagedProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        setupManagedProfile(COMP_DPC_APK, COMP_DPC_ADMIN);
+        verifyBindDeviceAdminServiceAsUser();
+    }
+
+    /**
+     * Same as {@link #testBindDeviceAdminServiceAsUser_corpOwnedManagedProfile} except
+     * creating managed profile through ManagedProvisioning like normal flow
+     */
+    public void testBindDeviceAdminServiceAsUser_corpOwnedManagedProfileWithManagedProvisioning()
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        provisionCorpOwnedManagedProfile();
+        verifyBindDeviceAdminServiceAsUser();
+    }
+
+    /**
+     * Device owner is {@link #COMP_DPC_PKG} while profile owner is {@link #COMP_DPC_PKG2}.
+     */
+    public void testBindDeviceAdminServiceAsUser_byodPlusDeviceOwner() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        setupManagedProfile(COMP_DPC_APK2, COMP_DPC_ADMIN2);
+        // Testing device owner -> profile owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+                mPrimaryUserId);
+        // Testing profile owner -> device owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG2,
+                MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+                mProfileUserId);
+    }
+
+    private void verifyBindDeviceAdminServiceAsUser() throws Exception {
+        // Installing a non managing app (neither device owner nor profile owner).
+        installAppAsUser(COMP_DPC_APK2, mPrimaryUserId);
+        installAppAsUser(COMP_DPC_APK2, mProfileUserId);
+
+        // Testing device owner -> profile owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+                mPrimaryUserId);
+        // Testing profile owner -> device owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+                mProfileUserId);
+    }
+
+    protected void setupManagedProfile(String apkName, String adminReceiverClassName)
+            throws Exception {
+        mProfileUserId = createManagedProfile(mPrimaryUserId);
+        installAppAsUser(apkName, mProfileUserId);
+        setProfileOwnerOrFail(adminReceiverClassName, mProfileUserId);
+        startUser(mProfileUserId);
+    }
+
+
+    protected void provisionCorpOwnedManagedProfile()
+            throws Exception {
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                DEVICE_OWNER_PROVISIONING_TEST,
+                "testProvisioningCorpOwnedManagedProfile",
+                mPrimaryUserId);
+        mProfileUserId = getFirstManagedProfileUserId();
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 90d5f9d..e85211f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -51,9 +51,6 @@
      */
     private boolean mHasDisabledEphemeralUserFeature;
 
-    /** CreateAndManageUser is available and an additional user can be created. */
-    private boolean mHasCreateAndManageUserFeature;
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -69,7 +66,6 @@
         mHasEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1) && hasUserSplit();
         mHasDisabledEphemeralUserFeature =
                 mHasFeature && canCreateAdditionalUsers(1) && !hasUserSplit();
-        mHasCreateAndManageUserFeature = mHasFeature && canCreateAdditionalUsers(1);
     }
 
     @Override
@@ -85,10 +81,6 @@
         super.tearDown();
     }
 
-    public void testCaCertManagement() throws Exception {
-        executeDeviceOwnerTest("CaCertManagementTest");
-    }
-
     public void testDeviceOwnerSetup() throws Exception {
         executeDeviceOwnerTest("DeviceOwnerSetupTest");
     }
@@ -274,19 +266,26 @@
 //    }
 
     public void testCreateAndManageUser_AddRestrictionSet() throws Exception {
-        if (mHasCreateAndManageUserFeature) {
+        if (mHasFeature && canCreateAdditionalUsers(1)) {
             executeDeviceTestMethod(".CreateAndManageUserTest",
                 "testCreateAndManageUser_AddRestrictionSet");
         }
     }
 
     public void testCreateAndManageUser_RemoveRestrictionSet() throws Exception {
-        if (mHasCreateAndManageUserFeature) {
+        if (mHasFeature && canCreateAdditionalUsers(1)) {
             executeDeviceTestMethod(".CreateAndManageUserTest",
                 "testCreateAndManageUser_RemoveRestrictionSet");
         }
     }
 
+    public void testUserAddedOrRemovedBroadcasts() throws Exception {
+        if (mHasFeature && canCreateAdditionalUsers(1)) {
+            executeDeviceTestMethod(".CreateAndManageUserTest",
+                "testUserAddedOrRemovedBroadcasts");
+        }
+    }
+
     public void testSecurityLoggingWithTwoUsers() throws Exception {
         if (!mHasFeature || getMaxNumberOfUsersSupported() < 2) {
             return;
@@ -325,6 +324,27 @@
         }
     }
 
+    public void testNetworkLoggingWithTwoUsers() throws Exception {
+        if (!mHasFeature || getMaxNumberOfUsersSupported() < 2) {
+            return;
+        }
+        int userId = -1;
+        try {
+            userId = createUser();
+            executeDeviceTestMethod(".NetworkLoggingTest",
+                    "testSetNetworkLoggingEnabledNotPossibleIfMoreThanOneUserPresent");
+            executeDeviceTestMethod(".NetworkLoggingTest",
+                    "testRetrievingNetworkLogsNotPossibleIfMoreThanOneUserPresent");
+        } finally {
+            removeUser(userId);
+        }
+    }
+
+    public void testNetworkLoggingWithSingleUser() throws Exception {
+        executeDeviceTestMethod(".NetworkLoggingTest", "testEnablingAndDisablingNetworkLogging");
+        executeDeviceTestMethod(".NetworkLoggingTest", "testProvidingWrongBatchTokenReturnsNull");
+    }
+
     public void testLockTask() throws Exception {
         if (!mHasFeature) {
             return;
@@ -332,6 +352,12 @@
         try {
             installAppAsUser(INTENT_RECEIVER_APK, mPrimaryUserId);
             executeDeviceOwnerTest("LockTaskTest");
+        } catch (AssertionError ex) {
+            // STOPSHIP(b/32771855), remove this once we fixed the bug.
+            executeShellCommand("dumpsys activity activities");
+            executeShellCommand("dumpsys window -a");
+            executeShellCommand("dumpsys activity service com.android.systemui");
+            throw ex;
         } finally {
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
         }
@@ -401,9 +427,24 @@
         // This case runs when DO is provisioned
         // mHasFeature == true and provisioned, can't provision DO again.
         executeDeviceTestMethod(".PreDeviceOwnerTest", "testIsProvisioningAllowedFalse");
-        // Can't provision Managed Profile when DO is on
+        // Can provision Managed Profile when DO is on
+        // STOPSHIP: Only allow creating a managed profile if allowed by the device owner.
+        // b/31952368
         executeDeviceTestMethod(".PreDeviceOwnerTest",
-                "testIsProvisioningAllowedFalseForManagedProfileAction");
+                "testIsProvisioningAllowedTrueForManagedProfileAction");
+    }
+
+    public void testAdminActionBookkeeping() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            executeDeviceOwnerTest("AdminActionBookkeepingTest");
+        } finally {
+            // Always attempt to disable network logging to bring the device to initial state.
+            executeDeviceTestMethod(".AdminActionBookkeepingTest", "testDisablingNetworkLogging");
+        }
     }
 
     public void testBluetoothRestriction() throws Exception {
@@ -418,12 +459,11 @@
             return;
         }
         String testClass = DEVICE_OWNER_PKG + "." + testClassName;
-        assertTrue(testClass + " failed.",
-                runDeviceTestsAsUser(DEVICE_OWNER_PKG, testClass, mPrimaryUserId));
+        runDeviceTestsAsUser(DEVICE_OWNER_PKG, testClass, mPrimaryUserId);
     }
 
     private void executeDeviceTestMethod(String className, String testName) throws Exception {
-        assertTrue(runDeviceTestsAsUser(DEVICE_OWNER_PKG, className, testName,
-                /* deviceOwnerUserId */ mPrimaryUserId));
+        runDeviceTestsAsUser(DEVICE_OWNER_PKG, className, testName,
+                /* deviceOwnerUserId */ mPrimaryUserId);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
index 2e574d3..9205ff7 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -64,11 +64,11 @@
             return;
         }
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testGetActivitiesForUserFails",
                 mPrimaryUserId,
-                Collections.singletonMap(PARAM_TEST_USER, mSecondaryUserSerialNumber)));
+                Collections.singletonMap(PARAM_TEST_USER, mSecondaryUserSerialNumber));
     }
 
     public void testNoLauncherCallbackPackageAddedSecondaryUser() throws Exception {
@@ -77,10 +77,10 @@
         }
         startCallbackService();
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testNoPackageAddedCallbackForUser",
                 mPrimaryUserId,
-                Collections.singletonMap(PARAM_TEST_USER, mSecondaryUserSerialNumber)));
+                Collections.singletonMap(PARAM_TEST_USER, mSecondaryUserSerialNumber));
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
index 14ce1d9..6521ed8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -74,13 +74,13 @@
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
 
         // Run tests to check SimpleApp exists in both profile and main user.
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testSimpleAppInstalledForUser",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber)));
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_PKG + ".LauncherAppsTests", "testSimpleAppInstalledForUser",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber)));
+                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
     }
 
     public void testLauncherCallbackPackageAddedProfile() throws Exception {
@@ -89,10 +89,10 @@
         }
         startCallbackService();
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageAddedCallbackForUser",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber)));
+                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
     }
 
     public void testLauncherCallbackPackageRemovedProfile() throws Exception {
@@ -102,10 +102,10 @@
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
         startCallbackService();
         getDevice().uninstallPackage(SIMPLE_APP_PKG);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageRemovedCallbackForUser",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber)));
+                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
     }
 
     public void testLauncherCallbackPackageChangedProfile() throws Exception {
@@ -115,9 +115,9 @@
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
         startCallbackService();
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageChangedCallbackForUser",
-                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber)));
+                mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
index a2a1986..0481777 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
@@ -54,9 +54,9 @@
             return;
         }
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testSimpleAppInstalledForUser",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLauncherCallbackPackageAddedMainUser() throws Exception {
@@ -66,10 +66,10 @@
         startCallbackService();
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
 
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageAddedCallbackForUser",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLauncherCallbackPackageRemovedMainUser() throws Exception {
@@ -79,10 +79,10 @@
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
         startCallbackService();
         getDevice().uninstallPackage(SIMPLE_APP_PKG);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageRemovedCallbackForUser",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLauncherCallbackPackageChangedMainUser() throws Exception {
@@ -92,10 +92,10 @@
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
         startCallbackService();
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageChangedCallbackForUser",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLauncherNonExportedAppFails() throws Exception {
@@ -103,9 +103,9 @@
             return;
         }
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testLaunchNonExportActivityFails",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLaunchNonExportActivityFails() throws Exception {
@@ -113,9 +113,9 @@
             return;
         }
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testLaunchNonExportLauncherFails",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
     public void testLaunchMainActivity() throws Exception {
@@ -123,8 +123,8 @@
             return;
         }
         installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
-        assertTrue(runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testLaunchMainActivity",
-                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber)));
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index e01d495..d479868 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -20,6 +20,7 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
+import java.lang.System;
 import junit.framework.AssertionFailedError;
 
 import java.util.concurrent.Callable;
@@ -69,6 +70,8 @@
 
     private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
 
+    private static final int MANAGED_PROFILE_REMOVED_TIMEOUT_SECONDS = 15;
+
     private int mParentUserId;
 
     // ID of the profile we'll create. This will always be a profile of the parent.
@@ -114,9 +117,9 @@
         if (!mHasFeature) {
             return;
         }
-        assertTrue(runDeviceTestsAsUser(
+        runDeviceTestsAsUser(
                 MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".ManagedProfileSetupTest",
-                mProfileUserId));
+                mProfileUserId);
     }
 
     /**
@@ -127,11 +130,20 @@
             return;
         }
         assertTrue(listUsers().contains(mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".WipeDataTest", mProfileUserId));
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".WipeDataTest", mProfileUserId);
         // Note: the managed profile is removed by this test, which will make removeUserCommand in
         // tearDown() to complain, but that should be OK since its result is not asserted.
-        assertFalse(listUsers().contains(mProfileUserId));
+        long epoch = System.currentTimeMillis();
+        while (System.currentTimeMillis() - epoch <=
+                MANAGED_PROFILE_REMOVED_TIMEOUT_SECONDS * 1000) {
+            Thread.sleep(1000);
+            if (!listUsers().contains(mProfileUserId)) {
+                // The managed profile has been removed: success
+                return;
+            }
+        }
+        fail("The managed profile has not been removed after calling wipeData");
     }
 
     public void testMaxOneManagedProfile() throws Exception {
@@ -154,18 +166,19 @@
         if (!mHasFeature || !hasDeviceFeature(FEATURE_WIFI)) {
             return;
         }
-        assertTrue("WiFi config already exists and could not be removed", runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, ".WifiTest", "testRemoveWifiNetworkIfExists", mParentUserId));
-
         installAppAsUser(WIFI_CONFIG_CREATOR_APK, mProfileUserId);
-        assertTrue("Failed to add WiFi config", runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, ".WifiTest", "testAddWifiNetwork", mProfileUserId));
+
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG, ".WifiTest", "testRemoveWifiNetworkIfExists", mParentUserId);
+
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG, ".WifiTest", "testAddWifiNetwork", mProfileUserId);
 
         // Now delete the user - should undo the effect of testAddWifiNetwork.
         removeUser(mProfileUserId);
-        assertTrue("WiFi config not removed after deleting profile", runDeviceTestsAsUser(
+        runDeviceTestsAsUser(
                 MANAGED_PROFILE_PKG, ".WifiTest", "testWifiNetworkDoesNotExist",
-                mParentUserId));
+                mParentUserId);
     }
 
     public void testCrossProfileIntentFilters() throws Exception {
@@ -177,27 +190,27 @@
         disableActivityForUser("ManagedProfileActivity", mParentUserId);
         disableActivityForUser("PrimaryUserActivity", mProfileUserId);
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
-                MANAGED_PROFILE_PKG + ".ManagedProfileTest", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                MANAGED_PROFILE_PKG + ".ManagedProfileTest", mProfileUserId);
 
         // Set up filters from primary to managed profile
         String command = "am start -W --user " + mProfileUserId  + " " + MANAGED_PROFILE_PKG
                 + "/.PrimaryUserFilterSetterActivity";
         CLog.d("Output for command " + command + ": "
               + getDevice().executeShellCommand(command));
-        assertTrue(runDeviceTestsAsUser(
-                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".PrimaryUserTest", mParentUserId));
+        runDeviceTestsAsUser(
+                MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".PrimaryUserTest", mParentUserId);
         // TODO: Test with startActivity
     }
 
-    public void testAppLinks() throws Exception {
+    public void testAppLinks_verificationStatus() throws Exception {
         if (!mHasFeature) {
             return;
         }
         // Disable all pre-existing browsers in the managed profile so they don't interfere with
         // intents resolution.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testDisableAllBrowsers", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testDisableAllBrowsers", mProfileUserId);
         installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
         installAppAsUser(INTENT_SENDER_APK, mParentUserId);
         installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
@@ -229,14 +242,69 @@
         assertAppLinkResult("testReceivedByAppLinkActivityInManaged");
     }
 
+    public void testAppLinks_enabledStatus() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        // Disable all pre-existing browsers in the managed profile so they don't interfere with
+        // intents resolution.
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testDisableAllBrowsers", mProfileUserId);
+        installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
+        installAppAsUser(INTENT_SENDER_APK, mParentUserId);
+        installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
+        installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
+
+        final String APP_HANDLER_COMPONENT = "com.android.cts.intent.receiver/.AppLinkActivity";
+
+        // allow_parent_profile_app_linking is not set, try different enabled state combinations.
+        // We should not have app link handler in parent user no matter whether it is enabled.
+
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testReceivedByBrowserActivityInManaged");
+
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testReceivedByBrowserActivityInManaged");
+
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testTwoReceivers");
+
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testTwoReceivers");
+
+        // We now set allow_parent_profile_app_linking, and hence we should have the app handler
+        // in parent user if it is enabled.
+        changeUserRestrictionForUser("allow_parent_profile_app_linking", ADD_RESTRICTION_COMMAND,
+                mProfileUserId);
+
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testReceivedByBrowserActivityInManaged");
+
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testTwoReceivers");
+
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testTwoReceivers");
+
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
+        assertAppLinkResult("testThreeReceivers");
+    }
 
     public void testSettingsIntents() throws Exception {
         if (!mHasFeature) {
             return;
         }
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".SettingsIntentsTest",
-                mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".SettingsIntentsTest",
+                mProfileUserId);
     }
 
     public void testCrossProfileContent() throws Exception {
@@ -249,18 +317,18 @@
         installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
 
         // Test from parent to managed
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAddManagedCanAccessParentFilters", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mParentUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testRemoveAllFilters", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testAddManagedCanAccessParentFilters", mProfileUserId);
+        runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mParentUserId);
 
         // Test from managed to parent
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAddParentCanAccessManagedFilters", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testRemoveAllFilters", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testAddParentCanAccessManagedFilters", mProfileUserId);
+        runDeviceTestsAsUser(INTENT_SENDER_PKG, ".ContentTest", mProfileUserId);
 
     }
 
@@ -273,15 +341,15 @@
         installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
         installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testAllowCrossProfileCopyPaste", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testAllowCrossProfileCopyPaste", mProfileUserId);
         // Test that managed can see what is copied in the parent.
         testCrossProfileCopyPasteInternal(mProfileUserId, true);
         // Test that the parent can see what is copied in managed.
         testCrossProfileCopyPasteInternal(mParentUserId, true);
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testDisallowCrossProfileCopyPaste", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testDisallowCrossProfileCopyPaste", mProfileUserId);
         // Test that managed can still see what is copied in the parent.
         testCrossProfileCopyPasteInternal(mProfileUserId, true);
         // Test that the parent cannot see what is copied in managed.
@@ -293,21 +361,36 @@
         final String direction = (userId == mParentUserId)
                 ? "testAddManagedCanAccessParentFilters"
                 : "testAddParentCanAccessManagedFilters";
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                "testRemoveAllFilters", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
-                direction, mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                "testRemoveAllFilters", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                direction, mProfileUserId);
         if (shouldSucceed) {
-            assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
-                    "testCanReadAcrossProfiles", userId));
-            assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
-                    "testIsNotified", userId));
+            runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
+                    "testCanReadAcrossProfiles", userId);
+            runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
+                    "testIsNotified", userId);
         } else {
-            assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
-                    "testCannotReadAcrossProfiles", userId));
+            runDeviceTestsAsUser(INTENT_SENDER_PKG, ".CopyPasteTest",
+                    "testCannotReadAcrossProfiles", userId);
         }
     }
 
+    /** Tests for the API helper class. */
+    public void testCurrentApiHelper() throws Exception {
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CurrentApiHelperTest",
+                mProfileUserId);
+    }
+
+    /** Test: unsupported public APIs are disabled on a parent profile. */
+    public void testParentProfileApiDisabled() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ParentProfileTest",
+                "testParentProfileApiDisabled", mProfileUserId);
+    }
+
     // TODO: This test is not specific to managed profiles, but applies to multi-user in general.
     // Move it to a MultiUserTest class when there is one. Should probably move
     // SetPolicyActivity to a more generic apk too as it might be useful for different kinds
@@ -348,14 +431,14 @@
             return ;
         }
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testEnableDisable", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testGetAddress", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testListenUsingRfcommWithServiceRecord", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
-                "testGetRemoteDevice", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
+                "testEnableDisable", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
+                "testGetAddress", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
+                "testListenUsingRfcommWithServiceRecord", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".BluetoothTest",
+                "testGetRemoteDevice", mProfileUserId);
     }
 
     public void testCameraPolicy() throws Exception {
@@ -367,40 +450,40 @@
             setDeviceAdmin(MANAGED_PROFILE_PKG + "/.PrimaryUserDeviceAdmin", mParentUserId);
 
             // Disable managed profile camera.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testDisableCameraInManagedProfile",
-                    mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    mProfileUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInPrimaryProfile",
-                    mParentUserId));
+                    mParentUserId);
 
             // Enable managed profile camera.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testEnableCameraInManagedProfile",
-                    mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    mProfileUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInPrimaryProfile",
-                    mParentUserId));
+                    mParentUserId);
 
             // Disable primary profile camera.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testDisableCameraInPrimaryProfile",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInManagedProfile",
-                    mProfileUserId));
+                    mProfileUserId);
 
             // Enable primary profile camera.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testEnableCameraInPrimaryProfile",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
                     "testIsCameraEnabledInManagedProfile",
-                    mProfileUserId));
+                    mProfileUserId);
         } finally {
             final String adminHelperClass = ".PrimaryUserAdminHelper";
-            assertTrue("Clear device admin failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
-                    adminHelperClass, "testClearDeviceAdmin", mParentUserId));
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    adminHelperClass, "testClearDeviceAdmin", mParentUserId);
         }
     }
 
@@ -426,8 +509,8 @@
         runManagedContactsTest(new Callable<Void>() {
             @Override
             public Void call() throws Exception {
-                assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                        "testQuickContact", mParentUserId));
+                runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                        "testQuickContact", mParentUserId);
                 return null;
             }
         });
@@ -470,28 +553,28 @@
         if (!mHasFeature) {
             return;
         }
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
-                "testDefaultOrganizationColor", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
-                "testDefaultOrganizationNameIsNull", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
-                mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
+                "testDefaultOrganizationColor", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
+                "testDefaultOrganizationNameIsNull", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OrganizationInfoTest",
+                mProfileUserId);
     }
 
     public void testPasswordMinimumRestrictions() throws Exception {
         if (!mHasFeature) {
             return;
         }
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PasswordMinimumRestrictionsTest",
-                mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PasswordMinimumRestrictionsTest",
+                mProfileUserId);
     }
 
     public void testBluetoothContactSharingDisabled() throws Exception {
         if (!mHasFeature) {
             return;
         }
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                "testSetBluetoothContactSharingDisabled_setterAndGetter", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                "testSetBluetoothContactSharingDisabled_setterAndGetter", mProfileUserId);
     }
 
     public void testCannotSetProfileOwnerAgain() throws Exception {
@@ -530,10 +613,10 @@
             return;
         }
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", mParentUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", mParentUserId);
 
         String restriction = "no_outgoing_beam";  // UserManager.DISALLOW_OUTGOING_BEAM
         String command = "add-restriction";
@@ -543,10 +626,10 @@
         assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
                 addRestrictionCommandOutput.contains("Status: ok"));
 
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareDisabled", mProfileUserId));
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
-                "testNfcShareEnabled", mParentUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareDisabled", mProfileUserId);
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", mParentUserId);
     }
 
     public void testCrossProfileWidgets() throws Exception {
@@ -566,28 +649,28 @@
             assertTrue("Command was expected to succeed " + commandOutput,
                     commandOutput.contains("Status: ok"));
 
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
-                    "testCrossProfileWidgetProviderAdded", mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
+                    "testCrossProfileWidgetProviderAdded", mProfileUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
                     ".CrossProfileWidgetPrimaryUserTest",
-                    "testHasCrossProfileWidgetProvider_true", mParentUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    "testHasCrossProfileWidgetProvider_true", mParentUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
                     ".CrossProfileWidgetPrimaryUserTest",
-                    "testHostReceivesWidgetUpdates_true", mParentUserId));
+                    "testHostReceivesWidgetUpdates_true", mParentUserId);
 
             commandOutput = changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
                     "remove-cross-profile-widget", mProfileUserId);
             assertTrue("Command was expected to succeed " + commandOutput,
                     commandOutput.contains("Status: ok"));
 
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
-                    "testCrossProfileWidgetProviderRemoved", mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
+                    "testCrossProfileWidgetProviderRemoved", mProfileUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
                     ".CrossProfileWidgetPrimaryUserTest",
-                    "testHasCrossProfileWidgetProvider_false", mParentUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    "testHasCrossProfileWidgetProvider_false", mParentUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
                     ".CrossProfileWidgetPrimaryUserTest",
-                    "testHostReceivesWidgetUpdates_false", mParentUserId));
+                    "testHostReceivesWidgetUpdates_false", mParentUserId);
         } finally {
             changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG, "remove-cross-profile-widget",
                     mProfileUserId);
@@ -600,13 +683,13 @@
             return;
         }
         // In Managed profile user when managed profile is provisioned
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
-                "testIsProvisioningAllowedFalse", mProfileUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
+                "testIsProvisioningAllowedFalse", mProfileUserId);
 
         // In parent user when managed profile is provisioned
         // It's allowed to provision again by removing the previous profile
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
-                "testIsProvisioningAllowedTrue", mParentUserId));
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PreManagedProfileTest",
+                "testIsProvisioningAllowedTrue", mParentUserId);
     }
 
     private void setDirectoryPrefix(String directoryName, int userId)
@@ -628,34 +711,34 @@
         }
         try {
             // Register phone account in parent user.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testRegisterPhoneAccount",
-                    mParentUserId));
+                    mParentUserId);
             // The phone account should not be visible in managed user.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testPhoneAccountNotRegistered",
-                    mProfileUserId));
+                    mProfileUserId);
         } finally {
             // Unregister the phone account.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testUnregisterPhoneAccount",
-                    mParentUserId));
+                    mParentUserId);
         }
 
         try {
             // Register phone account in profile user.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testRegisterPhoneAccount",
-                    mProfileUserId));
+                    mProfileUserId);
             // The phone account should not be visible in parent user.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testPhoneAccountNotRegistered",
-                    mParentUserId));
+                    mParentUserId);
         } finally {
             // Unregister the phone account.
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                     "testUnregisterPhoneAccount",
-                    mProfileUserId));
+                    mProfileUserId);
         }
     }
 
@@ -668,33 +751,38 @@
         }
         // Place a outgoing call through work phone account using TelecomManager and verify the
         // call is inserted properly.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testOutgoingCallUsingTelecomManager",
-                mProfileUserId));
+                mProfileUserId);
         // Make sure the call is not inserted into parent user.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testEnsureCallNotInserted",
-                mParentUserId));
+                mParentUserId);
 
         // Place a outgoing call through work phone account using ACTION_CALL and verify the call
         // is inserted properly.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testOutgoingCallUsingActionCall",
-                mProfileUserId));
+                mProfileUserId);
         // Make sure the call is not inserted into parent user.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testEnsureCallNotInserted",
-                mParentUserId));
+                mParentUserId);
 
         // Add an incoming call with parent user's phone account and verify the call is inserted
         // properly.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testIncomingCall",
-                mProfileUserId));
+                mProfileUserId);
         // Make sure the call is not inserted into parent user.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PhoneAccountTest",
                 "testEnsureCallNotInserted",
-                mParentUserId));
+                mParentUserId);
+    }
+
+    public void testRingtoneSync() throws Exception {
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".RingtoneSyncTest",
+                "testRingtoneSync", mProfileUserId);
     }
 
     public void testTrustAgentInfo() throws Exception {
@@ -702,22 +790,22 @@
             return;
         }
         // Set and get trust agent config using child dpm instance.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
                 "testSetAndGetTrustAgentConfiguration_child",
-                mProfileUserId));
+                mProfileUserId);
         // Set and get trust agent config using parent dpm instance.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
                 "testSetAndGetTrustAgentConfiguration_parent",
-                mProfileUserId));
+                mProfileUserId);
         // Unified case
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
                 "testSetTrustAgentConfiguration_bothHaveTrustAgentConfigAndUnified",
-                mProfileUserId));
+                mProfileUserId);
         // Non-unified case, this test must run last because we have no way to clear work side
         // password.
-        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".TrustAgentInfoTest",
                 "testSetTrustAgentConfiguration_bothHaveTrustAgentConfigAndNonUnified",
-                mProfileUserId));
+                mProfileUserId);
     }
 
     private void disableActivityForUser(String activityName, int userId)
@@ -773,8 +861,8 @@
     }
 
     private void assertAppLinkResult(String methodName) throws DeviceNotAvailableException {
-        assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".AppLinkTest", methodName,
-                mProfileUserId));
+        runDeviceTestsAsUser(INTENT_SENDER_PKG, ".AppLinkTest", methodName,
+                mProfileUserId);
     }
 
     private boolean shouldRunTelecomTest() throws DeviceNotAvailableException {
@@ -794,10 +882,10 @@
                     + " secure managed_profile_contact_remote_search 1");
 
             // Add test account
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testAddTestAccount", mParentUserId));
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testAddTestAccount", mProfileUserId));
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testAddTestAccount", mParentUserId);
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testAddTestAccount", mProfileUserId);
 
             // Install directory provider to both primary and managed profile
             installAppAsUser(DIRECTORY_PROVIDER_APK, mProfileUserId);
@@ -806,25 +894,25 @@
             setDirectoryPrefix(MANAGED_DIRECTORY_PREFIX, mProfileUserId);
 
             // Check enterprise directory API works
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testGetDirectoryListInPrimaryProfile", mParentUserId));
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testGetDirectoryListInPrimaryProfile", mParentUserId);
 
             // Insert Primary profile Contacts
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testPrimaryProfilePhoneAndEmailLookup_insertedAndfound", mParentUserId));
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testPrimaryProfilePhoneAndEmailLookup_insertedAndfound", mParentUserId);
             // Insert Managed profile Contacts
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
-                    "testManagedProfilePhoneAndEmailLookup_insertedAndfound", mProfileUserId));
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testManagedProfilePhoneAndEmailLookup_insertedAndfound", mProfileUserId);
             // Insert a primary contact with same phone & email as other
             // enterprise contacts
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testPrimaryProfileDuplicatedPhoneEmailContact_insertedAndfound",
-                    mParentUserId));
+                    mParentUserId);
             // Insert a enterprise contact with same phone & email as other
             // primary contacts
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
                     "testManagedProfileDuplicatedPhoneEmailContact_insertedAndfound",
-                    mProfileUserId));
+                    mProfileUserId);
 
             callable.call();
 
@@ -857,31 +945,31 @@
             mProfileUserId = profileUserId;
         }
 
-        private boolean runDeviceTestsAsUser(String pkgName, String testClassName,
+        private void runDeviceTestsAsUser(String pkgName, String testClassName,
                 String testMethodName, Integer userId) throws DeviceNotAvailableException {
-            return mManagedProfileTest.runDeviceTestsAsUser(pkgName, testClassName, testMethodName,
+            mManagedProfileTest.runDeviceTestsAsUser(pkgName, testClassName, testMethodName,
                     userId);
         }
 
         // Enable / Disable cross profile caller id
         public void setCallerIdEnabled(boolean enabled) throws DeviceNotAvailableException {
             if (enabled) {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                        "testSetCrossProfileCallerIdDisabled_false", mProfileUserId));
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        "testSetCrossProfileCallerIdDisabled_false", mProfileUserId);
             } else {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                        "testSetCrossProfileCallerIdDisabled_true", mProfileUserId));
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        "testSetCrossProfileCallerIdDisabled_true", mProfileUserId);
             }
         }
 
         // Enable / Disable cross profile contacts search
         public void setContactsSearchEnabled(boolean enabled) throws DeviceNotAvailableException {
             if (enabled) {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                        "testSetCrossProfileContactsSearchDisabled_false", mProfileUserId));
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        "testSetCrossProfileContactsSearchDisabled_false", mProfileUserId);
             } else {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                        "testSetCrossProfileContactsSearchDisabled_true", mProfileUserId));
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        "testSetCrossProfileContactsSearchDisabled_true", mProfileUserId);
             }
         }
 
@@ -889,182 +977,182 @@
                 throws DeviceNotAvailableException {
             // Primary user cannot use ordinary phone/email lookup api to access
             // managed contacts
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", mParentUserId));
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    "testPrimaryProfilePhoneLookup_canNotAccessEnterpriseContact", mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    "testPrimaryProfileEmailLookup_canNotAccessEnterpriseContact", mParentUserId);
             // Primary user can use ENTERPRISE_CONTENT_FILTER_URI to access
             // primary contacts
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneLookup_canAccessPrimaryContact",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailLookup_canAccessPrimaryContact",
-                    mParentUserId));
+                    mParentUserId);
             // When there exist contacts with the same phone/email in primary &
             // enterprise,
             // primary user can use ENTERPRISE_CONTENT_FILTER_URI to access the
             // primary contact.
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailLookupDuplicated_canAccessPrimaryContact",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneLookupDuplicated_canAccessPrimaryContact",
-                    mParentUserId));
+                    mParentUserId);
 
             // Managed user cannot use ordinary phone/email lookup api to access
             // primary contacts
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mProfileUserId));
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    "testManagedProfilePhoneLookup_canNotAccessPrimaryContact", mProfileUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    "testManagedProfileEmailLookup_canNotAccessPrimaryContact", mProfileUserId);
             // Managed user can use ENTERPRISE_CONTENT_FILTER_URI to access
             // enterprise contacts
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneLookup_canAccessEnterpriseContact",
-                    mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mProfileUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterpriseEmailLookup_canAccessEnterpriseContact",
-                    mProfileUserId));
+                    mProfileUserId);
             // Managed user cannot use ENTERPRISE_CONTENT_FILTER_URI to access
             // primary contacts
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneLookup_canNotAccessPrimaryContact",
-                    mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mProfileUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterpriseEmailLookup_canNotAccessPrimaryContact",
-                    mProfileUserId));
+                    mProfileUserId);
             // When there exist contacts with the same phone/email in primary &
             // enterprise,
             // managed user can use ENTERPRISE_CONTENT_FILTER_URI to access the
             // enterprise contact.
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterpriseEmailLookupDuplicated_canAccessEnterpriseContact",
-                    mProfileUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mProfileUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneLookupDuplicated_canAccessEnterpriseContact",
-                    mProfileUserId));
+                    mProfileUserId);
 
             // Check if phone lookup can access primary directories
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneLookup_canAccessPrimaryDirectories",
-                    mParentUserId));
+                    mParentUserId);
 
             // Check if email lookup can access primary directories
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailLookup_canAccessPrimaryDirectories",
-                    mParentUserId));
+                    mParentUserId);
 
             if (expected) {
                 // Primary user can use ENTERPRISE_CONTENT_FILTER_URI to access
                 // managed profile contacts
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneLookup_canAccessEnterpriseContact",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseEmailLookup_canAccessEnterpriseContact",
-                        mParentUserId));
+                        mParentUserId);
 
                 // Make sure SIP enterprise lookup works too.
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseSipLookup_canAccessEnterpriseContact",
-                        mParentUserId));
+                        mParentUserId);
 
                 // Check if phone lookup can access enterprise directories
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneLookup_canAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
 
                 // Check if email lookup can access enterprise directories
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseEmailLookup_canAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
             } else {
                 // Primary user cannot use ENTERPRISE_CONTENT_FILTER_URI to
                 // access managed contacts
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneLookup_canNotAccessEnterpriseContact",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneLookup_canNotAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
 
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseEmailLookup_canNotAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneLookup_canNotAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
             }
         }
 
         public void checkIfCanFilterSelfContacts() throws DeviceNotAvailableException {
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseCallableFilter_canAccessPrimaryDirectories",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterpriseCallableFilter_canAccessManagedDirectories",
-                    mProfileUserId));
+                    mProfileUserId);
 
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseEmailFilter_canAccessPrimaryDirectories",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testEnterpriseProfileEnterpriseEmailFilter_canAccessManagedDirectories",
-                    mProfileUserId));
+                    mProfileUserId);
 
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseContactFilter_canAccessPrimaryDirectories",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterpriseContactFilter_canAccessManagedDirectories",
-                    mProfileUserId));
+                    mProfileUserId);
 
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterprisePhoneFilter_canAccessPrimaryDirectories",
-                    mParentUserId));
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    mParentUserId);
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testManagedProfileEnterprisePhoneFilter_canAccessManagedDirectories",
-                    mProfileUserId));
+                    mProfileUserId);
         }
 
         public void checkIfCanFilterEnterpriseContacts(boolean expected)
                 throws DeviceNotAvailableException {
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
-                    "testFilterUriWhenDirectoryParamMissing", mParentUserId));
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                    "testFilterUriWhenDirectoryParamMissing", mParentUserId);
             if (expected) {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseCallableFilter_canAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseEmailFilter_canAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseContactFilter_canAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneFilter_canAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
             } else {
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseCallableFilter_canNotAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseEmailFilter_canNotAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterpriseContactFilter_canNotAccessManagedDirectories",
-                        mParentUserId));
-                assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+                        mParentUserId);
+                runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                         "testPrimaryProfileEnterprisePhoneFilter_canNotAccessManagedDirectories",
-                        mParentUserId));
+                        mParentUserId);
             }
         }
 
         public void checkIfNoEnterpriseDirectoryFound() throws DeviceNotAvailableException {
-            assertTrue(runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
+            runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
                     "testPrimaryProfileEnterpriseDirectories_canNotAccessManagedDirectories",
-                    mParentUserId));
+                    mParentUserId);
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index afc4e34..81b1b54 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -16,10 +16,6 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.lang.AssertionError;
-
 /**
  * Set of tests for managed profile owner use cases that also apply to device owners.
  * Tests that should be run identically in both cases are added in DeviceAndProfileOwnerTest.
@@ -78,20 +74,50 @@
 
         // start the ScreenCaptureDisabledActivity in the parent
         installAppAsUser(DEVICE_ADMIN_APK, mParentUserId);
-        startScreenCaptureDisabledActivity(mParentUserId);
+        startSimpleActivityAsUser(mParentUserId);
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", "testScreenCapturePossible");
     }
 
+    /**
+     * Verify the Profile Owner of a managed profile can create and change the password,
+     * but cannot remove it.
+     */
     @Override
-    public void testResetPassword() {
-        // Managed profile owner can't call resetPassword().
+    public void testResetPassword() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPasswordManagedProfile");
+    }
+
+    /**
+     *  Verify the Profile Owner of a managed profile can only change the password when FBE is
+     *  unlocked, and cannot remove the password even when FBE is unlocked.
+     */
+    @Override
+    public void testResetPasswordFbe() throws Exception {
+        if (!mHasFeature || !mSupportsFbe) {
+            return;
+        }
+
+        // Lock FBE and verify resetPassword is disabled
+        executeDeviceTestMethod(FBE_HELPER_CLASS, "testSetPassword");
+        rebootAndWaitUntilReady();
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPasswordDisabled");
+
+        // Start an activity in managed profile to trigger work challenge
+        startSimpleActivityAsUser(mUserId);
+
+        // Unlock FBE and verify resetPassword is enabled again
+        executeDeviceTestMethod(FBE_HELPER_CLASS, "testUnlockFbe");
+        executeDeviceTestMethod(RESET_PASSWORD_TEST_CLASS, "testResetPasswordManagedProfile");
     }
 
     public void testCannotClearProfileOwner() throws Exception {
         if (mHasFeature) {
-            assertTrue("Managed profile owner shouldn't be removed",
-                    runDeviceTestsAsUser(DEVICE_ADMIN_PKG, CLEAR_PROFILE_OWNER_NEGATIVE_TEST_CLASS,
-                            mUserId));
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, CLEAR_PROFILE_OWNER_NEGATIVE_TEST_CLASS,
+                    mUserId);
         }
     }
 
@@ -105,20 +131,4 @@
         // DISALLOW_UNMUTE_MICROPHONE and DISALLOW_ADJUST_VOLUME can only be set by device owners
         // and profile owners on the primary user.
     }
-
-    @Override
-    public void testDelegatedCertInstaller() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-
-        try {
-            super.testDelegatedCertInstaller();
-        } finally {
-            // In managed profile, clearing password through dpm is not allowed. Recreate user to
-            // clear password instead.
-            removeUser(mUserId);
-            createManagedProfile();
-        }
-    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
index 41f7010..68a0098 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java
@@ -58,7 +58,6 @@
             return;
         }
         String testClass = PROFILE_OWNER_PKG + "." + testClassName;
-        assertTrue(testClass + " failed.", runDeviceTestsAsUser(PROFILE_OWNER_PKG, testClass,
-                mPrimaryUserId));
+        runDeviceTestsAsUser(PROFILE_OWNER_PKG, testClass, mPrimaryUserId);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTestApi23.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTestApi23.java
index 4c1477e..323f6e0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTestApi23.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTestApi23.java
@@ -51,7 +51,7 @@
         if (!mHasFeature) {
             return;
         }
-        assertTrue("DelegatedCertInstaller failed", runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
-                ".DelegatedCertInstallerTest", "testSetNotExistCertInstallerPackage",  mUserId));
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG,
+                ".DelegatedCertInstallerTest", "testSetNotExistCertInstallerPackage",  mUserId);
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
index 789ce87..0c2f575 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/UserRestrictionsTest.java
@@ -44,8 +44,7 @@
                 assertTrue("Failed to clear owner",
                         removeAdmin(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
                                 mDeviceOwnerUserId));
-                assertTrue("Some user restrictions are still set",
-                        runTests("userrestrictions.CheckNoOwnerRestrictionsTest", mDeviceOwnerUserId));
+                runTests("userrestrictions.CheckNoOwnerRestrictionsTest", mDeviceOwnerUserId);
             }
 
             // DO/PO might have set DISALLOW_REMOVE_USER, so it needs to be done after removing
@@ -56,14 +55,14 @@
         super.tearDown();
     }
 
-    private boolean runTests(@Nonnull String className,
+    private void runTests(@Nonnull String className,
             @Nullable String method, int userId) throws DeviceNotAvailableException {
-        return runDeviceTestsAsUser(DEVICE_ADMIN_PKG, "." + className, method, userId);
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, "." + className, method, userId);
     }
 
-    private boolean runTests(@Nonnull String className, int userId)
+    private void runTests(@Nonnull String className, int userId)
             throws DeviceNotAvailableException {
-        return runTests(className, null, userId);
+        runTests(className, null, userId);
     }
 
     public void testUserRestrictions_deviceOwnerOnly() throws Exception {
@@ -77,6 +76,8 @@
         mRemoveOwnerInTearDown = true;
 
         runTests("userrestrictions.DeviceOwnerUserRestrictionsTest",
+                "testDefaultRestrictions", mDeviceOwnerUserId);
+        runTests("userrestrictions.DeviceOwnerUserRestrictionsTest",
                 "testSetAllRestrictions", mDeviceOwnerUserId);
     }
 
@@ -96,6 +97,8 @@
         mRemoveOwnerInTearDown = true;
 
         runTests("userrestrictions.PrimaryProfileOwnerUserRestrictionsTest",
+                "testDefaultRestrictions", mDeviceOwnerUserId);
+        runTests("userrestrictions.PrimaryProfileOwnerUserRestrictionsTest",
                 "testSetAllRestrictions", mDeviceOwnerUserId);
     }
 
@@ -111,6 +114,8 @@
                         secondaryUserId, /* expectFailure */ false));
 
         runTests("userrestrictions.SecondaryProfileOwnerUserRestrictionsTest",
+                "testDefaultRestrictions", secondaryUserId);
+        runTests("userrestrictions.SecondaryProfileOwnerUserRestrictionsTest",
                 "testSetAllRestrictions", secondaryUserId);
     }
 
diff --git a/hostsidetests/dumpsys/Android.mk b/hostsidetests/dumpsys/Android.mk
index 9de0e9c..8a3470f 100644
--- a/hostsidetests/dumpsys/Android.mk
+++ b/hostsidetests/dumpsys/Android.mk
@@ -21,9 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsDumpsysHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.dumpsys
 
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index fee107e..acfc72d 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,7 +16,7 @@
 
 package android.dumpsys.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -876,7 +876,8 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+            File testAppFile = buildHelper.getTestFile(TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
index 338a7ae..3c8ead8 100644
--- a/hostsidetests/jdwpsecurity/Android.mk
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -23,9 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsJdwpSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/jdwpsecurity/AndroidTest.xml b/hostsidetests/jdwpsecurity/AndroidTest.xml
index bbb99e9..a2a4db3 100644
--- a/hostsidetests/jdwpsecurity/AndroidTest.xml
+++ b/hostsidetests/jdwpsecurity/AndroidTest.xml
@@ -16,5 +16,6 @@
 <configuration description="Config for the CTS JDWP host test cases">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsJdwpSecurityHostTestCases.jar" />
+        <option name="runtime-hint" value="10m30s" />
     </test>
 </configuration>
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
index 186728c..a5570af 100644
--- a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -16,7 +16,7 @@
 
 package android.jdwpsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -85,7 +85,8 @@
         getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
 
         // Push jar file.
-        File jarFile = MigrationHelper.getTestFile(mBuildInfo, DEVICE_JAR_FILENAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        File jarFile = buildHelper.getTestFile(DEVICE_JAR_FILENAME);
         boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
         assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
     }
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index 14462d0..7c7ecb5 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsMonkeyTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 # prefix zzz intentional to run this last
 LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
index 26023be..5f22b62 100755
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -1,7 +1,6 @@
 package com.android.cts.monkey;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -9,6 +8,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 
@@ -41,9 +41,10 @@
         super.setUp();
         mDevice = getDevice();
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         for (int i = 0; i < PKGS.length; i++) {
             mDevice.uninstallPackage(PKGS[i]);
-            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+            File app = buildHelper.getTestFile(APKS[i]);
             mDevice.installPackage(app, false, options);
         }
         clearLogCat();
diff --git a/hostsidetests/multiuser/Android.mk b/hostsidetests/multiuser/Android.mk
index 1a324fb..ec18912 100644
--- a/hostsidetests/multiuser/Android.mk
+++ b/hostsidetests/multiuser/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.multiuser
 
@@ -34,4 +32,4 @@
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/multiuser/AndroidTest.xml b/hostsidetests/multiuser/AndroidTest.xml
index d4428fa..b6ceb00 100644
--- a/hostsidetests/multiuser/AndroidTest.xml
+++ b/hostsidetests/multiuser/AndroidTest.xml
@@ -16,5 +16,6 @@
 <configuration description="Config for the CTS multiuser host tests">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsMultiUserHostTestCases.jar" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
index d8232c3..ea6dadc 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
@@ -86,6 +86,29 @@
         throw new IllegalStateException();
     }
 
+    /**
+     * @return the userid of the created user
+     */
+    protected int createUser()
+            throws DeviceNotAvailableException, IllegalStateException {
+        final String command = "pm create-user "
+                + "TestUser_" + System.currentTimeMillis();
+        CLog.d("Starting command: " + command);
+        final String output = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + output);
+
+        if (output.startsWith("Success")) {
+            try {
+                return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
+            } catch (NumberFormatException e) {
+                CLog.e("Failed to parse result: %s", output);
+            }
+        } else {
+            CLog.e("Failed to create user: %s", output);
+        }
+        throw new IllegalStateException();
+    }
+
     private void removeTestUsers() throws Exception {
         for (int userId : getDevice().listUsers()) {
             if (!mFixedUsers.contains(userId)) {
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
index d111e0b..9a43534 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersPermissionTest.java
@@ -15,6 +15,10 @@
  */
 package android.host.multiuser;
 
+import static com.android.tradefed.log.LogUtil.CLog;
+
+import com.android.ddmlib.Log;
+
 public class CreateUsersPermissionTest extends BaseMultiUserTest {
 
     public void testCanCreateGuestUser() throws Exception {
@@ -45,9 +49,16 @@
     }
 
     public void testCantSetUserRestriction() throws Exception {
+        if (getDevice().isAdbRoot()) {
+            CLog.logAndDisplay(Log.LogLevel.WARN,
+                    "Cannot test testCantSetUserRestriction on rooted devices");
+            return;
+        }
         final String setRestriction = "pm set-user-restriction no_fun ";
         final String output = getDevice().executeShellCommand(setRestriction + "1");
-        assertTrue("Trying to set user restriction should fail with SecurityException",
-                output.startsWith("Error") && output.contains("SecurityException"));
+        final boolean isErrorOutput = output.startsWith("Error")
+                && output.contains("SecurityException");
+        assertTrue("Trying to set user restriction should fail with SecurityException. "
+                + "command output: " + output, isErrorOutput);
     }
 }
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index ad97ecd..1c3f053 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsHostsideNetworkTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
 
diff --git a/hostsidetests/net/aidl/Android.mk b/hostsidetests/net/aidl/Android.mk
index 4aa55b6..58be21f 100644
--- a/hostsidetests/net/aidl/Android.mk
+++ b/hostsidetests/net/aidl/Android.mk
@@ -17,6 +17,8 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := com/android/cts/net/hostside/IRemoteSocketFactory.aidl
+LOCAL_SRC_FILES := \
+        com/android/cts/net/hostside/IMyService.aidl \
+        com/android/cts/net/hostside/IRemoteSocketFactory.aidl
 LOCAL_MODULE := CtsHostsideNetworkTestsAidl
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl b/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl
new file mode 100644
index 0000000..72d1059
--- /dev/null
+++ b/hostsidetests/net/aidl/com/android/cts/net/hostside/IMyService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.net.hostside;
+
+interface IMyService {
+    void registerBroadcastReceiver();
+    int getCounters(String receiverName, String action);
+    String checkNetworkStatus();
+    String getRestrictBackgroundStatus();
+    void sendNotification(int notificationId, String notificationType);
+}
diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk
index 9519ec52..1c1a798 100644
--- a/hostsidetests/net/app/Android.mk
+++ b/hostsidetests/net/app/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator \
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \
         CtsHostsideNetworkTestsAidl
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index cbd8fea..014d7ae 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -16,11 +16,11 @@
 
 package com.android.cts.net.hostside;
 
-import static android.cts.util.SystemUtil.runShellCommand;
 import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -55,25 +55,11 @@
     // Constants below must match values defined on app2's Common.java
     private static final String MANIFEST_RECEIVER = "ManifestReceiver";
     private static final String DYNAMIC_RECEIVER = "DynamicReceiver";
-    private static final String ACTION_GET_COUNTERS =
-            "com.android.cts.net.hostside.app2.action.GET_COUNTERS";
-    private static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS =
-            "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS";
-    private static final String ACTION_CHECK_NETWORK =
-            "com.android.cts.net.hostside.app2.action.CHECK_NETWORK";
+
     private static final String ACTION_RECEIVER_READY =
             "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
-    static final String ACTION_SEND_NOTIFICATION =
-            "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION";
     static final String ACTION_SHOW_TOAST =
             "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
-    private static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
-    private static final String EXTRA_RECEIVER_NAME =
-            "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
-    private static final String EXTRA_NOTIFICATION_ID =
-            "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID";
-    private static final String EXTRA_NOTIFICATION_TYPE =
-            "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE";
 
     protected static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
     protected static final String NOTIFICATION_TYPE_DELETE = "DELETE";
@@ -100,6 +86,7 @@
     protected WifiManager mWfm;
     protected int mUid;
     private String mMeteredWifi;
+    private MyServiceClient mServiceClient;
     private boolean mHasWatch;
     private String mDeviceIdleConstantsSetting;
 
@@ -113,6 +100,8 @@
         mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mUid = getUid(TEST_APP2_PKG);
         final int myUid = getUid(mContext.getPackageName());
+        mServiceClient = new MyServiceClient(mContext);
+        mServiceClient.bind();
         mHasWatch = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_WATCH);
         if (mHasWatch) {
@@ -125,6 +114,13 @@
                 + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid));
    }
 
+    @Override
+    protected void tearDown() throws Exception {
+        mServiceClient.unbind();
+
+        super.tearDown();
+    }
+
     protected int getUid(String packageName) throws Exception {
         return mContext.getPackageManager().getPackageUid(packageName, 0);
     }
@@ -180,19 +176,13 @@
     }
 
     protected int getNumberBroadcastsReceived(String receiverName, String action) throws Exception {
-        final Intent intent = new Intent(ACTION_GET_COUNTERS);
-        intent.putExtra(EXTRA_ACTION, ACTION_RESTRICT_BACKGROUND_CHANGED);
-        intent.putExtra(EXTRA_RECEIVER_NAME, receiverName);
-        final String resultData = sendOrderedBroadcast(intent);
-        assertNotNull("timeout waiting for ordered broadcast result", resultData);
-        return Integer.valueOf(resultData);
+        return mServiceClient.getCounters(receiverName, action);
     }
 
     protected void assertRestrictBackgroundStatus(int expectedStatus) throws Exception {
-        final Intent intent = new Intent(ACTION_GET_RESTRICT_BACKGROUND_STATUS);
-        final String resultData = sendOrderedBroadcast(intent);
-        assertNotNull("timeout waiting for ordered broadcast result", resultData);
-        final String actualStatus = toString(Integer.parseInt(resultData));
+        final String status = mServiceClient.getRestrictBackgroundStatus();
+        assertNotNull("didn't get API status from app2", status);
+        final String actualStatus = toString(Integer.parseInt(status));
         assertEquals("wrong status", toString(expectedStatus), actualStatus);
     }
 
@@ -338,15 +328,15 @@
      * @return error message with the mismatch (or empty if assertion passed).
      */
     private String checkNetworkAccess(boolean expectAvailable) throws Exception {
-        String resultData = sendOrderedBroadcast(new Intent(ACTION_CHECK_NETWORK));
+        final String resultData = mServiceClient.checkNetworkStatus();
         if (resultData == null) {
-            return "timeout waiting for ordered broadcast";
+            return "did not get network status from app2";
         }
         // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
         final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
         assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check
-        final State state = State.valueOf(parts[0]);
-        final DetailedState detailedState = DetailedState.valueOf(parts[1]);
+        final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]);
+        final DetailedState detailedState = parts[1].equals("null") ? null : DetailedState.valueOf(parts[1]);
         final boolean connected = Boolean.valueOf(parts[2]);
         final String connectionCheckDetails = parts[3];
         final String networkInfo = parts[4];
@@ -552,6 +542,9 @@
     protected void addRestrictBackgroundWhitelist(int uid) throws Exception {
         executeShellCommand("cmd netpolicy add restrict-background-whitelist " + uid);
         assertRestrictBackgroundWhitelist(uid, true);
+        // UID policies live by the Highlander rule: "There can be only one".
+        // Hence, if app is whitelisted, it should not be blacklisted.
+        assertRestrictBackgroundBlacklist(uid, false);
     }
 
     protected void removeRestrictBackgroundWhitelist(int uid) throws Exception {
@@ -566,6 +559,9 @@
     protected void addRestrictBackgroundBlacklist(int uid) throws Exception {
         executeShellCommand("cmd netpolicy add restrict-background-blacklist " + uid);
         assertRestrictBackgroundBlacklist(uid, true);
+        // UID policies live by the Highlander rule: "There can be only one".
+        // Hence, if app is blacklisted, it should not be whitelisted.
+        assertRestrictBackgroundWhitelist(uid, false);
     }
 
     protected void removeRestrictBackgroundBlacklist(int uid) throws Exception {
@@ -698,9 +694,10 @@
      * {@link #runDeviceTests(String, String)} is executed.
      */
     protected void registerBroadcastReceiver() throws Exception {
-        executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService");
+        mServiceClient.registerBroadcastReceiver();
+
         // Wait until receiver is ready.
-        final int maxTries = 5;
+        final int maxTries = 10;
         for (int i = 1; i <= maxTries; i++) {
             final String message =
                     sendOrderedBroadcast(new Intent(ACTION_RECEIVER_READY), SECOND_IN_MS);
@@ -785,13 +782,10 @@
                 + "--receiver-foreground --receiver-registered-only");
     }
 
-    protected void sendNotification(int notificationId, String notificationType) {
-        final Intent intent = new Intent(ACTION_SEND_NOTIFICATION);
-        intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
-        intent.putExtra(EXTRA_NOTIFICATION_TYPE, notificationType);
-        Log.d(TAG, "Sending notification broadcast (id=" + notificationId + ", type="
-                + notificationType + ": " + intent);
-        mContext.sendBroadcast(intent);
+    protected void sendNotification(int notificationId, String notificationType) throws Exception {
+        Log.d(TAG, "Sending notification broadcast (id=" + notificationId
+                + ", type=" + notificationType);
+        mServiceClient.sendNotification(notificationId, notificationType);
     }
 
     protected String showToast() {
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index 881b3b4..7ca302f 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -133,26 +133,34 @@
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
         assertsForegroundAlwaysHasNetworkAccess();
+        assertRestrictBackgroundChangedReceived(1);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
-        // Make sure blacklist prevails over whitelist.
+        // UID policies live by the Highlander rule: "There can be only one".
+        // Hence, if app is whitelisted, it should not be blacklisted anymore.
         setRestrictBackground(true);
         assertRestrictBackgroundChangedReceived(2);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
         addRestrictBackgroundWhitelist(mUid);
         assertRestrictBackgroundChangedReceived(3);
-        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
 
         // Check status after removing blacklist.
+        // ...re-enables first
+        addRestrictBackgroundBlacklist(mUid);
+        assertRestrictBackgroundChangedReceived(4);
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
+        assertsForegroundAlwaysHasNetworkAccess();
+        // ... remove blacklist - access's still rejected because Data Saver is on
         removeRestrictBackgroundBlacklist(mUid);
         assertRestrictBackgroundChangedReceived(4);
-        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
+        assertsForegroundAlwaysHasNetworkAccess();
+        // ... finally, disable Data Saver
         setRestrictBackground(false);
         assertRestrictBackgroundChangedReceived(5);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
-
         assertsForegroundAlwaysHasNetworkAccess();
-        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
     }
 
     public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception {
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java
new file mode 100644
index 0000000..ff05d8c
--- /dev/null
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/MyServiceClient.java
@@ -0,0 +1,101 @@
+/*
+ * 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.net.hostside;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.cts.net.hostside.IMyService;
+
+import java.io.FileDescriptor;
+
+public class MyServiceClient {
+    private static final int TIMEOUT_MS = 5000;
+    private static final String PACKAGE = MyServiceClient.class.getPackage().getName();
+    private static final String APP2_PACKAGE = PACKAGE + ".app2";
+    private static final String SERVICE_NAME = APP2_PACKAGE + ".MyService";
+
+    private Context mContext;
+    private ServiceConnection mServiceConnection;
+    private IMyService mService;
+
+    public MyServiceClient(Context context) {
+        mContext = context;
+    }
+
+    public void bind() {
+        if (mService != null) {
+            throw new IllegalStateException("Already bound");
+        }
+
+        final ConditionVariable cv = new ConditionVariable();
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                mService = IMyService.Stub.asInterface(service);
+                cv.open();
+            }
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                mService = null;
+            }
+        };
+
+        final Intent intent = new Intent();
+        intent.setComponent(new ComponentName(APP2_PACKAGE, SERVICE_NAME));
+        // Needs to use BIND_ALLOW_OOM_MANAGEMENT and BIND_NOT_FOREGROUND so app2 does not run in
+        // the same process state as app
+        mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE
+                | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_FOREGROUND);
+        cv.block(TIMEOUT_MS);
+        if (mService == null) {
+            throw new IllegalStateException(
+                    "Could not bind to MyService service after " + TIMEOUT_MS + "ms");
+        }
+    }
+
+    public void unbind() {
+        if (mService != null) {
+            mContext.unbindService(mServiceConnection);
+        }
+    }
+
+    public void registerBroadcastReceiver() throws RemoteException {
+        mService.registerBroadcastReceiver();
+    }
+
+    public int getCounters(String receiverName, String action) throws RemoteException {
+        return mService.getCounters(receiverName, action);
+    }
+
+    public String checkNetworkStatus() throws RemoteException {
+        return mService.checkNetworkStatus();
+    }
+
+    public String getRestrictBackgroundStatus() throws RemoteException {
+        return mService.getRestrictBackgroundStatus();
+    }
+
+    public void sendNotification(int notificationId, String notificationType) throws RemoteException {
+        mService.sendNotification(notificationId, notificationType);
+    }
+}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java
index e07c0f5..dc9a630 100644
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -26,27 +26,13 @@
     // AbstractRestrictBackgroundNetworkTestCase.java
     static final String MANIFEST_RECEIVER = "ManifestReceiver";
     static final String DYNAMIC_RECEIVER = "DynamicReceiver";
-    static final String ACTION_GET_COUNTERS =
-            "com.android.cts.net.hostside.app2.action.GET_COUNTERS";
-    static final String ACTION_GET_RESTRICT_BACKGROUND_STATUS =
-            "com.android.cts.net.hostside.app2.action.GET_RESTRICT_BACKGROUND_STATUS";
-    static final String ACTION_CHECK_NETWORK =
-            "com.android.cts.net.hostside.app2.action.CHECK_NETWORK";
+
     static final String ACTION_RECEIVER_READY =
             "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
     static final String ACTION_FINISH_ACTIVITY =
             "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
-    static final String ACTION_SEND_NOTIFICATION =
-            "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION";
     static final String ACTION_SHOW_TOAST =
             "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
-    static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
-    static final String EXTRA_RECEIVER_NAME =
-            "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
-    static final String EXTRA_NOTIFICATION_ID =
-            "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID";
-    static final String EXTRA_NOTIFICATION_TYPE =
-            "com.android.cts.net.hostside.app2.extra.NOTIFICATION_TYPE";
 
     static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
     static final String NOTIFICATION_TYPE_DELETE = "DELETE";
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 733c3aa..f59cba1 100644
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -18,16 +18,8 @@
 
 import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
 
-import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK;
-import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS;
-import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS;
 import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
-import static com.android.cts.net.hostside.app2.Common.ACTION_SEND_NOTIFICATION;
 import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST;
-import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION;
-import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_ID;
-import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_TYPE;
-import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME;
 import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
 import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION;
 import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE;
@@ -56,14 +48,12 @@
 
 import java.net.HttpURLConnection;
 import java.net.URL;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Receiver used to:
  * <ol>
- * <li>Stored received RESTRICT_BACKGROUND_CHANGED broadcasts in a shared preference.
- * <li>Returned the number of RESTRICT_BACKGROUND_CHANGED broadcasts in an ordered broadcast.
+ *   <li>Count number of {@code RESTRICT_BACKGROUND_CHANGED} broadcasts received.
+ *   <li>Show a toast.
  * </ol>
  */
 public class MyBroadcastReceiver extends BroadcastReceiver {
@@ -89,23 +79,11 @@
             case ACTION_RESTRICT_BACKGROUND_CHANGED:
                 increaseCounter(context, action);
                 break;
-            case ACTION_GET_COUNTERS:
-                setResultDataFromCounter(context, intent);
-                break;
-            case ACTION_GET_RESTRICT_BACKGROUND_STATUS:
-                getRestrictBackgroundStatus(context, intent);
-                break;
-            case ACTION_CHECK_NETWORK:
-                checkNetwork(context, intent);
-                break;
             case ACTION_RECEIVER_READY:
                 final String message = mName + " is ready to rumble";
                 Log.d(TAG, message);
                 setResultData(message);
                 break;
-            case ACTION_SEND_NOTIFICATION:
-                sendNotification(context, intent);
-                break;
             case ACTION_SHOW_TOAST:
                 showToast(context);
                 break;
@@ -114,14 +92,20 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "[MyBroadcastReceiver: mName=" + mName + "]";
+    }
+
     private void increaseCounter(Context context, String action) {
-        final SharedPreferences prefs = context.getSharedPreferences(mName, Context.MODE_PRIVATE);
+        final SharedPreferences prefs = context.getApplicationContext()
+                .getSharedPreferences(mName, Context.MODE_PRIVATE);
         final int value = prefs.getInt(action, 0) + 1;
         Log.d(TAG, "increaseCounter('" + action + "'): setting '" + mName + "' to " + value);
         prefs.edit().putInt(action, value).apply();
     }
 
-    private int getCounter(Context context, String action, String receiverName) {
+    static int getCounter(Context context, String action, String receiverName) {
         final SharedPreferences prefs = context.getSharedPreferences(receiverName,
                 Context.MODE_PRIVATE);
         final int value = prefs.getInt(action, 0);
@@ -129,29 +113,14 @@
         return value;
     }
 
-    private void getRestrictBackgroundStatus(Context context, Intent intent) {
+    static String getRestrictBackgroundStatus(Context context) {
         final ConnectivityManager cm = (ConnectivityManager) context
                 .getSystemService(Context.CONNECTIVITY_SERVICE);
         final int apiStatus = cm.getRestrictBackgroundStatus();
         Log.d(TAG, "getRestrictBackgroundStatus: returning " + apiStatus);
-        setResultData(Integer.toString(apiStatus));
+        return String.valueOf(apiStatus);
     }
 
-    private void checkNetwork(final Context context, Intent intent) {
-        final ConnectivityManager cm = (ConnectivityManager) context
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-
-        String netStatus = null;
-        try {
-            netStatus = checkNetworkStatus(context, cm);
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Timeout checking network status");
-        }
-        Log.d(TAG, "checkNetwork(): returning " + netStatus);
-        setResultData(netStatus);
-    }
-
-
     private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
     /**
      * Checks whether the network is available and return a string which can then be send as a
@@ -182,71 +151,53 @@
      * </code></pre>
      *
      */
-    private String checkNetworkStatus(final Context context, final ConnectivityManager cm)
-            throws InterruptedException {
-        final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
-        new Thread(new Runnable() {
-
-            @Override
-            public void run() {
-                // TODO: connect to a hostside server instead
-                final String address = "http://example.com";
-                final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
-                Log.d(TAG, "Running checkNetworkStatus() on thread "
-                        + Thread.currentThread().getName() + " for UID " + getUid(context)
-                        + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
-                boolean checkStatus = false;
-                String checkDetails = "N/A";
-                try {
-                    final URL url = new URL(address);
-                    final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-                    conn.setReadTimeout(NETWORK_TIMEOUT_MS);
-                    conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
-                    conn.setRequestMethod("GET");
-                    conn.setDoInput(true);
-                    conn.connect();
-                    final int response = conn.getResponseCode();
-                    checkStatus = true;
-                    checkDetails = "HTTP response for " + address + ": " + response;
-                } catch (Exception e) {
-                    checkStatus = false;
-                    checkDetails = "Exception getting " + address + ": " + e;
-                }
-                Log.d(TAG, checkDetails);
-                final String status = String.format(NETWORK_STATUS_TEMPLATE,
-                        networkInfo.getState().name(), networkInfo.getDetailedState().name(),
-                        Boolean.toString(checkStatus), checkDetails, networkInfo);
-                Log.d(TAG, "Offering " + status);
-                result.offer(status);
-            }
-        }, mName).start();
-        return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS);
-    }
-
-    private void setResultDataFromCounter(Context context, Intent intent) {
-        final String action = intent.getStringExtra(EXTRA_ACTION);
-        if (action == null) {
-            Log.e(TAG, "Missing extra '" + EXTRA_ACTION + "' on " + intent);
-            return;
+    // TODO: now that it uses Binder, it counl return a Bundle with the data parts instead...
+    static String checkNetworkStatus(Context context) {
+        final ConnectivityManager cm =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        // TODO: connect to a hostside server instead
+        final String address = "http://example.com";
+        final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+        Log.d(TAG, "Running checkNetworkStatus() on thread "
+                + Thread.currentThread().getName() + " for UID " + getUid(context)
+                + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
+        boolean checkStatus = false;
+        String checkDetails = "N/A";
+        try {
+            final URL url = new URL(address);
+            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setReadTimeout(NETWORK_TIMEOUT_MS);
+            conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
+            conn.setRequestMethod("GET");
+            conn.setDoInput(true);
+            conn.connect();
+            final int response = conn.getResponseCode();
+            checkStatus = true;
+            checkDetails = "HTTP response for " + address + ": " + response;
+        } catch (Exception e) {
+            checkStatus = false;
+            checkDetails = "Exception getting " + address + ": " + e;
         }
-        final String receiverName = intent.getStringExtra(EXTRA_RECEIVER_NAME);
-        if (receiverName == null) {
-            Log.e(TAG, "Missing extra '" + EXTRA_RECEIVER_NAME + "' on " + intent);
-            return;
+        Log.d(TAG, checkDetails);
+        final String state, detailedState;
+        if (networkInfo != null) {
+            state = networkInfo.getState().name();
+            detailedState = networkInfo.getDetailedState().name();
+        } else {
+            state = detailedState = "null";
         }
-        final int counter = getCounter(context, action, receiverName);
-        setResultData(String.valueOf(counter));
+        final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
+                Boolean.valueOf(checkStatus), checkDetails, networkInfo);
+        Log.d(TAG, "Offering " + status);
+        return status;
     }
 
     /**
      * Sends a system notification containing actions with pending intents to launch the app's
      * main activitiy or service.
      */
-    private void sendNotification(Context context, Intent intent) {
-        final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
-        final String notificationType = intent.getStringExtra(EXTRA_NOTIFICATION_TYPE);
-        Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType
-                + ", intent=" + intent);
+    static void sendNotification(Context context, int notificationId, String notificationType ) {
+        Log.d(TAG, "sendNotification: id=" + notificationId + ", type=" + notificationType);
         final Intent serviceIntent = new Intent(context, MyService.class);
         final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent,
                 notificationId);
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
index e6454c7..9c19e50 100644
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
@@ -24,27 +24,74 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.os.IBinder;
+import android.os.Looper;
 import android.util.Log;
+import android.widget.Toast;
+
+import com.android.cts.net.hostside.IMyService;
 
 /**
  * Service used to dynamically register a broadcast receiver.
  */
 public class MyService extends Service {
 
+    private MyBroadcastReceiver mReceiver;
+
+    // TODO: move MyBroadcast static functions here - they were kept there to make git diff easier.
+
+    private IMyService.Stub mBinder =
+        new IMyService.Stub() {
+
+        @Override
+        public void registerBroadcastReceiver() {
+            if (mReceiver != null) {
+                Log.d(TAG, "receiver already registered: " + mReceiver);
+                return;
+            }
+            final Context context = getApplicationContext();
+            mReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER);
+            context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY));
+            context.registerReceiver(mReceiver,
+                    new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED));
+            Log.d(TAG, "receiver registered");
+        }
+
+        @Override
+        public int getCounters(String receiverName, String action) {
+            return MyBroadcastReceiver.getCounter(getApplicationContext(), action, receiverName);
+        }
+
+        @Override
+        public String checkNetworkStatus() {
+            return MyBroadcastReceiver.checkNetworkStatus(getApplicationContext());
+        }
+
+        @Override
+        public String getRestrictBackgroundStatus() {
+            return MyBroadcastReceiver.getRestrictBackgroundStatus(getApplicationContext());
+        }
+
+        @Override
+        public void sendNotification(int notificationId, String notificationType) {
+            MyBroadcastReceiver
+                .sendNotification(getApplicationContext(), notificationId, notificationType);
+        }
+      };
+
     @Override
     public IBinder onBind(Intent intent) {
-        return null;
+        return mBinder;
     }
 
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.d(TAG, "MyService.onStartCommand: " + intent);
-        final Context context = getApplicationContext();
-        final MyBroadcastReceiver myReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER);
-        context.registerReceiver(myReceiver, new IntentFilter(ACTION_RECEIVER_READY));
-        context.registerReceiver(myReceiver, new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED));
-        Log.d(TAG, "receiver registered");
-        return START_STICKY;
+    public void onDestroy() {
+        if (mReceiver != null) {
+            Log.d(TAG, "onDestroy(): unregistering " + mReceiver);
+            getApplicationContext().unregisterReceiver(mReceiver);
+        }
+
+        super.onDestroy();
     }
 }
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
index 6642512..f3d7dbd 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.net;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
@@ -80,7 +80,8 @@
 
     protected void installPackage(String apk) throws FileNotFoundException,
             DeviceNotAvailableException {
-        assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, apk), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false));
     }
 
     protected void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/numberblocking/Android.mk b/hostsidetests/numberblocking/Android.mk
index bf2d045..42c7169 100644
--- a/hostsidetests/numberblocking/Android.mk
+++ b/hostsidetests/numberblocking/Android.mk
@@ -25,9 +25,7 @@
 
 LOCAL_MODULE := CtsHostsideNumberBlockingTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/numberblocking/AndroidTest.xml b/hostsidetests/numberblocking/AndroidTest.xml
index 4d06e9d..c7597c4 100644
--- a/hostsidetests/numberblocking/AndroidTest.xml
+++ b/hostsidetests/numberblocking/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsHostsideNumberBlockingTestCases.jar" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
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/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
index 11455a0..5e1a0ec 100644
--- a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
+++ b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.numberblocking.hostside;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.tradefed.build.IBuildInfo;
@@ -149,7 +149,8 @@
 
     private void installTestAppForUser(int userId) throws Exception {
         LogUtil.CLog.logAndDisplay(Log.LogLevel.INFO, "Installing test app for user: " + userId);
-        File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        File testAppFile = buildHelper.getTestFile(TEST_APK);
         String installResult = getDevice().installPackageForUser(
                 testAppFile, true /*reinstall*/, userId);
         assertNull(String.format(
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
index bb5154f..e54703e 100644
--- a/hostsidetests/os/Android.mk
+++ b/hostsidetests/os/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.os
 
diff --git a/hostsidetests/os/AndroidTest.xml b/hostsidetests/os/AndroidTest.xml
index ff6e6b0..5563021 100644
--- a/hostsidetests/os/AndroidTest.xml
+++ b/hostsidetests/os/AndroidTest.xml
@@ -17,8 +17,10 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsDeviceOsTestApp.apk" />
+        <option name="test-file-name" value="CtsHostProcfsTestApp.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsOsHostTestCases.jar" />
+        <option name="runtime-hint" value="12m30s" />
     </test>
 </configuration>
diff --git a/hostsidetests/os/src/android/os/cts/OsHostTests.java b/hostsidetests/os/src/android/os/cts/OsHostTests.java
index 200ef40..3b2e027 100644
--- a/hostsidetests/os/src/android/os/cts/OsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/OsHostTests.java
@@ -16,8 +16,7 @@
 
 package android.os.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.ITestDevice;
@@ -25,6 +24,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -145,6 +145,7 @@
      * Helper: find a test apk
      */
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 }
diff --git a/hostsidetests/os/src/android/os/cts/ProcfsHostTests.java b/hostsidetests/os/src/android/os/cts/ProcfsHostTests.java
new file mode 100644
index 0000000..f564df1
--- /dev/null
+++ b/hostsidetests/os/src/android/os/cts/ProcfsHostTests.java
@@ -0,0 +1,211 @@
+/*
+ * 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.os.cts;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ProcfsHostTests extends DeviceTestCase {
+  // We need a running test app to test /proc/[PID]/* files.
+  private static final String TEST_APP_PACKAGE = "android.os.procfs";
+  private static final String TEST_APP_CLASS = "ProcfsTest";
+  private static final String START_TEST_APP_COMMAND =
+      String.format(
+          "am start -W -a android.intent.action.MAIN -n %s/%s.%s",
+          TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_APP_CLASS);
+  private static final String TEST_APP_LOG_REGEXP = "PID is (\\d+)";
+  private static final Pattern TEST_APP_LOG_PATTERN = Pattern.compile(TEST_APP_LOG_REGEXP);
+
+  private static final String PROC_STAT_PATH = "/proc/stat";
+  private static final String PROC_STAT_READ_COMMAND = "head -1 ";
+  // Verfies the first line of /proc/stat includes 'cpu' followed by 10 numbers.
+  // The 10th column was introduced in kernel version 2.6.33.
+  private static final String PROC_STAT_REGEXP = "cpu ( \\d+){10,10}";
+  private static final Pattern PROC_STAT_PATTERN = Pattern.compile(PROC_STAT_REGEXP);
+
+  // In Linux, a process's stat file (/proc/[PID]/stat) and a thread's (/proc/[PID]/task/[TID]/stat)
+  // share the same format. We want to verify these stat files include pid (a number), file name
+  // (a string in parentheses), and state (a character), followed by 41 or more numbers.
+  // The 44th column was introduced in kernel version 2.6.24.
+  private static final String PID_TID_STAT_REGEXP = "\\d+ \\(.*\\) [A-Za-z]( [\\d-]+){41,}";
+  private static final Pattern PID_TID_STAT_PATTERN = Pattern.compile(PID_TID_STAT_REGEXP);
+
+  // Interval in milliseconds between two sequential reads when checking whether a file is being
+  // updated.
+  private static final long UPDATE_READ_INTERVAL_MS = 100;
+  // Max time in milliseconds waiting for a file being update. If a file's content does not change
+  // during the period, it is not considered being actively updated.
+  private static final long UPDATE_MAX_WAIT_TIME_MS = 5000;
+
+  // A reference to the device under test, which gives us a handle to run commands.
+  private ITestDevice mDevice;
+
+  // Process ID of test app.
+  //
+  // Technically it doesn't need to be static in the master branch because a single object will be
+  // created to run different tests (calling various test* methods). However, this piece of code
+  // may be ported to older branches (e.g., mnc-dev) to test compatibility where a single object
+  // is created for each test. In these older branches it is useful to make this field static, so
+  // we don't have to kill and restart the app between tests.
+  private static int mTestAppPid = -1;
+
+  @Override
+  protected synchronized void setUp() throws Exception {
+    super.setUp();
+    mDevice = getDevice();
+    // Start the test app if not already.
+    if (mTestAppPid == -1) {
+      mTestAppPid = startTestApp();
+    }
+  }
+
+  /**
+   * Tests that host, as the shell user, can read /proc/stat file, the file is in a reasonable
+   * shape, and the file is being updated.
+   *
+   * @throws Exception
+   */
+  public void testProcStat() throws Exception {
+    testFile(PROC_STAT_PATH, PROC_STAT_READ_COMMAND, PROC_STAT_PATTERN);
+  }
+
+  /**
+   * Tests that host, as the shell user, can read /proc/[PID]/stat file, the file is in a reasonable
+   * shape, and the file is being updated.
+   *
+   * @throws Exception
+   */
+  public void testProcPidStat() throws Exception {
+    testFile("/proc/" + mTestAppPid + "/stat", "cat ", PID_TID_STAT_PATTERN);
+  }
+
+  /**
+   * Tests that host, as the shell user, can read /proc/[PID]/task/[TID]/stat files, and the files
+   * are in a reasonable shape. Also verifies there are more than one such files (a typical Android
+   * app easily has 10+ threads including those from Android runtime).
+   *
+   * <p>Note we are not testing whether these files are being updated because some Android runtime
+   * threads may be idling for a while so it is hard to test whether they are being updated within a
+   * limited time window (such as 'Profile Saver' thread in art/runtime/jit/profile_saver.h and
+   * 'JDWP' thread).
+   *
+   * @throws Exception
+   */
+  public void testProcTidStat() throws Exception {
+    int[] tids = lookForTidsInProcess(mTestAppPid);
+    assertTrue("/proc/" + mTestAppPid + "/task/ includes < 2 threads", tids.length >= 2);
+    for (int tid : tids) {
+      readAndCheckFile(
+          "/proc/" + mTestAppPid + "/task/" + tid + "/stat", "cat ", PID_TID_STAT_PATTERN);
+    }
+  }
+
+  /**
+   * Tests that host, as the shell user, can read the file at the given absolute path by using the
+   * given read command, the file is in the expected format pattern, and the file is being updated.
+   *
+   * @throws Exception
+   */
+  private void testFile(String absolutePath, String readCommand, Pattern pattern) throws Exception {
+    String content = readAndCheckFile(absolutePath, readCommand, pattern);
+
+    // Check the file is being updated.
+    long waitTime = 0;
+    while (waitTime < UPDATE_MAX_WAIT_TIME_MS) {
+      java.lang.Thread.sleep(UPDATE_READ_INTERVAL_MS);
+      waitTime += UPDATE_READ_INTERVAL_MS;
+      String newContent = readAndCheckFile(absolutePath, readCommand, pattern);
+      if (!newContent.equals(content)) {
+        return;
+      }
+    }
+    assertTrue(absolutePath + " not actively updated. Content: \"" + content + "\"", false);
+  }
+
+  /**
+   * Starts the test app and returns its process ID.
+   *
+   * @throws Exception
+   */
+  private int startTestApp() throws Exception {
+    // Clear logcat.
+    mDevice.executeAdbCommand("logcat", "-c");
+    // Start the app activity and wait for it to complete.
+    String results = mDevice.executeShellCommand(START_TEST_APP_COMMAND);
+    // Dump logcat.
+    String logs =
+        mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", TEST_APP_CLASS + ":I", "*:S");
+    // Search for string contianing the process ID.
+    int pid = -1;
+    Scanner in = new Scanner(logs);
+    while (in.hasNextLine()) {
+      String line = in.nextLine();
+      if (line.startsWith("I/" + TEST_APP_CLASS)) {
+        Matcher m = TEST_APP_LOG_PATTERN.matcher(line.split(":")[1].trim());
+        if (m.matches()) {
+          pid = Integer.parseInt(m.group(1));
+        }
+      }
+    }
+    in.close();
+    // Assert test app's pid is captured from log.
+    assertTrue(
+        "Test app PID not captured. results = \"" + results + "\"; logs = \"" + logs + "\"",
+        pid > 0);
+    return pid;
+  }
+
+  /**
+   * Reads and returns the file content at the given absolute path by using the given read command,
+   * after ensuring it is in the expected pattern.
+   *
+   * @throws Exception
+   */
+  private String readAndCheckFile(String absolutePath, String readCommand, Pattern pattern)
+      throws Exception {
+    String readResult = getDevice().executeShellCommand(readCommand + absolutePath);
+    assertNotNull("Unexpected empty file " + absolutePath, readResult);
+    readResult = readResult.trim();
+    assertTrue(
+        "Unexpected format of " + absolutePath + ": \"" + readResult + "\"",
+        pattern.matcher(readResult).matches());
+    return readResult;
+  }
+
+  /**
+   * Returns the thread IDs in a given process.
+   *
+   * @throws Exception
+   */
+  private int[] lookForTidsInProcess(int pid) throws Exception {
+    String taskPath = "/proc/" + pid + "/task";
+    // Explicitly pass -1 to 'ls' to get one per line rather than relying on adb not allocating a
+    // tty.
+    String lsOutput = getDevice().executeShellCommand("ls -1 " + taskPath);
+    assertNotNull("Unexpected empty directory " + taskPath, lsOutput);
+
+    String[] threads = lsOutput.split("\\s+");
+    int[] tids = new int[threads.length];
+    for (int i = 0; i < threads.length; i++) {
+      tids[i] = Integer.parseInt(threads[i]);
+    }
+    return tids;
+  }
+}
diff --git a/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk b/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk
new file mode 100644
index 0000000..f7b98c3
--- /dev/null
+++ b/hostsidetests/os/test-apps/ProcfsTestApp/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsHostProcfsTestApp
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/test-apps/ProcfsTestApp/AndroidManifest.xml b/hostsidetests/os/test-apps/ProcfsTestApp/AndroidManifest.xml
new file mode 100755
index 0000000..8a7463a
--- /dev/null
+++ b/hostsidetests/os/test-apps/ProcfsTestApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.os.procfs">
+
+    <application>
+        <activity android:name=".ProcfsTest"
+                android:exported="true" />
+    </application>
+</manifest>
+
diff --git a/hostsidetests/os/test-apps/ProcfsTestApp/src/android/os/procfs/ProcfsTest.java b/hostsidetests/os/test-apps/ProcfsTestApp/src/android/os/procfs/ProcfsTest.java
new file mode 100644
index 0000000..bf4a873
--- /dev/null
+++ b/hostsidetests/os/test-apps/ProcfsTestApp/src/android/os/procfs/ProcfsTest.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.os.procfs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class ProcfsTest extends Activity {
+  private static final String TAG = ProcfsTest.class.getSimpleName();
+
+  @Override
+  public void onCreate(Bundle icicle) {
+    super.onCreate(icicle);
+    // Log pid to Logcat so the test knows who we are.
+    int pid = android.os.Process.myPid();
+    Log.i(TAG, "PID is " + pid);
+  }
+}
diff --git a/hostsidetests/retaildemo/Android.mk b/hostsidetests/retaildemo/Android.mk
index 0aa5ee1..ba106cc 100644
--- a/hostsidetests/retaildemo/Android.mk
+++ b/hostsidetests/retaildemo/Android.mk
@@ -22,7 +22,10 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := \
+    tools-common-prebuilt \
+    cts-tradefed \
+    tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.retaildemo
 
diff --git a/hostsidetests/retaildemo/app/Android.mk b/hostsidetests/retaildemo/app/Android.mk
index e91e1da..dde24d2 100644
--- a/hostsidetests/retaildemo/app/Android.mk
+++ b/hostsidetests/retaildemo/app/Android.mk
@@ -21,7 +21,9 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -30,6 +32,6 @@
 
 LOCAL_PACKAGE_NAME := CtsRetailDemoApp
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoModeUiAutomationTest.java b/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoModeUiAutomationTest.java
new file mode 100644
index 0000000..9e225ea
--- /dev/null
+++ b/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoModeUiAutomationTest.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.retaildemo;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import android.os.PowerManager;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class DemoModeUiAutomationTest {
+    private static final String RETAIL_DEMO_PKG = "com.android.retaildemo";
+
+    private static final long LAUNCH_TIMEOUT_MS = 5000; // 5 sec
+
+    private static final long UI_TIMEOUT_MS = 4000; // 4 sec
+
+    private static final String RESET_NOTIFICATION_TEXT = "Tap to reset device";
+    private UiDevice mUiDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @Test
+    public void testResetNotification() {
+        startDemoSession();
+        mUiDevice.openNotification();
+        mUiDevice.wait(Until.hasObject(By.text(RESET_NOTIFICATION_TEXT)), UI_TIMEOUT_MS);
+        UiObject2 resetNotification = mUiDevice.findObject(By.text(RESET_NOTIFICATION_TEXT));
+        assertNotNull("Notification to reset demo mode not found", resetNotification);
+        resetNotification.click();
+    }
+
+    @Test
+    public void testUserRestrictions_inDemoUser() throws Exception {
+        final UserManager um = InstrumentationRegistry.getContext().getSystemService(
+                UserManager.class);
+        final String[] expectedRestrictions = new String[] {
+                UserManager.DISALLOW_CONFIG_WIFI,
+                UserManager.DISALLOW_CONFIG_BLUETOOTH,
+                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
+                UserManager.DISALLOW_USB_FILE_TRANSFER,
+                UserManager.DISALLOW_MODIFY_ACCOUNTS
+        };
+        final ArrayList<String> missingRestrictions = new ArrayList<>();
+        for (String restriction : expectedRestrictions) {
+            if (!um.hasUserRestriction(restriction)) {
+                missingRestrictions.add(restriction);
+            }
+        }
+        assertTrue("Restrictions should be set: " + missingRestrictions,
+                missingRestrictions.isEmpty());
+        assertFalse("Restriction should not be set: " + UserManager.DISALLOW_OUTGOING_CALLS,
+                um.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS));
+    }
+
+    @Test
+    public void testUserRestrictions_inSystemUser() throws Exception {
+        final UserManager um = InstrumentationRegistry.getContext().getSystemService(
+                UserManager.class);
+        assertTrue(UserManager.DISALLOW_SAFE_BOOT + " should be set in system user.",
+                um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT));
+    }
+
+    @Test
+    public void testScreenIsInteractive() throws Exception {
+        final PowerManager pm = InstrumentationRegistry.getContext().getSystemService(
+                PowerManager.class);
+        assertTrue(pm.isInteractive());
+    }
+
+    private void startDemoSession() {
+        final int h = mUiDevice.getDisplayHeight();
+        final int w = mUiDevice.getDisplayWidth();
+        final Random random = new Random(0);
+        mUiDevice.click(random.nextInt(w), random.nextInt(h));
+    }
+
+    @Test
+    public void testRetailDemoPkgLaunched() {
+        if (!Boolean.TRUE.equals(mUiDevice.wait(
+                Until.hasObject(By.pkg(RETAIL_DEMO_PKG).depth(0)), LAUNCH_TIMEOUT_MS))) {
+            fail("Retail demo package is not started");
+        }
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoUserTest.java b/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoUserTest.java
index bb20b1a..b3aa00b 100644
--- a/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoUserTest.java
+++ b/hostsidetests/retaildemo/app/src/com/android/cts/retaildemo/DemoUserTest.java
@@ -18,7 +18,6 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.content.Context;
 import android.os.UserManager;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
diff --git a/hostsidetests/retaildemo/src/android/host/retaildemo/BaseTestCase.java b/hostsidetests/retaildemo/src/android/host/retaildemo/BaseTestCase.java
index 5033b6d..f326e8f 100644
--- a/hostsidetests/retaildemo/src/android/host/retaildemo/BaseTestCase.java
+++ b/hostsidetests/retaildemo/src/android/host/retaildemo/BaseTestCase.java
@@ -34,13 +34,20 @@
 import java.util.Map;
 
 public class BaseTestCase extends DeviceTestCase implements IBuildReceiver {
+    protected static final String RETAIL_DEMO_TEST_APK = "CtsRetailDemoApp.apk";
+
     private static final String RETAIL_DEMO_TEST_PKG = "com.android.cts.retaildemo";
+
     private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
 
+    protected static final int USER_SYSTEM = 0; // From the UserHandle class.
+
+    private static final int FLAG_DEMO = 0x00000200; // From the UserInfo class.
+
     private IBuildInfo mBuildInfo;
     private CompatibilityBuildHelper mBuildHelper;
-
-    private ArrayList<Integer> mTestUsers;
+    protected boolean mSupportsMultiUser;
+    private ArrayList<Integer> mFixedUsers;
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
@@ -52,17 +59,33 @@
     protected void setUp() throws Exception {
         super.setUp();
         assertNotNull(mBuildInfo); // ensure build has been set before test is run.
-        mTestUsers = new ArrayList<>();
+
+        mSupportsMultiUser = getDevice().isMultiUserSupported();
+        mFixedUsers = new ArrayList<>();
+        final int primaryUserId = getDevice().getPrimaryUserId();
+        mFixedUsers.add(primaryUserId);
+        if (primaryUserId != USER_SYSTEM) {
+            mFixedUsers.add(USER_SYSTEM);
+        }
+        getDevice().switchUser(primaryUserId);
+        removeTestUsers();
     }
 
     @Override
     protected void tearDown() throws Exception {
-        for (int userId : mTestUsers) {
-            getDevice().removeUser(userId);
-        }
+        removeTestUsers();
         super.tearDown();
     }
 
+    private void removeTestUsers() throws DeviceNotAvailableException {
+        for (int userId : getDevice().listUsers()) {
+            if (!mFixedUsers.contains(userId)) {
+                getDevice().removeUser(userId);
+            }
+        }
+    }
+
+    // TODO: Update TestDevice class to include this functionality.
     protected int createDemoUser() throws DeviceNotAvailableException, IllegalStateException {
         final String command = "pm create-user --ephemeral --demo "
                 + "TestUser_" + System.currentTimeMillis();
@@ -73,7 +96,6 @@
         if (output.startsWith("Success")) {
             try {
                 int userId = Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
-                mTestUsers.add(userId);
                 return userId;
             } catch (NumberFormatException e) {
                 CLog.e("Failed to parse result: %s", output);
@@ -84,12 +106,98 @@
         throw new IllegalStateException();
     }
 
+    protected void enableDemoMode(boolean enabled) throws DeviceNotAvailableException {
+        getDevice().executeShellCommand("settings put global device_demo_mode "
+                + (enabled ? 1 : 0));
+    }
+
+    protected void setUserInactivityTimeoutMs(long timeoutMs) throws DeviceNotAvailableException {
+        updateTimeoutValue("user_inactivity_timeout_ms", timeoutMs);
+    }
+
+    protected void setWarningDialogTimeoutMs(long timeoutMs) throws DeviceNotAvailableException {
+        updateTimeoutValue("warning_dialog_timeout_ms", timeoutMs);
+    }
+
+    private void updateTimeoutValue(String constant, long timeoutMs)
+            throws DeviceNotAvailableException {
+        final String constantsValue = getRetailDemoModeConstants();
+        final String[] constants = constantsValue.split(",");
+        for (int i = 0; i < constants.length; ++i) {
+            if (constants[i].startsWith(constant)) {
+                constants[i] = constant + "=" + timeoutMs;
+                break;
+            }
+        }
+        setRetailDemoModeConstants(String.join(",", constants));
+    }
+
+    protected void setRetailDemoModeConstants(String constants)
+            throws DeviceNotAvailableException {
+        getDevice().executeShellCommand("settings put global retail_demo_mode_constants " +
+                constants);
+    }
+
+    protected String getRetailDemoModeConstants() throws DeviceNotAvailableException {
+        return getDevice().executeShellCommand("settings get global retail_demo_mode_constants");
+    }
+
+    protected Integer getDemoUserId(ArrayList<Integer> existingDemoUsers)
+            throws DeviceNotAvailableException {
+        ArrayList<String[]> users = tokenizeListUsers();
+        if (users == null) {
+            return null;
+        }
+        for (String[] user : users) {
+            final int flag = Integer.parseInt(user[3], 16);
+            final Integer userId = Integer.parseInt(user[1]);
+            if ((flag & FLAG_DEMO) != 0 && !existingDemoUsers.contains(userId)) {
+                return userId;
+            }
+        }
+        return null;
+    }
+
+    protected boolean isUserUnlocked(int userId) throws DeviceNotAvailableException {
+        final String state = getDevice().executeShellCommand(
+                "cmd activity get-started-user-state " + userId);
+        return state != null && state.startsWith("RUNNING_UNLOCKED");
+    }
+
+    // TODO: Add getDemoUserIds() to TestDevice class to avoid this code duplication.
+    private ArrayList<String[]> tokenizeListUsers() throws DeviceNotAvailableException {
+        String command = "pm list users";
+        String commandOutput = getDevice().executeShellCommand(command);
+        // Extract the id of all existing users.
+        String[] lines = commandOutput.split("\\r?\\n");
+        if (lines.length < 1) {
+            CLog.e("%s should contain at least one line", commandOutput);
+            return null;
+        }
+        if (!lines[0].equals("Users:")) {
+            CLog.e("%s in not a valid output for 'pm list users'", commandOutput);
+            return null;
+        }
+        ArrayList<String[]> users = new ArrayList<>(lines.length - 1);
+        for (int i = 1; i < lines.length; i++) {
+            // Individual user is printed out like this:
+            // \tUserInfo{$id$:$name$:$Integer.toHexString(flags)$} [running]
+            String[] tokens = lines[i].split("\\{|\\}|:");
+            if (tokens.length != 4 && tokens.length != 5) {
+                CLog.e("%s doesn't contain 4 or 5 tokens", lines[i]);
+                return null;
+            }
+            users.add(tokens);
+        }
+        return users;
+    }
+
     protected void installAppAsUser(String appFileName, int userId)
             throws FileNotFoundException, DeviceNotAvailableException {
         CLog.d("Installing app " + appFileName + " for user " + userId);
         File apkFile = new File(mBuildHelper.getTestsDir(), appFileName);
         final String result = getDevice().installPackageForUser(
-                apkFile, true, true, userId, "-t");
+                apkFile, true, true, userId, "-t -r");
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
diff --git a/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeTest.java b/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeTest.java
index 3fdfd72..c9e783b 100644
--- a/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeTest.java
+++ b/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeTest.java
@@ -15,18 +15,14 @@
  */
 package android.host.retaildemo;
 
-import static junit.framework.Assert.assertTrue;
-
 public class DemoModeTest extends BaseTestCase {
-    private static final String RETAIL_DEMO_TEST_APK = "CtsRetailDemoApp.apk";
-
     public void testIsDemoUser_inPrimaryUser() throws Exception {
         assertTrue(runDeviceTestsAsUser(
                 ".DemoUserTest", "testIsDemoUser_failure", getDevice().getPrimaryUserId()));
     }
 
     public void testIsDemoUser_inDemoUser() throws Exception {
-        if (!getDevice().isMultiUserSupported()) {
+        if (!mSupportsMultiUser) {
             return;
         }
         final int demoUserId = createDemoUser();
diff --git a/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeUiAutomationHostTest.java b/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeUiAutomationHostTest.java
new file mode 100644
index 0000000..9e057eb
--- /dev/null
+++ b/hostsidetests/retaildemo/src/android/host/retaildemo/DemoModeUiAutomationHostTest.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 android.host.retaildemo;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+import java.util.ArrayList;
+
+public class DemoModeUiAutomationHostTest extends BaseTestCase {
+    private static final int USER_INACTIVITY_TIMEOUT_MS = 120 * 1000; // 2 min
+
+    private static final int TIMEOUT_DEMO_USER_START_MS = 2000; // 2 sec
+    private static final int CHECK_INTERVAL_DEMO_USER_START_MS = 200; // 0.2 sec
+
+    private static final int TIMEOUT_DEMO_USER_UNLOCK_MS = 4000; // 4 sec
+    private static final int CHECK_INTERVAL_DEMO_USER_UNLOCK_MS = 500; // 0.5 sec
+
+    private static final int TIMEOUT_SCREEN_TURN_ON_ATTRACT_LOOP_MS = 1000; // 1 sec
+    private static final int TIMEOUT_SCREEN_TURN_ON_DEMO_SESSION_MS = 4000; // 4 sec
+
+    private int mStartUserId;
+    private String mStartRetailDemoModeConstants;
+    private ArrayList<Integer> existingDemoUsers;
+    private Integer mCurrentDemoUserId;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        mStartUserId = getDevice().getCurrentUser();
+        existingDemoUsers = new ArrayList<>();
+        // Increase the inactivity timeout so that the demo session is not reset during the test.
+        mStartRetailDemoModeConstants = getRetailDemoModeConstants();
+        setUserInactivityTimeoutMs(USER_INACTIVITY_TIMEOUT_MS);
+        enableDemoMode(true);
+    }
+
+    public void testResetNotification() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        initializeDemoUser();
+        executeDeviceTest("RetailDemoPkg is not launched", "testRetailDemoPkgLaunched");
+        executeDeviceTest("Notification to reset demo mode not found", "testResetNotification");
+
+        if (!awaitDemoSessionStart()) {
+            fail("Demo session is not recreated.");
+        }
+        installAppAsUser(RETAIL_DEMO_TEST_APK, mCurrentDemoUserId);
+        executeDeviceTest("RetailDemoPkg is not launched after session restart",
+                "testRetailDemoPkgLaunched");
+    }
+
+    public void testResetAfterInactivity() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        initializeDemoUser();
+        executeDeviceTest("RetailDemoPkg is not launched", "testRetailDemoPkgLaunched");
+        final long timeoutMs = 15 * 1000; // 15 sec
+        setUserInactivityTimeoutMs(timeoutMs);
+        setWarningDialogTimeoutMs(0);
+        getDevice().executeShellCommand("input tap 1 1"); // Tap to enter demo session.
+        getDevice().executeShellCommand("input keyevent 3"); // Tap home (any user activity is ok)
+        Thread.sleep(timeoutMs);
+
+        if (!awaitDemoSessionStart()) {
+            fail("Demo session is not recreated.");
+        }
+        installAppAsUser(RETAIL_DEMO_TEST_APK, mCurrentDemoUserId);
+        executeDeviceTest("RetailDemoPkg is not launched after session restart",
+                "testRetailDemoPkgLaunched");
+    }
+
+    public void testUserRestrictions() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        initializeDemoUser();
+        executeDeviceTest("User restrictions not set correctly for demo user",
+                "testUserRestrictions_inDemoUser");
+        executeDeviceTestAsUser("User restrictions not set correctly for system user",
+                "testUserRestrictions_inSystemUser", USER_SYSTEM);
+    }
+
+    public void testScreenTurnsOn_attractLoop() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        initializeDemoUser();
+        executeDeviceTest("RetailDemoPkg is not launched", "testRetailDemoPkgLaunched");
+        getDevice().executeShellCommand("input keyevent 26"); // Turn off the screen.
+        // Wait for the screen to turn on.
+        Thread.sleep(TIMEOUT_SCREEN_TURN_ON_ATTRACT_LOOP_MS);
+        // Verify that the screen is turned on.
+        executeDeviceTest("Screen is not turned on automatically during attract loop",
+                "testScreenIsInteractive");
+    }
+
+    public void testScreenTurnsOn_demoSession() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        initializeDemoUser();
+        executeDeviceTest("RetailDemoPkg is not launched", "testRetailDemoPkgLaunched");
+        getDevice().executeShellCommand("input tap 1 1"); // Tap to enter demo session.
+        getDevice().executeShellCommand("input keyevent 26"); // Turn off the screen.
+        // Wait for the screen to turn on.
+        Thread.sleep(TIMEOUT_SCREEN_TURN_ON_DEMO_SESSION_MS);
+        // Verify that the screen is turned on.
+        executeDeviceTest("Screen is not turned on automatically during demo session",
+                "testScreenIsInteractive");
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (!mSupportsMultiUser) {
+            return;
+        }
+        enableDemoMode(false);
+        Thread.sleep(2000 /* 2 sec */); // Wait for the setting to be persisted.
+        getDevice().switchUser(mStartUserId);
+        setRetailDemoModeConstants(mStartRetailDemoModeConstants);
+        super.tearDown();
+    }
+
+    private void initializeDemoUser() throws Exception {
+        // Wait for the demo user to start.
+        if (!awaitDemoSessionStart()) {
+            fail("Demo user is not created");
+        }
+        installAppAsUser(RETAIL_DEMO_TEST_APK, mCurrentDemoUserId);
+        // Wait for the demo user to unlock.
+        if (!awaitDemoUserUnlock()) {
+            fail("Demo user is not unlocked");
+        }
+    }
+
+    private boolean awaitDemoUserUnlock()
+            throws InterruptedException, DeviceNotAvailableException {
+        final long endTime = System.currentTimeMillis() + TIMEOUT_DEMO_USER_UNLOCK_MS;
+        while (!isUserUnlocked(mCurrentDemoUserId)
+                && System.currentTimeMillis() < endTime) {
+            Thread.sleep(CHECK_INTERVAL_DEMO_USER_UNLOCK_MS);
+        }
+        return isUserUnlocked(mCurrentDemoUserId);
+    }
+
+    private boolean awaitDemoSessionStart()
+            throws InterruptedException, DeviceNotAvailableException {
+        final long endTime = System.currentTimeMillis() + TIMEOUT_DEMO_USER_START_MS;
+        while (mStartUserId == getDevice().getCurrentUser()
+                && System.currentTimeMillis() < endTime) {
+            Thread.sleep(CHECK_INTERVAL_DEMO_USER_START_MS);
+        }
+        mCurrentDemoUserId = getDemoUserId(existingDemoUsers);
+        if (mCurrentDemoUserId != null) {
+            existingDemoUsers.add(mCurrentDemoUserId);
+            return true;
+        }
+        return false;
+    }
+
+    private void executeDeviceTest(String msg, String testMethodName) throws Exception {
+        executeDeviceTestAsUser(msg, testMethodName, mCurrentDemoUserId);
+    }
+
+    private void executeDeviceTestAsUser(String msg, String testMethodName, int userId)
+            throws Exception {
+        assertTrue(msg, runDeviceTestsAsUser(".DemoModeUiAutomationTest", testMethodName, userId));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/sample/Android.mk b/hostsidetests/sample/Android.mk
index 8d8a076..bfdaeda 100644
--- a/hostsidetests/sample/Android.mk
+++ b/hostsidetests/sample/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_MODULE := CtsSampleHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/sample/app2/Android.mk b/hostsidetests/sample/app2/Android.mk
new file mode 100644
index 0000000..0900f1f
--- /dev/null
+++ b/hostsidetests/sample/app2/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsSampleDeviceApp2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/sample/app2/AndroidManifest.xml b/hostsidetests/sample/app2/AndroidManifest.xml
new file mode 100644
index 0000000..7d65c30
--- /dev/null
+++ b/hostsidetests/sample/app2/AndroidManifest.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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.sample.cts.app2">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.sample.cts.app2" />
+
+</manifest>
diff --git a/hostsidetests/sample/app2/src/android/sample/cts/app2/SampleDeviceTest.java b/hostsidetests/sample/app2/src/android/sample/cts/app2/SampleDeviceTest.java
new file mode 100644
index 0000000..8299d47
--- /dev/null
+++ b/hostsidetests/sample/app2/src/android/sample/cts/app2/SampleDeviceTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.sample.cts.app2;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.runner.AndroidJUnit4;
+
+/**
+ * Device-side tests for CtsSampleHostTestCases
+ */
+@RunWith(AndroidJUnit4.class)
+public class SampleDeviceTest {
+
+    @Test
+    public void testPasses() throws Exception {
+        Assert.assertTrue(true);
+    }
+
+    @Test
+    public void testAssumeFails() throws Exception {
+        Assume.assumeTrue(false);
+    }
+
+    @Test
+    public void testFails() throws Exception {
+        Assert.assertTrue(false);
+    }
+}
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4DeviceTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4DeviceTest.java
new file mode 100644
index 0000000..f32c523
--- /dev/null
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4DeviceTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.sample.cts;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/**
+ * Test that collects test results from test package android.sample.cts.app2.
+ *
+ * When this test builds, it also builds a support APK containing
+ * {@link android.sample.cts.app2.SampleDeviceTest}, the results of which are
+ * collected from the hostside and reported accordingly.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class SampleHostJUnit4DeviceTest extends CompatibilityHostTestBase {
+
+    private static final String TEST_PKG = "android.sample.cts.app2";
+    private static final String TEST_CLASS = TEST_PKG + "." + "SampleDeviceTest";
+    private static final String TEST_APP = "CtsSampleDeviceApp2.apk";
+
+    private static final String TEST_PASSES = "testPasses";
+    private static final String TEST_ASSUME_FAILS = "testAssumeFails";
+    private static final String TEST_FAILS = "testFails";
+
+    @Before
+    public void setUp() throws Exception {
+        installPackage(TEST_APP);
+    }
+
+    @Test
+    public void testRunDeviceTestsPasses() throws Exception {
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, TEST_PASSES));
+    }
+
+    @Test(expected=AssertionError.class)
+    public void testRunDeviceTestsFails() throws Exception {
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, TEST_FAILS));
+    }
+
+    @Test
+    public void testRunDeviceTestsAssumeFails() throws Exception {
+        Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, TEST_ASSUME_FAILS));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        uninstallPackage(TEST_PKG);
+    }
+
+}
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4Test.java b/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4Test.java
new file mode 100644
index 0000000..f8f1f3a
--- /dev/null
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostJUnit4Test.java
@@ -0,0 +1,112 @@
+/*
+ * 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.sample.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.IDeviceTest;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Scanner;
+
+/**
+ * Test to check the APK logs to Logcat.
+ *
+ * When this test builds, it also builds {@link android.sample.app.SampleDeviceActivity} into an
+ * APK which it then installed at runtime and started. The activity simply prints a message to
+ * Logcat and then gets uninstalled.
+ *
+ * Instead of extending DeviceTestCase, this JUnit4 test extends IDeviceTest and is run with
+ * tradefed's DeviceJUnit4ClassRunner
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class SampleHostJUnit4Test implements IDeviceTest {
+
+    /**
+     * The package name of the APK.
+     */
+    private static final String PACKAGE = "android.sample.app";
+
+    /**
+     * The class name of the main activity in the APK.
+     */
+    private static final String CLASS = "SampleDeviceActivity";
+
+    /**
+     * The command to launch the main activity.
+     */
+    private static final String START_COMMAND = String.format(
+            "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
+
+    /**
+     * The command to clear the main activity.
+     */
+    private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+
+    /**
+     * The test string to look for.
+     */
+    private static final String TEST_STRING = "SampleTestString";
+
+    private ITestDevice mDevice;
+
+    @Override
+    public void setDevice(ITestDevice device) {
+        mDevice = device;
+    }
+
+    @Override
+    public ITestDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
+     * Tests the string was successfully logged to Logcat from the activity.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLogcat() throws Exception {
+        ITestDevice device = getDevice();
+        assertNotNull("Device not set", device);
+        // Clear activity
+        device.executeShellCommand(CLEAR_COMMAND);
+        // Clear logcat.
+        device.executeAdbCommand("logcat", "-c");
+        // Start the APK and wait for it to complete.
+        device.executeShellCommand(START_COMMAND);
+        // Dump logcat.
+        String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
+        // Search for string.
+        String testString = "";
+        Scanner in = new Scanner(logs);
+        while (in.hasNextLine()) {
+            String line = in.nextLine();
+            if(line.startsWith("I/"+CLASS)) {
+                testString = line.split(":")[1].trim();
+            }
+        }
+        in.close();
+        // Assert the logged string matches the test string.
+        assertEquals("Incorrect test string", TEST_STRING, testString);
+    }
+}
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
index f276712..389048d 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostTest.java
@@ -47,6 +47,11 @@
             "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
 
     /**
+     * The command to clear the main activity.
+     */
+    private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+
+    /**
      * The test string to look for.
      */
     private static final String TEST_STRING = "SampleTestString";
@@ -58,6 +63,8 @@
      */
     public void testLogcat() throws Exception {
         ITestDevice device = getDevice();
+        // Clear activity
+        device.executeShellCommand(CLEAR_COMMAND);
         // Clear logcat.
         device.executeAdbCommand("logcat", "-c");
         // Start the APK and wait for it to complete.
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index a500f2f..244379d 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -30,9 +30,7 @@
 
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.security
 
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index a8c35d2..9fe8734 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.RestrictedBuildTest;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -111,7 +111,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */
@@ -657,7 +658,7 @@
     /* Devices always have healthd */
     @CddTest(requirement="9.7")
     public void testHealthdDomain() throws DeviceNotAvailableException {
-        assertDomainOne("u:r:healthd:s0", "/sbin/healthd");
+        assertDomainOne("u:r:healthd:s0", "/system/bin/healthd");
     }
 
     /* Servicemanager is always there */
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/activityandwindowmanager/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
new file mode 100644
index 0000000..ff9e62b
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsServicesHostTestCases
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
+LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
+
+LOCAL_CTS_TEST_PACKAGE := android.server
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
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/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/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
new file mode 100755
index 0000000..7be90fe
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -0,0 +1,263 @@
+<?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.cts">
+
+    <!-- virtual display test permissions -->
+    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+        <activity android:name=".TestActivity"
+                android:resizeableActivity="true"
+                android:exported="true"
+        />
+        <activity android:name=".ResizeableActivity"
+                android:resizeableActivity="true"
+                android:exported="true"
+                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+        />
+        <activity android:name=".NonResizeableActivity"
+                android:resizeableActivity="false"
+                android:exported="true"
+        />
+        <activity android:name=".DockedActivity"
+                android:resizeableActivity="true"
+                android:exported="true"
+                android:taskAffinity="nobody.but.DockedActivity"
+        />
+        <activity android:name=".TranslucentActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar"
+            android:resizeableActivity="true"
+            android:taskAffinity="nobody.but.TranslucentActivity"
+            android:exported="true"
+        />
+        <activity android:name=".NoRelaunchActivity"
+                android:resizeableActivity="true"
+                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|fontScale"
+                android:exported="true"
+                android:taskAffinity="nobody.but.NoRelaunchActivity"
+        />
+        <activity android:name=".SlowCreateActivity"
+                android:resizeableActivity="true"
+                android:exported="true"
+        />
+        <activity android:name=".LaunchingActivity"
+                android:resizeableActivity="true"
+                android:exported="true"
+                android:taskAffinity="nobody.but.LaunchToSideActivity"
+        />
+        <activity android:name=".PipActivity"
+                android:resizeableActivity="true"
+                android:supportsPictureInPicture="true"
+                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                android:exported="true"
+                android:taskAffinity="nobody.but.PipActivity"
+        />
+        <activity android:name=".AlwaysFocusablePipActivity"
+                  android:theme="@style/Theme.Transparent"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  androidprv:alwaysFocusable="true"
+                  android:exported="true"
+                  android:taskAffinity="nobody.but.AlwaysFocusablePipActivity"
+        />
+        <activity android:name=".LaunchIntoPinnedStackPipActivity"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  androidprv:alwaysFocusable="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true"
+        />
+        <activity android:name=".VisibleBehindActivity"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  android:exported="true"
+                  android:taskAffinity="nobody.but.VisibleBehindActivity"
+        />
+        <activity android:name=".LaunchPipOnPipActivity"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  android:taskAffinity="nobody.but.LaunchPipOnPipActivity"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true"
+        />
+        <activity android:name=".LaunchTapToFinishPipActivity"
+                  android:resizeableActivity="true"
+                  android:supportsPictureInPicture="true"
+                  androidprv:alwaysFocusable="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true"
+        />
+        <activity android:name=".LaunchImeWithPipActivity"
+            android:resizeableActivity="true"
+            android:supportsPictureInPicture="true"
+            androidprv:alwaysFocusable="true"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+            android:exported="true"
+            android:windowSoftInputMode="stateAlwaysVisible"
+        />
+        <activity android:name=".PipOnStopActivity"
+            android:resizeableActivity="true"
+            android:supportsPictureInPicture="true"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+            android:exported="true"
+            android:taskAffinity="nobody.but.PipOnStopActivity"
+        />
+        <activity android:name=".FreeformActivity"
+                  android:resizeableActivity="true"
+                  android:taskAffinity="nobody.but.FreeformActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".TopLeftLayoutActivity"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true">
+                  <layout android:defaultWidth="240dp"
+                          android:defaultHeight="160dp"
+                          android:gravity="top|left"
+                          android:minWidth="100dp"
+                          android:minHeight="80dp"
+                  />
+        </activity>
+        <activity android:name=".TopRightLayoutActivity"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true">
+                  <layout android:defaultWidth="25%"
+                          android:defaultHeight="35%"
+                          android:gravity="top|right"
+                          android:minWidth="100dp"
+                          android:minHeight="80dp"
+                  />
+        </activity>
+        <activity android:name=".BottomLeftLayoutActivity"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true">
+                  <layout android:defaultWidth="25%"
+                          android:defaultHeight="35%"
+                          android:gravity="bottom|left"
+                          android:minWidth="100dp"
+                          android:minHeight="80dp"
+                  />
+        </activity>
+        <activity android:name=".BottomRightLayoutActivity"
+                  android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true">
+                  <layout android:defaultWidth="240dp"
+                          android:defaultHeight="160dp"
+                          android:gravity="bottom|right"
+                          android:minWidth="100dp"
+                          android:minHeight="80dp"
+                  />
+        </activity>
+        <activity android:name=".TurnScreenOnActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".TurnScreenOnDismissKeyguardActivity"
+            android:exported="true"
+        />
+        <activity android:name=".SingleTaskActivity"
+            android:exported="true"
+            android:launchMode="singleTask"
+        />
+        <activity android:name=".SingleInstanceActivity"
+            android:exported="true"
+            android:launchMode="singleInstance"
+        />
+        <activity android:name=".TrampolineActivity"
+                  android:exported="true"
+                  android:theme="@android:style/Theme.NoDisplay"
+        />
+        <activity android:name=".BroadcastReceiverActivity"
+                  android:resizeableActivity="true"
+                  android:exported="true"
+        />
+        <activity-alias android:enabled="true"
+                android:exported="true"
+                android:name=".EntryPointAliasActivity"
+                android:targetActivity=".TrampolineActivity" >
+        </activity-alias>
+        <activity android:name=".BottomActivity"
+                  android:exported="true"
+                  android:theme="@style/NoPreview"
+        />
+        <activity android:name=".TopActivity"
+                  android:process=".top_process"
+                  android:exported="true"
+                  android:theme="@style/NoPreview"
+        />
+        <activity android:name=".TranslucentTopActivity"
+                  android:process=".top_process"
+                  android:exported="true"
+                  android:theme="@style/TranslucentTheme"
+        />
+        <activity android:name=".AnimationTestActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".VirtualDisplayActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".ShowWhenLockedActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".ShowWhenLockedWithDialogActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".ShowWhenLockedDialogActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Material.Dialog"
+        />
+        <activity android:name=".ShowWhenLockedTranslucentActivity"
+                  android:exported="true"
+                  android:theme="@android:style/Theme.Translucent"
+        />
+        <activity android:name=".DismissKeyguardActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".DismissKeyguardMethodActivity"
+            android:exported="true"
+        />
+        <activity android:name=".WallpaperActivity"
+            android:exported="true"
+            android:theme="@style/WallpaperTheme"
+        />
+        <activity android:name=".KeyguardLockActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".LogConfigurationActivity"
+            android:exported="true"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+        />
+        <activity android:name=".PortraitOrientationActivity"
+                  android:exported="true"
+                  android:screenOrientation="portrait"
+                  android:documentLaunchMode="always"
+        />
+        <activity android:name=".LandscapeOrientationActivity"
+                  android:exported="true"
+                  android:screenOrientation="landscape"
+                  android:documentLaunchMode="always"
+        />
+    </application>
+</manifest>
+
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml
new file mode 100644
index 0000000..877ecc4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ 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
+  -->
+<translate
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fromYDelta="100%" android:toYDelta="0"
+    android:interpolator="@android:interpolator/linear"
+    android:fillEnabled="true"
+    android:fillBefore="true" android:fillAfter="true"
+    android:duration="500"
+    android:background="#ff0000">
+</translate>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/floating.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/floating.xml
new file mode 100644
index 0000000..a373740
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/floating.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/popup_window"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom|center"
+    android:background="@android:color/white"
+    android:padding="10dp"
+    android:orientation="vertical">
+
+
+    <TextView
+        android:id="@+id/txt_backup"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawablePadding="15dp"
+        android:gravity="center_vertical"
+        android:padding="15dp"
+        android:text="Backup"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@+id/txt_detail"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawablePadding="15dp"
+        android:gravity="center_vertical"
+        android:padding="15dp"
+        android:text="Detail"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@+id/txt_open"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawablePadding="15dp"
+        android:gravity="center_vertical"
+        android:padding="15dp"
+        android:text="Open"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@+id/txt_uninstall"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawablePadding="15dp"
+        android:gravity="center_vertical"
+        android:padding="15dp"
+        android:text="Uninstall"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/main.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/main.xml
new file mode 100644
index 0000000..b53184e
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/main.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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">
+</RelativeLayout>
+
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/tap_to_finish_pip_layout.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/tap_to_finish_pip_layout.xml
new file mode 100644
index 0000000..b3f24a4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/tap_to_finish_pip_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
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#FF0000ff">
+</FrameLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/translucent.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/translucent.xml
new file mode 100644
index 0000000..09d76c0
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/translucent.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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">
+    <View
+        android:layout_width="100dp"
+        android:layout_height="100dp"
+        android:layout_gravity="center"
+        android:background="#80ff0000"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml
new file mode 100644
index 0000000..deac584
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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">
+
+    <SurfaceView
+        android:id="@+id/surfaceView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
new file mode 100644
index 0000000..7fc6725
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
@@ -0,0 +1,43 @@
+<?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.Transparent" parent="android:Theme">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowNoTitle">true</item>
+    </style>
+    <style name="WallpaperTheme">
+        <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+    <style name="TranslucentTheme">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+    <style name="TranslucentWallpaperTheme">
+        <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+    <style name="NoPreview">
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+</resources>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
new file mode 100644
index 0000000..119f7bc
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.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 android.server.cts;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+public abstract class AbstractLifecycleLogActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(getTag(), "onCreate");
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        Log.i(getTag(), "onConfigurationChanged");
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        Log.i(getTag(), "onDestroy");
+    }
+
+    protected abstract String getTag();
+
+    protected void dumpDisplaySize(Configuration config) {
+        // Dump the display size as seen by this Activity.
+        final WindowManager wm = getSystemService(WindowManager.class);
+        final Display display = wm.getDefaultDisplay();
+        final Point point = new Point();
+        display.getSize(point);
+        final DisplayMetrics metrics = getResources().getDisplayMetrics();
+
+        final String line = "config" +
+                " size=" + buildCoordString(config.screenWidthDp, config.screenHeightDp) +
+                " displaySize=" + buildCoordString(point.x, point.y) +
+                " metricsSize=" + buildCoordString(metrics.widthPixels, metrics.heightPixels) +
+                " smallestScreenWidth=" + config.smallestScreenWidthDp +
+                " densityDpi=" + config.densityDpi;
+
+        Log.i(getTag(), line);
+    }
+
+    protected static String buildCoordString(int x, int y) {
+        return "(" + x + "," + y + ")";
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java
new file mode 100644
index 0000000..84b4b45
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AlwaysFocusablePipActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.Rect;
+
+public class AlwaysFocusablePipActivity extends Activity {
+
+    static void launchAlwaysFocusablePipActivity(Activity caller) {
+        final Intent intent = new Intent(caller, AlwaysFocusablePipActivity.class);
+        intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(new Rect(0, 0, 500, 500));
+        options.setLaunchStackId(4 /* ActivityManager.StackId.PINNED_STACK_ID */);
+        caller.startActivity(intent, options.toBundle());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java
new file mode 100644
index 0000000..5ae923e
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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 android.app.Activity;
+
+public class AnimationTestActivity extends Activity {
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        overridePendingTransition(R.anim.animation_with_background, -1);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomActivity.java
new file mode 100644
index 0000000..38a71f1
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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 android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+
+public class BottomActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = BottomActivity.class.getSimpleName();
+
+    private int mStopDelay;
+    private View mFloatingWindow;
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final boolean useWallpaper = getIntent().getBooleanExtra("USE_WALLPAPER", false);
+        if (useWallpaper) {
+            setTheme(R.style.WallpaperTheme);
+        }
+        setContentView(R.layout.main);
+
+        // Delayed stop is for simulating a case where resume happens before
+        // activityStopped() is received by AM, and the transition starts without
+        // going through fully stopped state (see b/30255354).
+        // If enabled, we stall onStop() of BottomActivity, open TopActivity but make
+        // it finish before onStop() ends. This will cause BottomActivity to resume before
+        // it notifies AM of activityStopped(). We also add a second window of
+        // TYPE_BASE_APPLICATION, so that the transition animation could start earlier.
+        // Otherwise the main window has to relayout to visible first and the error won't occur.
+        // Note that if the test fails, we shouldn't try to change the app here to make
+        // it pass. The test app is artificially made to simulate an failure case, but
+        // it's not doing anything wrong.
+        mStopDelay = getIntent().getIntExtra("STOP_DELAY", 0);
+        if (mStopDelay > 0) {
+            LayoutInflater inflater = getLayoutInflater();
+            mFloatingWindow = inflater.inflate(R.layout.floating, null);
+
+            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+            params.setTitle("Floating");
+            getWindowManager().addView(mFloatingWindow, params);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        Log.d(TAG, "onResume() E");
+        super.onResume();
+
+        if (mStopDelay > 0) {
+            // Refresh floating window
+            Log.d(TAG, "Scheuling invalidate Floating Window in onResume()");
+            mFloatingWindow.invalidate();
+        }
+
+        Log.d(TAG, "onResume() X");
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        if (mStopDelay > 0) {
+            try {
+                Log.d(TAG, "Stalling onStop() by " + mStopDelay + " ms...");
+                Thread.sleep(mStopDelay);
+            } catch(InterruptedException e) {}
+
+            // Refresh floating window
+            Log.d(TAG, "Scheuling invalidate Floating Window in onStop()");
+            mFloatingWindow.invalidate();
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java
new file mode 100644
index 0000000..8de1cda
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomLeftLayoutActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class BottomLeftLayoutActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java
new file mode 100644
index 0000000..24fa2fc
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BottomRightLayoutActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class BottomRightLayoutActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
new file mode 100644
index 0000000..6dab9dd
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.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 android.server.cts;
+
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+/**
+ * Activity that registers broadcast receiver .
+ */
+public class BroadcastReceiverActivity extends Activity {
+
+    public static final String ACTION_TRIGGER_BROADCAST = "trigger_broadcast";
+
+    private TestBroadcastReceiver mBroadcastReceiver = new TestBroadcastReceiver();
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        IntentFilter broadcastFilter = new IntentFilter(ACTION_TRIGGER_BROADCAST);
+
+        registerReceiver(mBroadcastReceiver, broadcastFilter);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mBroadcastReceiver);
+    }
+
+    public class TestBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final Bundle extras = intent.getExtras();
+            if (extras == null) {
+                return;
+            }
+            if (extras.getBoolean("finish")) {
+                finish();
+            }
+            if (extras.getBoolean("dismissKeyguard")) {
+                getWindow().addFlags(FLAG_DISMISS_KEYGUARD);
+            }
+            if (extras.getBoolean("dismissKeyguardMethod")) {
+                getSystemService(KeyguardManager.class).dismissKeyguard(
+                        BroadcastReceiverActivity.this, new KeyguardDismissLoggerCallback(), null);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardActivity.java
new file mode 100644
index 0000000..726a756
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardActivity.java
@@ -0,0 +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.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class DismissKeyguardActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java
new file mode 100644
index 0000000..18228e7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.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.server.cts;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+public class DismissKeyguardMethodActivity extends Activity {
+
+    private final String TAG = "DismissKeyguardMethodActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getSystemService(KeyguardManager.class).dismissKeyguard(this,
+                new KeyguardDismissLoggerCallback(), null);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java
new file mode 100644
index 0000000..007df5f
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DockedActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.cts;
+
+import android.app.Activity;
+
+public class DockedActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.java
new file mode 100644
index 0000000..f8c6d0c
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/FreeformActivity.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.server.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.Rect;
+
+public class FreeformActivity extends Activity {
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        final Intent intent = new Intent(this, TestActivity.class);
+        intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(new Rect(0, 0, 900, 900));
+        this.startActivity(intent, options.toBundle());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java
new file mode 100644
index 0000000..efc0c79
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.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.server.cts;
+
+import android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.util.Log;
+
+public class KeyguardDismissLoggerCallback extends KeyguardDismissCallback {
+
+    private final String TAG = "KeyguardDismissLoggerCallback";
+
+    @Override
+    public void onDismissError() {
+        Log.i(TAG, "onDismissError");
+    }
+
+    @Override
+    public void onDismissSucceeded() {
+        Log.i(TAG, "onDismissSucceeded");
+    }
+
+    @Override
+    public void onDismissCancelled() {
+        Log.i(TAG, "onDismissCancelled");
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardLockActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardLockActivity.java
new file mode 100644
index 0000000..352cf04
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardLockActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.app.KeyguardManager;
+import android.os.Bundle;
+
+public class KeyguardLockActivity extends BroadcastReceiverActivity {
+
+    private KeyguardManager.KeyguardLock mKeyguardLock;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mKeyguardLock = getSystemService(KeyguardManager.class).newKeyguardLock("test");
+        mKeyguardLock.disableKeyguard();
+    }
+
+    @Override
+    protected void onDestroy() {
+        mKeyguardLock.reenableKeyguard();
+        super.onDestroy();
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LandscapeOrientationActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LandscapeOrientationActivity.java
new file mode 100644
index 0000000..0ab69b1
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LandscapeOrientationActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class LandscapeOrientationActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchImeWithPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchImeWithPipActivity.java
new file mode 100644
index 0000000..67bbb63
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchImeWithPipActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.app.Activity;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.WindowManager;
+
+public class LaunchImeWithPipActivity extends Activity {
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+        final Display display = wm.getDefaultDisplay();
+        final Point displaySize = new Point();
+        display.getRealSize(displaySize);
+        PipActivity.launchActivity(this, new Rect(0, displaySize.y - 150, 150, displaySize.y),
+                false /* tapToLaunch */);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java
new file mode 100644
index 0000000..23298a0
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchIntoPinnedStackPipActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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 android.app.Activity;
+
+public class LaunchIntoPinnedStackPipActivity extends Activity {
+    @Override
+    protected void onResume() {
+        super.onResume();
+        AlwaysFocusablePipActivity.launchAlwaysFocusablePipActivity(this);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java
new file mode 100644
index 0000000..1b9b729
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchPipOnPipActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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 android.app.Activity;
+
+public class LaunchPipOnPipActivity extends Activity {
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
+        AlwaysFocusablePipActivity.launchAlwaysFocusablePipActivity(this);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchTapToFinishPipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchTapToFinishPipActivity.java
new file mode 100644
index 0000000..4e3fc89
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchTapToFinishPipActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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 android.app.Activity;
+import android.graphics.Rect;
+
+public class LaunchTapToFinishPipActivity extends Activity {
+    @Override
+    protected void onResume() {
+        super.onResume();
+        PipActivity.launchActivity(this, new Rect(0, 0, 500, 500), true /* tapToLaunch */);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
new file mode 100644
index 0000000..8d1d358
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.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 android.server.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Activity that launches another activities when new intent is received.
+ */
+public class LaunchingActivity extends Activity {
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        final Bundle extras = intent.getExtras();
+        if (extras == null) {
+            return;
+        }
+
+        Intent newIntent = new Intent();
+        String targetActivity = extras.getString("target_activity");
+        if (targetActivity != null) {
+            String packageName = getApplicationContext().getPackageName();
+            newIntent.setComponent(new ComponentName(packageName,
+                    packageName + "." + targetActivity));
+        } else {
+            newIntent.setClass(this, TestActivity.class);
+        }
+
+        if (extras.getBoolean("launch_to_the_side")) {
+            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_ADJACENT);
+            if (extras.getBoolean("multiple_task")) {
+                newIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+            }
+            if (extras.getBoolean("random_data")) {
+                Uri data = new Uri.Builder()
+                        .path(String.valueOf(System.currentTimeMillis()))
+                        .build();
+                newIntent.setData(data);
+            }
+        }
+
+        ActivityOptions options = null;
+        final int displayId = extras.getInt("display_id", -1);
+        if (displayId != -1) {
+            options = ActivityOptions.makeBasic();
+            options.setLaunchDisplayId(displayId);
+            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+        }
+
+        startActivity(newIntent, options != null ? options.toBundle() : null);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LogConfigurationActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LogConfigurationActivity.java
new file mode 100644
index 0000000..61eb78c
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LogConfigurationActivity.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.server.cts;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.util.Log;
+
+/**
+ * Activity that logs configuration changes.
+ */
+public class LogConfigurationActivity extends Activity {
+
+    private static final String TAG = "LogConfigurationActivity";
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        Log.i(TAG, "Configuration changed: " + newConfig.screenWidthDp + ","
+                + newConfig.screenHeightDp);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java
new file mode 100644
index 0000000..9cc3b9d
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NoRelaunchActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+public class NoRelaunchActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = NoRelaunchActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java
new file mode 100644
index 0000000..b871a8d
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/NonResizeableActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+public class NonResizeableActivity extends AbstractLifecycleLogActivity {
+
+     private static final String TAG = NonResizeableActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
new file mode 100644
index 0000000..a2f9ac7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -0,0 +1,143 @@
+/*
+ * 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.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.TextUtils;
+
+public class PipActivity extends Activity {
+
+    // Calls enterPictureInPicture() on creation
+    private static final String EXTRA_ENTER_PIP = "enter_pip";
+    // Used with EXTRA_AUTO_ENTER_PIP, value specifies the aspect ratio to enter PIP with
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO = "enter_pip_aspect_ratio";
+    // Calls setPictureInPictureAspectRatio with the aspect ratio specified in the value
+    private static final String EXTRA_SET_ASPECT_RATIO = "set_aspect_ratio";
+    // Adds a click listener to finish this activity when it is clicked
+    private static final String EXTRA_TAP_TO_FINISH = "tap_to_finish";
+    // Calls requestAutoEnterPictureInPicture() with the value provided
+    private static final String EXTRA_ENTER_PIP_ON_MOVE_TO_BG = "enter_pip_on_move_to_bg";
+    // Starts the activity (component name) provided by the value at the end of onCreate
+    private static final String EXTRA_START_ACTIVITY = "start_activity";
+    // Finishes the activity at the end of onCreate (after EXTRA_START_ACTIVITY is handled)
+    private static final String EXTRA_FINISH_SELF_ON_RESUME = "finish_self_on_resume";
+    // Calls enterPictureInPicture() again after onPictureInPictureModeChanged(false) is called
+    private static final String EXTRA_REENTER_PIP_ON_EXIT = "reenter_pip_on_exit";
+
+    private Handler mHandler = new Handler();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Enter picture in picture with the given aspect ratio if provided
+        if (getIntent().hasExtra(EXTRA_ENTER_PIP)) {
+            if (getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO)) {
+                try {
+                    final float aspectRatio = Float.valueOf(getIntent().getStringExtra(
+                            EXTRA_ENTER_PIP_ASPECT_RATIO));
+                    enterPictureInPictureMode(aspectRatio);
+                } catch (Exception e) {
+                    // This call can fail intentionally if the aspect ratio is too extreme
+                }
+            } else {
+                enterPictureInPictureMode();
+            }
+        }
+
+        // Request auto-enter PIP
+        if (getIntent().hasExtra(EXTRA_ENTER_PIP_ON_MOVE_TO_BG)) {
+            enterPictureInPictureModeOnMoveToBackground(Boolean.valueOf(
+                    getIntent().getStringExtra(EXTRA_ENTER_PIP_ON_MOVE_TO_BG)));
+        }
+
+        // We need to wait for either enterPictureInPicture() or requestAutoEnterPictureInPicture()
+        // to be called before setting the aspect ratio
+        if (getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO)) {
+            final float aspectRatio = Float.valueOf(getIntent().getStringExtra(
+                    EXTRA_SET_ASPECT_RATIO));
+            try {
+                setPictureInPictureAspectRatio(aspectRatio);
+            } catch (Exception e) {
+                // This call can fail intentionally if the aspect ratio is too extreme
+            }
+        }
+
+        // Enable tap to finish if necessary
+        if (getIntent().hasExtra(EXTRA_TAP_TO_FINISH)) {
+            setContentView(R.layout.tap_to_finish_pip_layout);
+            findViewById(R.id.content).setOnClickListener(v -> {
+                finish();
+            });
+        }
+
+        // Launch a new activity if requested
+        String launchActivityComponent = getIntent().getStringExtra(EXTRA_START_ACTIVITY);
+        if (launchActivityComponent != null) {
+            Intent launchIntent = new Intent();
+            launchIntent.setComponent(ComponentName.unflattenFromString(launchActivityComponent));
+            startActivity(launchIntent);
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Finish self if requested
+        if (getIntent().hasExtra(EXTRA_FINISH_SELF_ON_RESUME)) {
+            finish();
+        }
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
+
+        if (!isInPictureInPictureMode && getIntent().hasExtra(EXTRA_REENTER_PIP_ON_EXIT)) {
+            // This call to re-enter PIP can happen too quickly (host side tests can have difficulty
+            // checking that the stacks ever changed). Therefor, we need to delay here slightly to
+            // allow the tests to verify that the stacks have changed before re-entering.
+            mHandler.postDelayed(() -> {
+                enterPictureInPictureMode();
+            }, 1000);
+        }
+    }
+
+    /**
+     * Launches a new instance of the PipActivity.
+     */
+    static void launchActivity(Activity caller, Rect bounds, boolean tapToFinish) {
+        final Intent intent = new Intent(caller, PipActivity.class);
+        intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRA_TAP_TO_FINISH, tapToFinish);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(bounds);
+        options.setLaunchStackId(4 /* ActivityManager.StackId.PINNED_STACK_ID */);
+        caller.startActivity(intent, options.toBundle());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipOnStopActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipOnStopActivity.java
new file mode 100644
index 0000000..1abc696
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipOnStopActivity.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 android.server.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * This activity will try and enter picture in picture when it is stopped.
+ */
+public class PipOnStopActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.tap_to_finish_pip_layout);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        startActivity(new Intent(this, PipActivity.class));
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        try {
+            enterPictureInPictureMode();
+        } catch (RuntimeException e) {
+            // Known failure, we expect this call to throw an exception
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PortraitOrientationActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PortraitOrientationActivity.java
new file mode 100644
index 0000000..7acb4da
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PortraitOrientationActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class PortraitOrientationActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java
new file mode 100644
index 0000000..1747b8b
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ResizeableActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.content.res.Configuration;
+import android.os.Bundle;
+
+public class ResizeableActivity extends AbstractLifecycleLogActivity {
+    @Override
+    protected String getTag() {
+        return "ResizeableActivity";
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        dumpDisplaySize(getResources().getConfiguration());
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        dumpDisplaySize(newConfig);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedActivity.java
new file mode 100644
index 0000000..6e3348a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedActivity.java
@@ -0,0 +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.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ShowWhenLockedActivity extends BroadcastReceiverActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedDialogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedDialogActivity.java
new file mode 100644
index 0000000..5b60139
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedDialogActivity.java
@@ -0,0 +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.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ShowWhenLockedDialogActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedTranslucentActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedTranslucentActivity.java
new file mode 100644
index 0000000..929c9f7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedTranslucentActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ShowWhenLockedTranslucentActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        setContentView(R.layout.translucent);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedWithDialogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedWithDialogActivity.java
new file mode 100644
index 0000000..58d5ac7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/ShowWhenLockedWithDialogActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ShowWhenLockedWithDialogActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        new AlertDialog.Builder(this)
+                .setTitle("Dialog")
+                .show();
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java
new file mode 100644
index 0000000..e0eaecf
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleInstanceActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class SingleInstanceActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java
new file mode 100644
index 0000000..7ffde13
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SingleTaskActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class SingleTaskActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java
new file mode 100644
index 0000000..a757165
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SlowCreateActivity.java
@@ -0,0 +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.cts;
+
+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);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
new file mode 100644
index 0000000..2d74cad
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.cts;
+
+import android.content.res.Configuration;
+
+public class TestActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = TestActivity.class.getSimpleName();
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        dumpDisplaySize(getResources().getConfiguration());
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        dumpDisplaySize(newConfig);
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopActivity.java
new file mode 100644
index 0000000..6684999
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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 android.os.Handler;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TopActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = TopActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final boolean useWallpaper = getIntent().getBooleanExtra("USE_WALLPAPER", false);
+        if (useWallpaper) {
+            setTheme(R.style.WallpaperTheme);
+        }
+
+        final int finishDelay = getIntent().getIntExtra("FINISH_DELAY", 0);
+        if (finishDelay > 0) {
+            Handler handler = new Handler();
+            handler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    Log.d(TAG, "Calling finish()");
+                    finish();
+                }
+            }, finishDelay);
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java
new file mode 100644
index 0000000..2305582
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopLeftLayoutActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class TopLeftLayoutActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java
new file mode 100644
index 0000000..701d3db
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TopRightLayoutActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class TopRightLayoutActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java
new file mode 100644
index 0000000..b3f9444
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TrampolineActivity.java
@@ -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.
+ */
+
+package android.server.cts;
+
+import android.os.Bundle;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.content.Intent;
+
+public class TrampolineActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = TrampolineActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // Add a delay here to expose more easily a failure case where the real target
+        // activity is visible before it's launched, because its task is being brought
+        // to foreground. We need to verify that 'am start' is unblocked correctly.
+        try {
+            Thread.sleep(2000);
+        } catch(InterruptedException e) {}
+        Intent intent = new Intent(this, SingleTaskActivity.class);
+        intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK);
+
+        startActivity(intent);
+        finish();
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java
new file mode 100644
index 0000000..96697aa
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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 android.app.Activity;
+
+public class TranslucentActivity extends Activity {
+
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTopActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTopActivity.java
new file mode 100644
index 0000000..9d96898
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTopActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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 android.os.Handler;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TranslucentTopActivity extends AbstractLifecycleLogActivity {
+
+    private static final String TAG = TranslucentTopActivity.class.getSimpleName();
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final boolean useWallpaper = getIntent().getBooleanExtra("USE_WALLPAPER", false);
+        if (useWallpaper) {
+            setTheme(R.style.TranslucentWallpaperTheme);
+        }
+
+        final int finishDelay = getIntent().getIntExtra("FINISH_DELAY", 0);
+        if (finishDelay > 0) {
+            Handler handler = new Handler();
+            handler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    Log.d(TAG, "Calling finish()");
+                    finish();
+                }
+            }, finishDelay);
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.java
new file mode 100644
index 0000000..79e31b3
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnActivity.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 android.server.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class TurnScreenOnActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+        super.onCreate(savedInstanceState);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java
new file mode 100644
index 0000000..9d262a7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.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.server.cts;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class TurnScreenOnDismissKeyguardActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+        getSystemService(KeyguardManager.class).dismissKeyguard(this,
+                new KeyguardDismissLoggerCallback(), null);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
new file mode 100644
index 0000000..38e0d61
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -0,0 +1,104 @@
+/*
+ * 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 android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowManager;
+
+/**
+ * Activity that is able to create and destroy a virtual display.
+ */
+public class VirtualDisplayActivity extends Activity {
+    private static final String TAG = "VirtualDisplayActivity";
+
+    private static final int DEFAULT_DENSITY_DPI = 160;
+    private static final String KEY_DENSITY_DPI = "density_dpi";
+
+    private DisplayManager mDisplayManager;
+    private VirtualDisplay mVirtualDisplay;
+
+    private Surface mSurface;
+    private SurfaceView mSurfaceView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.virtual_display_layout);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
+        mSurface = mSurfaceView.getHolder().getSurface();
+
+        mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        final Bundle extras = intent.getExtras();
+        if (extras == null) {
+            return;
+        }
+
+        String command = extras.getString("command");
+        switch (command) {
+            case "create_display":
+                createVirtualDisplay(extras);
+                break;
+            case "destroy_display":
+                destroyVirtualDisplay();
+                break;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        destroyVirtualDisplay();
+    }
+
+    private void createVirtualDisplay(Bundle extras) {
+        if (mVirtualDisplay == null) {
+            final int width = mSurfaceView.getWidth();
+            final int height = mSurfaceView.getHeight();
+            final int densityDpi = extras.getInt(KEY_DENSITY_DPI, DEFAULT_DENSITY_DPI);
+            Log.d(TAG, "createVirtualDisplay: " + width + "x" + height + ", dpi: "
+                    + densityDpi);
+            final int flags = 0;
+            mVirtualDisplay = mDisplayManager.createVirtualDisplay("VirtualDisplay", width, height,
+                    densityDpi, mSurface, flags);
+        }
+    }
+
+    private void destroyVirtualDisplay() {
+        if (mVirtualDisplay != null) {
+            Log.d(TAG, "destroyVirtualDisplay");
+            mVirtualDisplay.release();
+            mVirtualDisplay = null;
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
new file mode 100644
index 0000000..29feba9
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.app.Activity;
+import android.util.Log;
+
+public class VisibleBehindActivity extends Activity {
+    private static final String TAG = "VisibleBehindActivity";
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (requestVisibleBehind(true)) {
+            Log.e(TAG, "Failed to request visibility behind...");
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/WallpaperActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/WallpaperActivity.java
new file mode 100644
index 0000000..63e11d5
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/WallpaperActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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 android.app.Activity;
+
+public class WallpaperActivity extends Activity {
+}
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/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
new file mode 100644
index 0000000..5da44c7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.displaysize.app;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class SmallestWidthActivity extends Activity {
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        final Bundle extras = intent.getExtras();
+        if (extras != null && extras.getBoolean("launch_another_activity")) {
+            Intent startIntent = new Intent();
+            startIntent.setComponent(
+                    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..0d5f61a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.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 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.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static android.server.cts.StateLogger.log;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityAndWindowManagerOverrideConfigTests
+ */
+public class ActivityAndWindowManagerOverrideConfigTests extends ActivityManagerTestBase {
+    private static final String TEST_ACTIVITY_NAME = "LogConfigurationActivity";
+
+    private class ConfigurationChangeObserver {
+        private final Pattern mConfigurationChangedPattern =
+            Pattern.compile("(.+)Configuration changed: (\\d+),(\\d+)");
+
+        private ConfigurationChangeObserver() {
+        }
+
+        private boolean findConfigurationChange(String activityName)
+                throws DeviceNotAvailableException, InterruptedException {
+            int tries = 0;
+            boolean observedChange = false;
+            while (tries < 5 && !observedChange) {
+                final String[] lines = getDeviceLogsForComponent(activityName);
+                log("Looking at logcat");
+                for (int i = lines.length - 1; i >= 0; i--) {
+                    final String line = lines[i].trim();
+                    log(line);
+                    Matcher matcher = mConfigurationChangedPattern.matcher(line);
+                    if (matcher.matches()) {
+                        observedChange = true;
+                        break;
+                    }
+                }
+                tries++;
+                Thread.sleep(500);
+            }
+            return observedChange;
+        }
+    }
+
+    public void testReceiveOverrideConfigFromRelayout() throws Exception {
+        if (!supportsFreeform()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Device doesn't support freeform. Skipping test.");
+            return;
+        }
+
+        launchActivityInStack(TEST_ACTIVITY_NAME, FREEFORM_WORKSPACE_STACK_ID);
+
+        setDeviceRotation(0);
+        clearLogcat();
+        resizeActivityTask(TEST_ACTIVITY_NAME, 0, 0, 100, 100);
+        ConfigurationChangeObserver c = new ConfigurationChangeObserver();
+        final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+        assertTrue("Expected to observe configuration change when resizing",
+                reportedSizeAfterResize);
+
+        clearLogcat();
+        setDeviceRotation(2);
+        final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+        assertFalse("Not expected to observe configuration change after flip rotation",
+                reportedSizeAfterRotation);
+    }
+}
+
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
new file mode 100644
index 0000000..a4a6191
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -0,0 +1,172 @@
+/*
+ * 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.lang.Exception;
+import java.lang.String;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerActivityVisibilityTests
+ */
+public class ActivityManagerActivityVisibilityTests extends ActivityManagerTestBase {
+    private static final String TRANSLUCENT_ACTIVITY = "AlwaysFocusablePipActivity";
+    private static final String VISIBLE_BEHIND_ACTIVITY = "VisibleBehindActivity";
+    private static final String PIP_ON_PIP_ACTIVITY = "LaunchPipOnPipActivity";
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String TRANSLUCENT_ACTIVITY_NAME = "TranslucentActivity";
+    private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
+    private static final String TURN_SCREEN_ON_ACTIVITY_NAME = "TurnScreenOnActivity";
+    private static final String BROADCAST_RECEIVER_ACTIVITY = "BroadcastReceiverActivity";
+
+    public void testVisibleBehindHomeActivity() throws Exception {
+        launchActivity(VISIBLE_BEHIND_ACTIVITY);
+        mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForHomeActivityVisible(mDevice);
+
+        /* TODO: Find a proper way to wait until launcher activity
+         * becomes fully visible. It appears that both VisibleBehindActivity
+         * and home activity are visible at some point before the former
+         * disappears.*/
+        Thread.sleep(3000);
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
+        mAmWmState.assertVisibility(
+                VISIBLE_BEHIND_ACTIVITY, hasDeviceFeature("android.software.leanback"));
+    }
+
+    public void testVisibleBehindOtherActivity_NotOverHome() throws Exception {
+        launchActivity(VISIBLE_BEHIND_ACTIVITY);
+        launchActivity(TRANSLUCENT_ACTIVITY);
+
+        mAmWmState.computeState(mDevice,
+                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
+        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
+    }
+
+    public void testVisibleBehindOtherActivity_OverHome() throws Exception {
+        executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
+        mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY);
+        executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
+
+        mAmWmState.computeState(mDevice,
+                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
+        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
+    }
+
+    public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
+        if (!supportsPip()) {
+            return;
+        }
+
+        executeShellCommand(getAmStartCmdOverHome(PIP_ON_PIP_ACTIVITY));
+        mAmWmState.waitForValidState(mDevice, PIP_ON_PIP_ACTIVITY);
+        // NOTE: moving to pinned stack will trigger the pip-on-pip activity to launch the
+        // translucent activity.
+        executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
+
+        mAmWmState.computeState(mDevice, new String[] {PIP_ON_PIP_ACTIVITY, TRANSLUCENT_ACTIVITY});
+        mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
+        mAmWmState.assertVisibility(PIP_ON_PIP_ACTIVITY, true);
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
+    }
+
+    /**
+     * Asserts that the home activity is visible when a translucent activity is launched in the
+     * fullscreen stack over the home activity.
+     */
+    public void testTranslucentActivityOnTopOfHome() throws Exception {
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        launchActivity(TRANSLUCENT_ACTIVITY);
+
+        mAmWmState.computeState(mDevice, new String[]{TRANSLUCENT_ACTIVITY});
+        mAmWmState.assertFrontStack(
+                "Fullscreen stack must be the front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
+        mAmWmState.assertHomeActivityVisible(true);
+    }
+
+    /**
+     * Assert that the home activity is visible if a task that was launched from home is pinned
+     * and also assert the next task in the fullscreen stack isn't visible.
+     */
+    public void testHomeVisibleOnActivityTaskPinned() throws Exception {
+        if (!supportsPip()) {
+            return;
+        }
+
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        launchActivity(TEST_ACTIVITY_NAME);
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        launchActivity(TRANSLUCENT_ACTIVITY);
+        executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
+
+        mAmWmState.computeState(mDevice, new String[]{TRANSLUCENT_ACTIVITY});
+
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, false);
+        mAmWmState.assertHomeActivityVisible(true);
+    }
+
+    public void testTranslucentActivityOverDockedStack() throws Exception {
+        launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
+        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME});
+        launchActivityInStack(TRANSLUCENT_ACTIVITY_NAME, DOCKED_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME,
+                TRANSLUCENT_ACTIVITY_NAME}, false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain fullscreen stack",
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true);
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
+        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY_NAME, true);
+    }
+
+    public void testTurnScreenOnActivity() throws Exception {
+        sleepDevice();
+        launchActivity(TURN_SCREEN_ON_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY_NAME, true);
+    }
+
+    public void testFinishActivityInNonFocusedStack() throws Exception {
+        // Launch two activities in docked stack.
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTaskFlag */, BROADCAST_RECEIVER_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] { BROADCAST_RECEIVER_ACTIVITY });
+        mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, true);
+        // Launch something to fullscreen stack to make it focused.
+        launchActivityInStack(TEST_ACTIVITY_NAME, 1);
+        mAmWmState.computeState(mDevice, new String[] { TEST_ACTIVITY_NAME });
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
+        // Finish activity in non-focused (docked) stack.
+        executeShellCommand("am broadcast -a trigger_broadcast --ez finish true");
+        mAmWmState.computeState(mDevice, new String[] { LAUNCHING_ACTIVITY });
+        mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
+        mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, false);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
new file mode 100644
index 0000000..0f77868
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
@@ -0,0 +1,184 @@
+/*
+ * 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.tradefed.device.DeviceNotAvailableException;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerAmStartOptionsTests
+ */
+public class ActivityManagerAmStartOptionsTests extends ActivityManagerTestBase {
+
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String ENTRYPOINT_ACTIVITY_NAME = "EntryPointAliasActivity";
+    private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity";
+
+    public void testDashD() throws Exception {
+        final String activityComponentName =
+                ActivityManagerTestBase.getActivityComponentName(TEST_ACTIVITY_NAME);
+
+        final String[] waitForActivityRecords = new String[] {activityComponentName};
+
+        // 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.
+        int prevProcId = -1;
+        for (int i = 0; i < 2; i++) {
+            executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME) + " -D");
+
+            mAmWmState.waitForDebuggerWindowVisible(mDevice, waitForActivityRecords);
+            int procId = mAmWmState.getAmState().getActivityProcId(activityComponentName);
+
+            assertTrue("Invalid ProcId.", procId >= 0);
+            if (i > 0) {
+                assertTrue("Run " + i + " didn't start new proc.", prevProcId != procId);
+            }
+            prevProcId = procId;
+        }
+    }
+
+    public void testDashW_Direct() throws Exception {
+        testDashW(SINGLE_TASK_ACTIVITY_NAME, SINGLE_TASK_ACTIVITY_NAME);
+    }
+
+    public void testDashW_Indirect() throws Exception {
+        testDashW(ENTRYPOINT_ACTIVITY_NAME, SINGLE_TASK_ACTIVITY_NAME);
+    }
+
+    private void testDashW(final String entryActivity, final String actualActivity)
+            throws Exception {
+        // Test cold start
+        startActivityAndVerifyResult(entryActivity, actualActivity, true);
+
+        // Test warm start
+        pressHomeButton();
+        startActivityAndVerifyResult(entryActivity, actualActivity, false);
+
+        // Test "hot" start (app already in front)
+        startActivityAndVerifyResult(entryActivity, actualActivity, false);
+    }
+
+    private void startActivityAndVerifyResult(final String entryActivity,
+            final String actualActivity, boolean shouldStart) throws Exception {
+        clearLogcat();
+
+        // Pass in different data only when cold starting. This is to make the intent
+        // different in subsequent warm/hot launches, so that the entrypoint alias
+        // activity is always started, but the actual activity is not started again
+        // because of the NEW_TASK and singleTask flags.
+        final String result = executeShellCommand(getAmStartCmd(entryActivity) + " -W"
+                + (shouldStart ? " -d about:blank" : ""));
+
+        // Verify shell command return value
+        verifyShellOutput(result, actualActivity, shouldStart);
+
+        // TODO: Disable logcat check for now.
+        // Logcat of WM or AM tag could be lost (eg. chatty if earlier events generated
+        // too many lines), and make the test look flaky. We need to either use event
+        // log or swith to other mechanisms. Only verify shell output for now, it should
+        // still catch most failures.
+
+        // Verify adb logcat log
+        //verifyLogcat(actualActivity, shouldStart);
+    }
+
+    private static final Pattern sNotStartedWarningPattern = Pattern.compile(
+            "Warning: Activity not started(.*)");
+    private static final Pattern sStatusPattern = Pattern.compile(
+            "Status: (.*)");
+    private static final Pattern sActivityPattern = Pattern.compile(
+            "Activity: (.*)");
+    private static final String sStatusOk = "ok";
+
+    private void verifyShellOutput(
+            final String result, final String activity, boolean shouldStart) {
+        boolean warningFound = false;
+        String status = null;
+        String reportedActivity = null;
+        String componentActivityName = getActivityComponentName(activity);
+
+        final String[] lines = result.split("\\n");
+        // Going from the end of logs to beginning in case if some other activity is started first.
+        for (int i = lines.length - 1; i >= 0; i--) {
+            final String line = lines[i].trim();
+            Matcher matcher = sNotStartedWarningPattern.matcher(line);
+            if (matcher.matches()) {
+                warningFound = true;
+                continue;
+            }
+            matcher = sStatusPattern.matcher(line);
+            if (matcher.matches()) {
+                status = matcher.group(1);
+                continue;
+            }
+            matcher = sActivityPattern.matcher(line);
+            if (matcher.matches()) {
+                reportedActivity = matcher.group(1);
+                continue;
+            }
+        }
+
+        assertTrue("Status " + status + " is not ok", sStatusOk.equals(status));
+        assertTrue("Reported activity is " + reportedActivity + " not " + componentActivityName,
+                componentActivityName.equals(reportedActivity));
+
+        if (shouldStart && warningFound) {
+            fail("Should start new activity but brought something to front.");
+        } else if (!shouldStart && !warningFound){
+            fail("Should bring existing activity to front but started new activity.");
+        }
+    }
+
+    private static final Pattern sDisplayTimePattern =
+            Pattern.compile("(.+): Displayed (.*): (\\+{0,1})([0-9]+)ms(.*)");
+
+    void verifyLogcat(String actualActivityName, boolean shouldStart)
+            throws DeviceNotAvailableException {
+        int displayCount = 0;
+        String activityName = null;
+
+        for (String line : getDeviceLogsForComponent("ActivityManager")) {
+            line = line.trim();
+
+            Matcher matcher = sDisplayTimePattern.matcher(line);
+            if (matcher.matches()) {
+                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.cts")) {
+                    continue;
+                }
+                if (!shouldStart) {
+                    fail("Shouldn't display anything but displayed " + activityName);
+                }
+                displayCount++;
+            }
+        }
+        final String expectedActivityName = getActivityComponentName(actualActivityName);
+        if (shouldStart) {
+            if (displayCount != 1) {
+                fail("Should display exactly one activity but displayed " + displayCount);
+            } else if (!expectedActivityName.equals(activityName)) {
+                fail("Should display " + expectedActivityName +
+                        " but displayed " + activityName);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
new file mode 100644
index 0000000..8636415
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -0,0 +1,372 @@
+/*
+ * 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.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerAppConfigurationTests
+ */
+public class ActivityManagerAppConfigurationTests extends ActivityManagerTestBase {
+    private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String PORTRAIT_ACTIVITY_NAME = "PortraitOrientationActivity";
+    private static final String LANDSCAPE_ACTIVITY_NAME = "LandscapeOrientationActivity";
+
+    /**
+     * Tests that the WindowManager#getDefaultDisplay() and the Configuration of the Activity
+     * has an updated size when the Activity is resized from fullscreen to docked state.
+     *
+     * The Activity handles configuration changes, so it will not be restarted between resizes.
+     * On Configuration changes, the Activity logs the Display size and Configuration width
+     * and heights. The values reported in fullscreen should be larger than those reported in
+     * docked state.
+     */
+    public void testConfigurationUpdatesWhenResizedFromFullscreen() throws Exception {
+        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                DOCKED_STACK_ID);
+
+        assertSizesAreSane(fullscreenSizes, dockedSizes);
+    }
+
+    /**
+     * Same as {@link #testConfigurationUpdatesWhenResizedFromFullscreen()} but resizing
+     * from docked state to fullscreen (reverse).
+     */
+    public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
+        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                DOCKED_STACK_ID);
+
+        moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        assertSizesAreSane(fullscreenSizes, dockedSizes);
+    }
+
+    /**
+     * Tests whether the Display sizes change when rotating the device.
+     */
+    public void testConfigurationUpdatesWhenRotatingWhileFullscreen() throws Exception {
+        setDeviceRotation(0);
+        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        rotateAndCheckSizes(initialSizes, FULLSCREEN_WORKSPACE_STACK_ID);
+    }
+
+    /**
+     * Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity
+     * is in the docked stack.
+     */
+    public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
+        setDeviceRotation(0);
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        // Launch our own activity to side in case Recents (or other activity to side) doesn't
+        // support rotation.
+        launchActivityToSide(false /* randomData */, false /* multipleTask */, TEST_ACTIVITY_NAME);
+        // Launch target activity in docked stack.
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTask */, RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                DOCKED_STACK_ID);
+
+        rotateAndCheckSizes(initialSizes, DOCKED_STACK_ID);
+    }
+
+    /**
+     * Same as {@link #testConfigurationUpdatesWhenRotatingWhileDocked()} but when the Activity
+     * is launched to side from docked stack.
+     */
+    public void testConfigurationUpdatesWhenRotatingToSideFromDocked() throws Exception {
+        setDeviceRotation(0);
+
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        launchActivityToSide(false /* randomData */, false /* multipleTaskFlag */,
+                RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        rotateAndCheckSizes(initialSizes, FULLSCREEN_WORKSPACE_STACK_ID);
+    }
+
+    private void rotateAndCheckSizes(ReportedSizes prevSizes, int stackId) throws Exception {
+        for (int rotation = 3; rotation >= 0; --rotation) {
+            clearLogcat();
+            setDeviceRotation(rotation);
+            final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                    stackId);
+            assertSizesRotate(prevSizes, rotatedSizes);
+            prevSizes = rotatedSizes;
+        }
+    }
+
+    /**
+     * Tests when activity moved from fullscreen stack to docked and back. Activity will be
+     * relaunched twice and it should have same config as initial one.
+     */
+    public void testSameConfigurationFullSplitFullRelaunch() throws Exception {
+        moveActivityFullSplitFull(TEST_ACTIVITY_NAME);
+    }
+
+    /**
+     * Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch.
+     */
+    public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
+        moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
+    }
+
+    /**
+     * Launches activity in fullscreen stack, moves to docked stack and back to fullscreen stack.
+     * Last operation is done in a way which simulates split-screen divider movement maximizing
+     * docked stack size and then moving task to fullscreen stack - the same way it is done when
+     * user long-presses overview/recents button to exit split-screen.
+     * Asserts that initial and final reported sizes in fullscreen stack are the same.
+     */
+    private void moveActivityFullSplitFull(String activityName) throws Exception {
+        // Launch to fullscreen stack and record size.
+        launchActivityInStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        final Rectangle displayRect = getDisplayRect(activityName);
+
+        // Move to docked stack.
+        moveActivityToStack(activityName, DOCKED_STACK_ID);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(activityName, DOCKED_STACK_ID);
+        assertSizesAreSane(initialFullscreenSizes, dockedSizes);
+        // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
+        // will come up.
+        launchActivityInStack(activityName, DOCKED_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] { activityName },
+                false /* compareTaskAndStackBounds */);
+
+        // Resize docked stack to fullscreen size. This will trigger activity relaunch with
+        // non-empty override configuration corresponding to fullscreen size.
+        runCommandAndPrintOutput("am stack resize " + DOCKED_STACK_ID + " 0 0 "
+                + displayRect.width + " " + displayRect.height);
+        // Move activity back to fullscreen stack.
+        moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+
+        // After activity configuration was changed twice it must report same size as original one.
+        assertSizesAreSame(initialFullscreenSizes, finalFullscreenSizes);
+    }
+
+    /**
+     * Tests when activity moved from docked stack to fullscreen and back. Activity will be
+     * relaunched twice and it should have same config as initial one.
+     */
+    public void testSameConfigurationSplitFullSplitRelaunch() throws Exception {
+        moveActivitySplitFullSplit(TEST_ACTIVITY_NAME);
+    }
+
+    /**
+     * Same as {@link #testSameConfigurationSplitFullSplitRelaunch} but without relaunch.
+     */
+    public void testSameConfigurationSplitFullSplitNoRelaunch() throws Exception {
+        moveActivitySplitFullSplit(RESIZEABLE_ACTIVITY_NAME);
+    }
+
+    /**
+     * Test that device handles consequent requested orientations and displays the activities.
+     */
+    public void testFullscreenAppOrientationRequests() throws Exception {
+        launchActivity(PORTRAIT_ACTIVITY_NAME);
+        mAmWmState.assertVisibility(PORTRAIT_ACTIVITY_NAME, true /* visible */);
+        assertEquals("Fullscreen app requested portrait orientation",
+                1 /* portrait */, mAmWmState.getWmState().getLastOrientation());
+
+        launchActivity(LANDSCAPE_ACTIVITY_NAME);
+        mAmWmState.assertVisibility(LANDSCAPE_ACTIVITY_NAME, true /* visible */);
+        assertEquals("Fullscreen app requested landscape orientation",
+                0 /* landscape */, mAmWmState.getWmState().getLastOrientation());
+
+        launchActivity(PORTRAIT_ACTIVITY_NAME);
+        mAmWmState.assertVisibility(PORTRAIT_ACTIVITY_NAME, true /* visible */);
+        assertEquals("Fullscreen app requested portrait orientation",
+                1 /* portrait */, mAmWmState.getWmState().getLastOrientation());
+    }
+
+    /**
+     * Test that device doesn't change device orientation by app request while in multi-window.
+     */
+    public void testSplitscreenPortraitAppOrientationRequests() throws Exception {
+        requestOrientationInSplitScreen(1 /* portrait */, LANDSCAPE_ACTIVITY_NAME);
+    }
+
+    /**
+     * Test that device doesn't change device orientation by app request while in multi-window.
+     */
+    public void testSplitscreenLandscapeAppOrientationRequests() throws Exception {
+        requestOrientationInSplitScreen(0 /* landscape */, PORTRAIT_ACTIVITY_NAME);
+    }
+
+    /**
+     * Rotate the device and launch specified activity in split-screen, checking if orientation
+     * didn't change.
+     */
+    private void requestOrientationInSplitScreen(int orientation, String activity)
+            throws Exception {
+        // Set initial orientation.
+        setDeviceRotation(orientation);
+
+        // Launch activities that request orientations and check that device doesn't rotate.
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+
+        launchActivityToSide(false /* randomData */, true /* multipleTaskFlag */, activity);
+        mAmWmState.computeState(mDevice, new String[] {activity});
+        mAmWmState.assertVisibility(activity, true /* visible */);
+        assertEquals("Split-screen apps shouldn't influence device orientation",
+                orientation, mAmWmState.getWmState().getRotation());
+
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                true /* multipleTask */, activity);
+        mAmWmState.computeState(mDevice, new String[] {activity});
+        mAmWmState.assertVisibility(activity, true /* visible */);
+        assertEquals("Split-screen apps shouldn't influence device orientation",
+                orientation, mAmWmState.getWmState().getRotation());
+    }
+
+    /**
+     * Launches activity in docked stack, moves to fullscreen stack and back to docked stack.
+     * Asserts that initial and final reported sizes in docked stack are the same.
+     */
+    private void moveActivitySplitFullSplit(String activityName) throws Exception {
+        // Launch to docked stack and record size.
+        launchActivityInStack(activityName, DOCKED_STACK_ID);
+        final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName,
+                DOCKED_STACK_ID);
+        // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
+        // will come up.
+        launchActivityInStack(activityName, DOCKED_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] { activityName },
+                false /* compareTaskAndStackBounds */);
+
+        // Move to fullscreen stack.
+        moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        assertSizesAreSane(fullscreenSizes, initialDockedSizes);
+
+        // Move activity back to docked stack.
+        moveActivityToStack(activityName, DOCKED_STACK_ID);
+        final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName,
+                DOCKED_STACK_ID);
+
+        // After activity configuration was changed twice it must report same size as original one.
+        assertSizesAreSame(initialDockedSizes, finalDockedSizes);
+    }
+
+    /**
+     * Asserts that after rotation, the aspect ratios of display size, metrics, and configuration
+     * have flipped.
+     */
+    private static void assertSizesRotate(ReportedSizes rotationA, ReportedSizes rotationB)
+            throws Exception {
+        assertEquals(rotationA.displayWidth, rotationA.metricsWidth);
+        assertEquals(rotationA.displayHeight, rotationA.metricsHeight);
+        assertEquals(rotationB.displayWidth, rotationB.metricsWidth);
+        assertEquals(rotationB.displayHeight, rotationB.metricsHeight);
+
+        final boolean beforePortrait = rotationA.displayWidth < rotationA.displayHeight;
+        final boolean afterPortrait = rotationB.displayWidth < rotationB.displayHeight;
+        assertFalse(beforePortrait == afterPortrait);
+
+        final boolean beforeConfigPortrait = rotationA.widthDp < rotationA.heightDp;
+        final boolean afterConfigPortrait = rotationB.widthDp < rotationB.heightDp;
+        assertEquals(beforePortrait, beforeConfigPortrait);
+        assertEquals(afterPortrait, afterConfigPortrait);
+
+        assertEquals(rotationA.smallestWidthDp, rotationB.smallestWidthDp);
+    }
+
+    /**
+     * Throws an AssertionError if fullscreenSizes has widths/heights (depending on aspect ratio)
+     * that are smaller than the dockedSizes.
+     */
+    private static void assertSizesAreSane(ReportedSizes fullscreenSizes, ReportedSizes dockedSizes)
+            throws Exception {
+        final boolean portrait = fullscreenSizes.displayWidth < fullscreenSizes.displayHeight;
+        if (portrait) {
+            assertTrue(dockedSizes.displayHeight < fullscreenSizes.displayHeight);
+            assertTrue(dockedSizes.heightDp < fullscreenSizes.heightDp);
+            assertTrue(dockedSizes.metricsHeight < fullscreenSizes.metricsHeight);
+        } else {
+            assertTrue(dockedSizes.displayWidth < fullscreenSizes.displayWidth);
+            assertTrue(dockedSizes.widthDp < fullscreenSizes.widthDp);
+            assertTrue(dockedSizes.metricsWidth < fullscreenSizes.metricsWidth);
+        }
+    }
+
+    /**
+     * Throws an AssertionError if sizes are different.
+     */
+    private static void assertSizesAreSame(ReportedSizes firstSize, ReportedSizes secondSize)
+            throws Exception {
+        assertEquals(firstSize.widthDp, secondSize.widthDp);
+        assertEquals(firstSize.heightDp, secondSize.heightDp);
+        assertEquals(firstSize.displayWidth, secondSize.displayWidth);
+        assertEquals(firstSize.displayHeight, secondSize.displayHeight);
+        assertEquals(firstSize.metricsWidth, secondSize.metricsWidth);
+        assertEquals(firstSize.metricsHeight, secondSize.metricsHeight);
+        assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp);
+    }
+
+    private ReportedSizes getActivityDisplaySize(String activityName, int stackId)
+            throws Exception {
+        mAmWmState.computeState(mDevice, new String[] { activityName },
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain stack " + stackId, stackId);
+        final ReportedSizes details = getLastReportedSizesForActivity(activityName);
+        assertNotNull(details);
+        return details;
+    }
+
+    private Rectangle getDisplayRect(String activityName)
+            throws Exception {
+        final String windowName = getWindowName(activityName);
+
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+
+        mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
+
+        final List<WindowManagerState.WindowState> tempWindowList = new ArrayList<>();
+        mAmWmState.getWmState().getMatchingVisibleWindowState(windowName, tempWindowList);
+
+        assertEquals("Should have exactly one window state for the activity.", 1,
+                tempWindowList.size());
+
+        WindowManagerState.WindowState windowState = tempWindowList.get(0);
+        assertNotNull("Should have a valid window", windowState);
+
+        WindowManagerState.Display display = mAmWmState.getWmState()
+                .getDisplay(windowState.getDisplayId());
+        assertNotNull("Should be on a display", display);
+
+        return display.getDisplayRect();
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
new file mode 100644
index 0000000..45630e4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerConfigChangeTests
+ */
+public class ActivityManagerConfigChangeTests extends ActivityManagerTestBase {
+
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
+
+    public void testRotation90Relaunch() throws Exception{
+        // Should relaunch on every rotation and receive no onConfigurationChanged()
+        testRotation(TEST_ACTIVITY_NAME, 1, 1, 0);
+    }
+
+    public void testRotation90NoRelaunch() throws Exception {
+        // Should receive onConfigurationChanged() on every rotation and no relaunch
+        testRotation(NO_RELAUNCH_ACTIVITY_NAME, 1, 0, 1);
+    }
+
+    public void testRotation180Relaunch() throws Exception {
+        // Should receive nothing
+        testRotation(TEST_ACTIVITY_NAME, 2, 0, 0);
+    }
+
+    public void testRotation180NoRelaunch() throws Exception {
+        // Should receive nothing
+        testRotation(NO_RELAUNCH_ACTIVITY_NAME, 2, 0, 0);
+    }
+
+    public void testChangeFontScaleRelaunch() throws Exception {
+        // Should relaunch and receive no onConfigurationChanged()
+        testChangeFontScale(TEST_ACTIVITY_NAME, true);
+    }
+
+    public void testChangeFontScaleNoRelaunch() throws Exception {
+        // Should receive onConfigurationChanged() and no relaunch
+        testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false);
+    }
+
+    private void testRotation(
+            String activityName, int rotationStep, int numRelaunch, int numConfigChange)
+                    throws Exception {
+        launchActivity(activityName);
+
+        final String[] waitForActivitiesVisible = new String[] {activityName};
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+
+        setDeviceRotation(4 - rotationStep);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+
+        for (int rotation = 0; rotation < 4; rotation += rotationStep) {
+            clearLogcat();
+            setDeviceRotation(rotation);
+            mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+            assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange);
+        }
+    }
+
+    private void testChangeFontScale(
+            String activityName, boolean relaunch) throws Exception {
+        launchActivity(activityName);
+        final String[] waitForActivitiesVisible = new String[] {activityName};
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+
+        setFontScale(1.0f);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+
+        for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
+            clearLogcat();
+            setFontScale(fontScale);
+            mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+            assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1);
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
new file mode 100644
index 0000000..8bd31bc
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -0,0 +1,429 @@
+/*
+ * 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.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.cts.StateLogger.log;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerDisplayTests
+ */
+public class ActivityManagerDisplayTests extends ActivityManagerTestBase {
+    private static final String DUMPSYS_ACTIVITY_PROCESSES = "dumpsys activity processes";
+
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
+    private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
+
+    private static final int INVALID_DENSITY_DPI = -1;
+    private static final int CUSTOM_DENSITY_DPI = 222;
+
+    /** Temp storage used for parsing. */
+    private final LinkedList<String> mDumpLines = new LinkedList<>();
+
+    private boolean mVirtualDisplayCreated;
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mVirtualDisplayCreated) {
+            executeShellCommand(getDestroyVirtualDisplayCommand());
+        }
+        super.tearDown();
+    }
+
+    /**
+     * Tests that the global configuration is equal to the default display's override configuration.
+     */
+    public void testDefaultDisplayOverrideConfiguration() throws Exception {
+        final ReportedDisplays reportedDisplays = getDisplaysStates();
+        assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig);
+        final DisplayState primaryDisplay = reportedDisplays.getDisplayState(DEFAULT_DISPLAY_ID);
+        assertEquals("Primary display's configuration should not be equal to global configuration.",
+                reportedDisplays.mGlobalConfig, primaryDisplay.mOverrideConfig);
+    }
+
+    /**
+     * Tests that secondary display has override configuration set.
+     */
+    public void testCreateVirtualDisplayWithCustomConfig() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Find the density of created display.
+        final int newDensityDpi = newDisplay.getDpi();
+        assertEquals(CUSTOM_DENSITY_DPI, newDensityDpi);
+
+        // Destroy the created display.
+        executeShellCommand(getDestroyVirtualDisplayCommand());
+    }
+
+    /**
+     * Tests launching an activity on virtual display.
+     */
+    public void testLaunchActivityOnSecondaryDisplay() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+
+        // Check that activity is on the right display.
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Activity launched on secondary display must be resumed",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+
+        // Check that activity config corresponds to display config.
+        final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME);
+        assertEquals("Activity launched on secondary display must have proper configuration",
+                CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
+    }
+
+    /**
+     * Tests launching an activity on virtual display and then launching another activity via shell
+     * command and without specifying the display id - it must appear on the same external display.
+     */
+    public void testConsequentLaunchActivity() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+
+        // Launch second activity without specifying display.
+        launchActivity(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        // Check that activity is launched in focused stack on external display.
+        mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /**
+     * Tests launching an activity on virtual display and then launching another activity from the
+     * first one - it must appear on the secondary display, because it was launched from there.
+     */
+    public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be resumed",
+                LAUNCHING_ACTIVITY);
+
+        // Launch second activity from app on secondary display without specifying display id.
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTask */, TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        // Check that activity is launched in focused stack on external display.
+        mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /**
+     * Tests launching an activity to secondary display from activity on primary display.
+     */
+    public void testLaunchActivityFromAppToSecondaryDisplay() throws Exception {
+        // Start launching activity.
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI,
+                true /* launchInSplitScreen */);
+
+        // Launch activity on secondary display from the app on primary display.
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */, false /* multipleTask*/,
+                TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+
+        // Check that activity is launched on external display.
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /**
+     * Tests launching activities on secondary and then on primary display to see if the stack
+     * visibility is not affected.
+     */
+    public void testLaunchActivitiesAffectsVisibility() throws Exception {
+        // Start launching activity.
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
+
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI,
+                true /* launchInSplitScreen */);
+        mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
+        mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
+
+        // Launch activity on new secondary display.
+        launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+        mAmWmState.waitForValidState(mDevice, TEST_ACTIVITY_NAME);
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+        mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
+        mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
+
+        // Launch activity on primary display and check if it doesn't affect activity on secondary
+        // display.
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTask */, RESIZEABLE_ACTIVITY_NAME);
+        mAmWmState.waitForValidState(mDevice, RESIZEABLE_ACTIVITY_NAME,
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
+        mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
+        mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
+    }
+
+    /** Find the display that was not originally reported in oldDisplays and added in newDisplays */
+    private DisplayState findNewDisplayId(ReportedDisplays oldDisplays,
+            ReportedDisplays newDisplays) {
+        for (Integer displayId : newDisplays.mDisplayStates.keySet()) {
+            if (!oldDisplays.mDisplayStates.containsKey(displayId)) {
+                return newDisplays.getDisplayState(displayId);
+            }
+        }
+
+        return null;
+    }
+
+    /** Create new virtual display with custom density. */
+    private DisplayState createVirtualDisplay(int densityDpi) throws Exception {
+        return createVirtualDisplay(densityDpi, false /* launchInSplitScreen */);
+    }
+
+    /**
+     * Create new virtual display.
+     * @param densityDpi provide custom density for the display.
+     * @param launchInSplitScreen start {@link VirtualDisplayActivity} to side from
+     *                            {@link LaunchingActivity} on primary display.
+     * @return {@link DisplayState} of newly created display.
+     * @throws Exception
+     */
+    private DisplayState createVirtualDisplay(int densityDpi,
+            boolean launchInSplitScreen) throws Exception {
+        // Start an activity that is able to create virtual displays.
+        if (launchInSplitScreen) {
+            launchActivityToSide(false /* randomData */, false /* multipleTaskFlag */,
+                    VIRTUAL_DISPLAY_ACTIVITY);
+        } else {
+            launchActivity(VIRTUAL_DISPLAY_ACTIVITY);
+        }
+        mAmWmState.computeState(mDevice, new String[] {VIRTUAL_DISPLAY_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        final ReportedDisplays originalDS = getDisplaysStates();
+        final int originalDisplayCount = originalDS.mDisplayStates.size();
+
+        // Create virtual display with custom density dpi.
+        executeShellCommand(getCreateVirtualDisplayCommand(densityDpi));
+        mVirtualDisplayCreated = true;
+
+        // Wait for the virtual display to be created and get configurations.
+        final ReportedDisplays ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
+        assertEquals("New virtual display must be created",
+                originalDisplayCount + 1, ds.mDisplayStates.size());
+
+        // Find the newly added display.
+        final DisplayState newDisplay = findNewDisplayId(originalDS, ds);
+        assertNotNull("New virtual display must be created", newDisplay);
+
+        return newDisplay;
+    }
+
+    /** Wait for provided number of displays and report their configurations. */
+    private ReportedDisplays getDisplaysStateAfterCreation(int expectedDisplayCount)
+            throws DeviceNotAvailableException {
+        ReportedDisplays ds = getDisplaysStates();
+
+        while (!ds.isValidState(expectedDisplayCount)) {
+            log("***Waiting for the correct number of displays...");
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                log(e.toString());
+            }
+            ds = getDisplaysStates();
+        }
+
+        return ds;
+    }
+
+    private ReportedDisplays getDisplaysStates() throws DeviceNotAvailableException {
+        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(DUMPSYS_ACTIVITY_PROCESSES, outputReceiver);
+        String dump = outputReceiver.getOutput();
+        mDumpLines.clear();
+
+        Collections.addAll(mDumpLines, dump.split("\\n"));
+
+        return ReportedDisplays.create(mDumpLines);
+    }
+
+    /** Contains the configurations applied to attached displays. */
+    private static final class DisplayState {
+        private int mDisplayId;
+        private String mOverrideConfig;
+
+        private DisplayState(int displayId, String overrideConfig) {
+            mDisplayId = displayId;
+            mOverrideConfig = overrideConfig;
+        }
+
+        private int getDpi() {
+            final String[] configParts = mOverrideConfig.split(" ");
+            for (String part : configParts) {
+                if (part.endsWith("dpi")) {
+                    final String densityDpiString = part.substring(0, part.length() - 3);
+                    return Integer.parseInt(densityDpiString);
+                }
+            }
+
+            return -1;
+        }
+    }
+
+    /** Contains the configurations applied to attached displays. */
+    private static final class ReportedDisplays {
+        private static final Pattern sGlobalConfigurationPattern =
+                Pattern.compile("mGlobalConfiguration: (\\{.*\\})");
+        private static final Pattern sDisplayOverrideConfigurationsPattern =
+                Pattern.compile("Display override configurations:");
+        private static final Pattern sDisplayConfigPattern =
+                Pattern.compile("(\\d+): (\\{.*\\})");
+
+        private String mGlobalConfig;
+        private Map<Integer, DisplayState> mDisplayStates = new HashMap<>();
+
+        static ReportedDisplays create(LinkedList<String> dump) {
+            final ReportedDisplays result = new ReportedDisplays();
+
+            while (!dump.isEmpty()) {
+                final String line = dump.pop().trim();
+
+                Matcher matcher = sDisplayOverrideConfigurationsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    while (ReportedDisplays.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
+                        final String displayOverrideConfigLine = dump.pop().trim();
+                        log(displayOverrideConfigLine);
+                        matcher = sDisplayConfigPattern.matcher(displayOverrideConfigLine);
+                        matcher.matches();
+                        final Integer displayId = Integer.valueOf(matcher.group(1));
+                        result.mDisplayStates.put(displayId,
+                                new DisplayState(displayId, matcher.group(2)));
+                    }
+                    continue;
+                }
+
+                matcher = sGlobalConfigurationPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    result.mGlobalConfig = matcher.group(1);
+                }
+            }
+
+            return result;
+        }
+
+        /** Check if next line in dump matches the pattern and we should continue extracting. */
+        static boolean shouldContinueExtracting(LinkedList<String> dump, Pattern matchingPattern) {
+            if (dump.isEmpty()) {
+                return false;
+            }
+
+            final String line = dump.peek().trim();
+            return matchingPattern.matcher(line).matches();
+        }
+
+        DisplayState getDisplayState(int displayId) {
+            return mDisplayStates.get(displayId);
+        }
+
+        /** Check if reported state is valid. */
+        boolean isValidState(int expectedDisplayCount) {
+            if (mDisplayStates.size() != expectedDisplayCount) {
+                return false;
+            }
+
+            for (Map.Entry<Integer, DisplayState> entry : mDisplayStates.entrySet()) {
+                final DisplayState ds = entry.getValue();
+                if (ds.mDisplayId != DEFAULT_DISPLAY_ID && ds.getDpi() == -1) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static String getCreateVirtualDisplayCommand(int densityDpi) {
+        final StringBuilder commandBuilder
+                = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+        commandBuilder.append(" -f 0x20000000");
+        commandBuilder.append(" --es command create_display");
+        if (densityDpi != INVALID_DENSITY_DPI) {
+            commandBuilder.append(" --ei density_dpi ").append(densityDpi);
+        }
+        return commandBuilder.toString();
+    }
+
+    private static String getDestroyVirtualDisplayCommand() {
+        return getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY) + " -f 0x20000000" +
+                " --es command destroy_display";
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
new file mode 100644
index 0000000..74741d9
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -0,0 +1,377 @@
+/*
+ * 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.cts;
+
+import java.awt.Rectangle;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerDockedStackTests
+ */
+public class ActivityManagerDockedStackTests extends ActivityManagerTestBase {
+
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity";
+    private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
+    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
+    private static final String SINGLE_INSTANCE_ACTIVITY_NAME = "SingleInstanceActivity";
+    private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity";
+
+    private static final int TASK_SIZE = 600;
+    private static final int STACK_SIZE = 300;
+
+    public void testStackList() throws Exception {
+        launchActivity(TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
+    }
+
+    public void testDockActivity() throws Exception {
+        launchActivityInDockStack(TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+    }
+
+    public void testNonResizeableNotDocked() throws Exception {
+        launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME});
+
+        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
+        mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
+        mAmWmState.assertFrontStack(
+                "Fullscreen stack must be front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+    }
+
+    public void testLaunchToSide() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+    }
+
+    public void testLaunchToSideAndBringToFront() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
+        final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        // Launch activity to side.
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, waitForFirstVisible);
+        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
+                TEST_ACTIVITY_NAME);
+
+        // Launch another activity to side to cover first one.
+        launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.computeState(mDevice, waitForSecondVisible);
+        int taskNumberCovered = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertEquals("Fullscreen stack must have one task added.",
+                taskNumberInitial + 1, taskNumberCovered);
+        mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
+                NO_RELAUNCH_ACTIVITY_NAME);
+
+        // Launch activity that was first launched to side. It should be brought to front.
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, waitForFirstVisible);
+        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertEquals("Task number in fullscreen stack must remain the same.",
+                taskNumberCovered, taskNumberFinal);
+        mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
+                TEST_ACTIVITY_NAME);
+    }
+
+    public void testLaunchToSideMultiple() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        final String[] waitForActivitiesVisible =
+            new String[] {TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY};
+
+        // Launch activity to side.
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
+
+        // Try to launch to side same activity again.
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal);
+        mAmWmState.assertFocusedActivity("Launched to side activity must remain in front.",
+                TEST_ACTIVITY_NAME);
+        mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
+    }
+
+    public void testLaunchToSideSingleInstance() throws Exception {
+        launchTargetToSide(SINGLE_INSTANCE_ACTIVITY_NAME, false);
+    }
+
+    public void testLaunchToSideSingleTask() throws Exception {
+        launchTargetToSide(SINGLE_TASK_ACTIVITY_NAME, false);
+    }
+
+    public void testLaunchToSideMultipleWithDifferentIntent() throws Exception {
+        launchTargetToSide(TEST_ACTIVITY_NAME, true);
+    }
+
+    private void launchTargetToSide(String targetActivityName,
+                                    boolean taskCountMustIncrement) throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        final String[] waitForActivitiesVisible =
+            new String[] {targetActivityName, LAUNCHING_ACTIVITY};
+
+        // Launch activity to side with data.
+        launchActivityToSide(true, false, targetActivityName);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
+
+        // Try to launch to side same activity again with different data.
+        launchActivityToSide(true, false, targetActivityName);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberSecondLaunch = mAmWmState.getAmState()
+                .getStackById(FULLSCREEN_WORKSPACE_STACK_ID).getTasks().size();
+        if (taskCountMustIncrement) {
+            mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1,
+                    taskNumberSecondLaunch);
+        } else {
+            mAmWmState.assertEquals("Task number must not change.", taskNumberInitial,
+                    taskNumberSecondLaunch);
+        }
+        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
+                targetActivityName);
+        mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
+
+        // Try to launch to side same activity again with no data.
+        launchActivityToSide(false, false, targetActivityName);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        if (taskCountMustIncrement) {
+            mAmWmState.assertEquals("Task number must be incremented.", taskNumberSecondLaunch + 1,
+                    taskNumberFinal);
+        } else {
+            mAmWmState.assertEquals("Task number must not change.", taskNumberSecondLaunch,
+                    taskNumberFinal);
+        }
+        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
+                targetActivityName);
+        mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
+    }
+
+    public void testLaunchToSideMultipleWithFlag() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        final String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
+
+        // Launch activity to side.
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
+
+        // Try to launch to side same activity again, but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK.
+        launchActivityToSide(false, true);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
+                .getTasks().size();
+        mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1,
+                taskNumberFinal);
+        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
+                TEST_ACTIVITY_NAME);
+        mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.",
+                mAmWmState.getAmState()
+                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
+    }
+
+    public void testRotationWhenDocked() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+
+        // Rotate device single steps (90°) 0-1-2-3.
+        // Each time we compute the state we implicitly assert valid bounds.
+        String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
+        setDeviceRotation(0);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(1);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(2);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(3);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        // Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for double
+        // step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side.
+        setDeviceRotation(1);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(3);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(0);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(2);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        setDeviceRotation(0);
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+    }
+
+    public void testRotationWhenDockedWhileLocked() throws Exception {
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        launchActivityToSide();
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertSanity();
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+
+        String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
+        sleepDevice();
+        setDeviceRotation(0);
+        wakeUpAndUnlockDevice();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+
+        sleepDevice();
+        setDeviceRotation(1);
+        wakeUpAndUnlockDevice();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+
+        sleepDevice();
+        setDeviceRotation(2);
+        wakeUpAndUnlockDevice();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+
+        sleepDevice();
+        setDeviceRotation(3);
+        wakeUpAndUnlockDevice();
+        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+    }
+
+    public void testResizeDockedStack() throws Exception {
+        launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
+        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
+        mAmWmState.assertContainsStack("Must contain fullscreen stack",
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        assertEquals(new Rectangle(0, 0, STACK_SIZE, STACK_SIZE),
+                mAmWmState.getAmState().getStackById(DOCKED_STACK_ID).getBounds());
+        mAmWmState.assertDockedTaskBounds(TASK_SIZE, DOCKED_ACTIVITY_NAME);
+        mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true);
+        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
+    }
+
+    public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
+        final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
+        launchActivity(TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, waitTestActivityName);
+        final Rectangle fullScreenBounds =
+                mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds();
+
+        moveActivityToDockStack(TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, waitTestActivityName);
+        launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+
+        mAmWmState.computeState(mDevice,
+                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
+        final Rectangle initialDockBounds =
+                mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds();
+
+        clearLogcat();
+
+        Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
+        resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+        mAmWmState.computeState(mDevice,
+                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
+
+        // We resize twice to make sure we cross an orientation change threshold for both
+        // activities.
+        newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false);
+        resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+        mAmWmState.computeState(mDevice,
+                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
+        assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
+        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
+    }
+
+    private Rectangle computeNewDockBounds(
+            Rectangle fullscreenBounds, Rectangle dockBounds, boolean reduceSize) {
+        final boolean inLandscape = fullscreenBounds.width > dockBounds.width;
+        // We are either increasing size or reducing it.
+        final float sizeChangeFactor = reduceSize ? 0.5f : 1.5f;
+        final Rectangle newBounds = new Rectangle(dockBounds);
+        if (inLandscape) {
+            // In landscape we change the width.
+            newBounds.width *= sizeChangeFactor;
+        } else {
+            // In portrait we change the height
+            newBounds.height *= sizeChangeFactor;
+        }
+
+        return newBounds;
+    }
+
+    private void launchActivityToSide() throws Exception {
+        launchActivityToSide(false, false);
+    }
+
+    private void launchActivityToSide(boolean randomData, boolean multipleTaskFlag)
+            throws Exception {
+        launchActivityToSide(randomData, multipleTaskFlag, null /* targetActivity */);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
new file mode 100644
index 0000000..b7dff24
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
@@ -0,0 +1,101 @@
+/*
+ * 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.awt.Rectangle;
+import java.util.ArrayList;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerFreeformStackTests
+ */
+public class ActivityManagerFreeformStackTests extends ActivityManagerTestBase {
+
+    private static final String TEST_ACTIVITY = "TestActivity";
+    private static final int TEST_TASK_OFFSET = 20;
+    private static final int TEST_TASK_OFFSET_2 = 100;
+    private static final int TEST_TASK_SIZE_1 = 900;
+    private static final int TEST_TASK_SIZE_2 = TEST_TASK_SIZE_1 * 2;
+    // NOTE: Launching the FreeformActivity will automatically launch the TestActivity
+    // with bounds (0, 0, 900, 900)
+    private static final String FREEFORM_ACTIVITY = "FreeformActivity";
+    private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
+    private static final String NO_RELAUNCH_ACTIVITY = "NoRelaunchActivity";
+
+    public void testFreeformWindowManagementSupport() throws Exception {
+
+        launchActivityInStack(FREEFORM_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
+
+        mAmWmState.computeState(mDevice, new String[] {FREEFORM_ACTIVITY, TEST_ACTIVITY});
+
+        if (!supportsFreeform()) {
+            mAmWmState.assertDoesNotContainStack(
+                    "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
+            return;
+        }
+
+        mAmWmState.assertFrontStack(
+                "Freeform stack must be the front stack.", FREEFORM_WORKSPACE_STACK_ID);
+        mAmWmState.assertVisibility(FREEFORM_ACTIVITY, true);
+        mAmWmState.assertVisibility(TEST_ACTIVITY, true);
+        mAmWmState.assertFocusedActivity(
+                TEST_ACTIVITY + " must be focused Activity", TEST_ACTIVITY);
+        assertEquals(new Rectangle(0, 0, TEST_TASK_SIZE_1, TEST_TASK_SIZE_1),
+                mAmWmState.getAmState().getTaskByActivityName(TEST_ACTIVITY).getBounds());
+    }
+
+    public void testNonResizeableActivityNotLaunchedToFreeform() throws Exception {
+        launchActivityInStack(NON_RESIZEABLE_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
+
+        mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY});
+
+        mAmWmState.assertFrontStack(
+                "Fullscreen stack must be the front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.assertDoesNotContainStack(
+                "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
+    }
+
+    public void testActivityLifeCycleOnResizeFreeformTask() throws Exception {
+        launchActivityInStack(TEST_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
+        launchActivityInStack(NO_RELAUNCH_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
+
+        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
+
+        if (!supportsFreeform()) {
+            mAmWmState.assertDoesNotContainStack(
+                    "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
+            return;
+        }
+
+        resizeActivityTask(TEST_ACTIVITY,
+                TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_1, TEST_TASK_SIZE_2);
+        resizeActivityTask(NO_RELAUNCH_ACTIVITY,
+                TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_1, TEST_TASK_SIZE_2);
+
+        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
+
+        clearLogcat();
+        resizeActivityTask(TEST_ACTIVITY,
+                TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
+        resizeActivityTask(NO_RELAUNCH_ACTIVITY,
+                TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
+        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
+
+        assertActivityLifecycle(TEST_ACTIVITY, true);
+        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
new file mode 100644
index 0000000..a4dfcee
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.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.server.cts;
+
+import java.lang.Exception;
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import java.awt.Rectangle;
+import android.server.cts.WindowManagerState.WindowState;
+import android.server.cts.WindowManagerState.Display;
+
+import static android.server.cts.ActivityAndWindowManagersState.dpToPx;
+import static com.android.ddmlib.Log.LogLevel.INFO;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerManifestLayoutTests
+ */
+public class ActivityManagerManifestLayoutTests extends ActivityManagerTestBase {
+
+    // Test parameters
+    private static final int DEFAULT_WIDTH_DP = 240;
+    private static final int DEFAULT_HEIGHT_DP = 160;
+    private static final float DEFAULT_WIDTH_FRACTION = 0.25f;
+    private static final float DEFAULT_HEIGHT_FRACTION = 0.35f;
+    private static final int MIN_WIDTH_DP = 100;
+    private static final int MIN_HEIGHT_DP = 80;
+
+    private static final int GRAVITY_VER_CENTER = 0x01;
+    private static final int GRAVITY_VER_TOP    = 0x02;
+    private static final int GRAVITY_VER_BOTTOM = 0x04;
+    private static final int GRAVITY_HOR_CENTER = 0x10;
+    private static final int GRAVITY_HOR_LEFT   = 0x20;
+    private static final int GRAVITY_HOR_RIGHT  = 0x40;
+
+    private List<WindowState> mTempWindowList = new ArrayList();
+    private Display mDisplay;
+    private WindowState mWindowState;
+
+    public void testGravityAndDefaultSizeTopLeft() throws Exception {
+        testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_LEFT, false /*fraction*/);
+    }
+
+    public void testGravityAndDefaultSizeTopRight() throws Exception {
+        testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_RIGHT, true /*fraction*/);
+    }
+
+    public void testGravityAndDefaultSizeBottomLeft() throws Exception {
+        testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_LEFT, true /*fraction*/);
+    }
+
+    public void testGravityAndDefaultSizeBottomRight() throws Exception {
+        testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_RIGHT, false /*fraction*/);
+    }
+
+    public void testMinimalSizeFreeform() throws Exception {
+        if (!supportsFreeform()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no freeform support");
+            return;
+        }
+        testMinimalSize(FREEFORM_WORKSPACE_STACK_ID);
+    }
+
+    public void testMinimalSizeDocked() throws Exception {
+        testMinimalSize(DOCKED_STACK_ID);
+    }
+
+    private void testMinimalSize(int stackId) throws Exception {
+        final String activityName = "BottomRightLayoutActivity";
+
+        // Issue command to resize to <0,0,1,1>. We expect the size to be floored at
+        // MIN_WIDTH_DPxMIN_HEIGHT_DP.
+        if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
+            launchActivityInStack(activityName, stackId);
+            resizeActivityTask(activityName, 0, 0, 1, 1);
+        } else { // stackId == DOCKED_STACK_ID
+            launchActivityInDockStack(activityName);
+            resizeDockedStack(1, 1, 1, 1);
+        }
+        getDisplayAndWindowState(activityName, false);
+
+        final int minWidth = dpToPx(MIN_WIDTH_DP, mDisplay.getDpi());
+        final int minHeight = dpToPx(MIN_HEIGHT_DP, mDisplay.getDpi());
+        final Rectangle containingRect = mWindowState.getContainingFrame();
+
+        Assert.assertEquals("Min width is incorrect", minWidth, containingRect.width);
+        Assert.assertEquals("Min height is incorrect", minHeight, containingRect.height);
+    }
+
+    private void testLayout(
+            int vGravity, int hGravity, boolean fraction) throws Exception {
+        if (!supportsFreeform()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no freeform support");
+            return;
+        }
+
+        final String activityName = (vGravity == GRAVITY_VER_TOP ? "Top" : "Bottom")
+                + (hGravity == GRAVITY_HOR_LEFT ? "Left" : "Right") + "LayoutActivity";
+
+        // Launch in freeform stack
+        launchActivityInStack(activityName, FREEFORM_WORKSPACE_STACK_ID);
+
+        getDisplayAndWindowState(activityName, true);
+
+        final Rectangle containingRect = mWindowState.getContainingFrame();
+        final Rectangle appRect = mDisplay.getAppRect();
+        final int expectedWidthPx, expectedHeightPx;
+        // Evaluate the expected window size in px. If we're using fraction dimensions,
+        // calculate the size based on the app rect size. Otherwise, convert the expected
+        // size in dp to px.
+        if (fraction) {
+            expectedWidthPx = (int) (appRect.width * DEFAULT_WIDTH_FRACTION);
+            expectedHeightPx = (int) (appRect.height * DEFAULT_HEIGHT_FRACTION);
+        } else {
+            final int densityDpi = mDisplay.getDpi();
+            expectedWidthPx = dpToPx(DEFAULT_WIDTH_DP, densityDpi);
+            expectedHeightPx = dpToPx(DEFAULT_HEIGHT_DP, densityDpi);
+        }
+
+        verifyFrameSizeAndPosition(
+                vGravity, hGravity, expectedWidthPx, expectedHeightPx, containingRect, appRect);
+    }
+
+    private void getDisplayAndWindowState(String activityName, boolean checkFocus)
+            throws Exception {
+        final String windowName = getWindowName(activityName);
+
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+
+        if (checkFocus) {
+            mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
+        } else {
+            mAmWmState.assertVisibility(activityName, true);
+        }
+
+        mAmWmState.getWmState().getMatchingVisibleWindowState(windowName, mTempWindowList);
+
+        Assert.assertEquals("Should have exactly one window state for the activity.",
+                1, mTempWindowList.size());
+
+        mWindowState = mTempWindowList.get(0);
+        Assert.assertNotNull("Should have a valid window", mWindowState);
+
+        mDisplay = mAmWmState.getWmState().getDisplay(mWindowState.getDisplayId());
+        Assert.assertNotNull("Should be on a display", mDisplay);
+    }
+
+    private void verifyFrameSizeAndPosition(
+            int vGravity, int hGravity, int expectedWidthPx, int expectedHeightPx,
+            Rectangle containingFrame, Rectangle parentFrame) {
+        Assert.assertEquals("Width is incorrect", expectedWidthPx, containingFrame.width);
+        Assert.assertEquals("Height is incorrect", expectedHeightPx, containingFrame.height);
+
+        if (vGravity == GRAVITY_VER_TOP) {
+            Assert.assertEquals("Should be on the top", parentFrame.y, containingFrame.y);
+        } else if (vGravity == GRAVITY_VER_BOTTOM) {
+            Assert.assertEquals("Should be on the bottom",
+                    parentFrame.y + parentFrame.height, containingFrame.y + containingFrame.height);
+        }
+
+        if (hGravity == GRAVITY_HOR_LEFT) {
+            Assert.assertEquals("Should be on the left", parentFrame.x, containingFrame.x);
+        } else if (hGravity == GRAVITY_HOR_RIGHT){
+            Assert.assertEquals("Should be on the right",
+                    parentFrame.x + parentFrame.width, containingFrame.x + containingFrame.width);
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
new file mode 100644
index 0000000..e777311
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -0,0 +1,548 @@
+/*
+ * 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 static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.cts.ActivityManagerState.STATE_STOPPED;
+import android.server.cts.ActivityManagerState.ActivityStack;
+
+import java.awt.Rectangle;
+import java.lang.Exception;
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerPinnedStackTests
+ */
+public class ActivityManagerPinnedStackTests extends ActivityManagerTestBase {
+    private static final String TEST_ACTIVITY = "TestActivity";
+    private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
+    private static final String PIP_ACTIVITY = "PipActivity";
+    private static final String ALWAYS_FOCUSABLE_PIP_ACTIVITY = "AlwaysFocusablePipActivity";
+    private static final String LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY =
+            "LaunchIntoPinnedStackPipActivity";
+    private static final String LAUNCH_TAP_TO_FINISH_PIP_ACTIVITY = "LaunchTapToFinishPipActivity";
+    private static final String LAUNCH_IME_WITH_PIP_ACTIVITY = "LaunchImeWithPipActivity";
+    private static final String PIP_ON_STOP_ACTIVITY = "PipOnStopActivity";
+
+    private static final String EXTRA_ENTER_PIP = "enter_pip";
+    private static final String EXTRA_ENTER_PIP_ASPECT_RATIO = "enter_pip_aspect_ratio";
+    private static final String EXTRA_SET_ASPECT_RATIO = "set_aspect_ratio";
+    private static final String EXTRA_ENTER_PIP_ON_MOVE_TO_BG = "enter_pip_on_move_to_bg";
+    private static final String EXTRA_START_ACTIVITY = "start_activity";
+    private static final String EXTRA_FINISH_SELF_ON_RESUME = "finish_self_on_resume";
+    private static final String EXTRA_REENTER_PIP_ON_EXIT = "reenter_pip_on_exit";
+
+    private static final int ROTATION_0 = 0;
+    private static final int ROTATION_90 = 1;
+    private static final int ROTATION_180 = 2;
+    private static final int ROTATION_270 = 3;
+
+    private static final float FLOAT_COMPARE_EPSILON = 0.005f;
+
+    private static final float VALID_ASPECT_RATIO = 2f;
+    private static final float EXTREME_ASPECT_RATIO = 3f;
+
+    public void testEnterPictureInPictureMode() throws Exception {
+        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"),
+                PIP_ACTIVITY, false, false);
+    }
+
+    public void testMoveTopActivityToPinnedStack() throws Exception {
+        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY, true, false);
+    }
+
+    public void testAlwaysFocusablePipActivity() throws Exception {
+        pinnedStackTester(getAmStartCmd(ALWAYS_FOCUSABLE_PIP_ACTIVITY),
+                ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
+    }
+
+    public void testLaunchIntoPinnedStack() throws Exception {
+        pinnedStackTester(getAmStartCmd(LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY),
+                ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
+    }
+
+    public void testNonTappablePipActivity() throws Exception {
+        // Launch the tap-to-finish activity at a specific place
+        launchActivity(LAUNCH_TAP_TO_FINISH_PIP_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Tap the screen at a known location in the pinned stack bounds, and ensure that it is
+        // not passed down to the top task
+        tapToFinishPip();
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertVisibility(PIP_ACTIVITY, true);
+    }
+
+    public void testPinnedStackDefaultBounds() throws Exception {
+        // Launch a PIP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        setDeviceRotation(ROTATION_0);
+        WindowManagerState wmState = mAmWmState.getWmState();
+        wmState.computeState(mDevice);
+        Rectangle defaultPipBounds = wmState.getDefaultPinnedStackBounds();
+        Rectangle stableBounds = wmState.getStableBounds();
+        assertTrue(defaultPipBounds.width > 0 && defaultPipBounds.height > 0);
+        assertTrue(stableBounds.contains(defaultPipBounds));
+
+        setDeviceRotation(ROTATION_90);
+        wmState = mAmWmState.getWmState();
+        wmState.computeState(mDevice);
+        defaultPipBounds = wmState.getDefaultPinnedStackBounds();
+        stableBounds = wmState.getStableBounds();
+        assertTrue(defaultPipBounds.width > 0 && defaultPipBounds.height > 0);
+        assertTrue(stableBounds.contains(defaultPipBounds));
+    }
+
+    public void testPinnedStackMovementBounds() throws Exception {
+        // Launch a PIP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        setDeviceRotation(ROTATION_0);
+        WindowManagerState wmState = mAmWmState.getWmState();
+        wmState.computeState(mDevice);
+        Rectangle pipMovementBounds = wmState.getPinnedStackMomentBounds();
+        Rectangle stableBounds = wmState.getStableBounds();
+        assertTrue(pipMovementBounds.width > 0 && pipMovementBounds.height > 0);
+        assertTrue(stableBounds.contains(pipMovementBounds));
+
+        setDeviceRotation(ROTATION_90);
+        wmState = mAmWmState.getWmState();
+        wmState.computeState(mDevice);
+        pipMovementBounds = wmState.getPinnedStackMomentBounds();
+        stableBounds = wmState.getStableBounds();
+        assertTrue(pipMovementBounds.width > 0 && pipMovementBounds.height > 0);
+        assertTrue(stableBounds.contains(pipMovementBounds));
+    }
+
+    public void testPinnedStackOutOfBoundsInsetsNonNegative() throws Exception {
+        final WindowManagerState wmState = mAmWmState.getWmState();
+
+        // Launch an activity into the pinned stack
+        launchActivity(LAUNCH_TAP_TO_FINISH_PIP_ACTIVITY);
+
+        // Get the display dimensions
+        WindowManagerState.WindowState windowState = getWindowState(PIP_ACTIVITY);
+        WindowManagerState.Display display = wmState.getDisplay(windowState.getDisplayId());
+        Rectangle displayRect = display.getDisplayRect();
+
+        // Move the pinned stack offscreen
+        String moveStackOffscreenCommand = String.format("am stack resize 4 %d %d %d %d",
+                displayRect.width - 200, 0, displayRect.width + 200, 500);
+        executeShellCommand(moveStackOffscreenCommand);
+
+        // Ensure that the surface insets are not negative
+        windowState = getWindowState(PIP_ACTIVITY);
+        Rectangle contentInsets = windowState.getContentInsets();
+        assertTrue(contentInsets.x >= 0 && contentInsets.y >= 0 && contentInsets.width >= 0 &&
+                contentInsets.height >= 0);
+    }
+
+    public void testPinnedStackInBoundsAfterRotation() throws Exception {
+        // Launch an activity into the pinned stack
+        launchActivity(LAUNCH_TAP_TO_FINISH_PIP_ACTIVITY);
+
+        // Ensure that the PIP stack is fully visible in each orientation
+        setDeviceRotation(ROTATION_0);
+        assertPinnedStackActivityIsInDisplayBounds(PIP_ACTIVITY);
+        setDeviceRotation(ROTATION_90);
+        assertPinnedStackActivityIsInDisplayBounds(PIP_ACTIVITY);
+        setDeviceRotation(ROTATION_180);
+        assertPinnedStackActivityIsInDisplayBounds(PIP_ACTIVITY);
+        setDeviceRotation(ROTATION_270);
+        assertPinnedStackActivityIsInDisplayBounds(PIP_ACTIVITY);
+        setDeviceRotation(ROTATION_0);
+    }
+
+    public void testPinnedStackOffsetForIME() throws Exception {
+        // Launch an activity which shows an IME
+        launchActivity(LAUNCH_IME_WITH_PIP_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        setDeviceRotation(0 /* ROTATION_0 */);
+        assertPinnedStackDoesNotIntersectIME();
+        setDeviceRotation(1 /* ROTATION_90 */);
+        assertPinnedStackDoesNotIntersectIME();
+        setDeviceRotation(2 /* ROTATION_180 */);
+        assertPinnedStackDoesNotIntersectIME();
+        setDeviceRotation(3 /* ROTATION_270 */);
+        assertPinnedStackDoesNotIntersectIME();
+        setDeviceRotation(0 /* ROTATION_0 */);
+    }
+
+    public void testEnterPipAspectRatio() throws Exception {
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(VALID_ASPECT_RATIO));
+        mAmWmState.computeState(mDevice, new String[]{PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Assert that we have entered PIP and that the aspect ratio is correct
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+        Rectangle pinnedStackBounds =
+                mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
+        assertTrue(floatEquals((float) pinnedStackBounds.width / pinnedStackBounds.height,
+                VALID_ASPECT_RATIO));
+    }
+
+    public void testResizePipAspectRatio() throws Exception {
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_SET_ASPECT_RATIO, Float.toString(VALID_ASPECT_RATIO));
+        mAmWmState.computeState(mDevice, new String[]{PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Hacky, but we need to wait for the enterPictureInPicture animation to complete and
+        // the resize to be called before we can check the pinned stack bounds
+        final boolean[] result = new boolean[1];
+        mAmWmState.waitForWithAmState(mDevice, (state) -> {
+            Rectangle pinnedStackBounds = state.getStackById(PINNED_STACK_ID).getBounds();
+            boolean isValidAspectRatio = floatEquals(
+                    (float) pinnedStackBounds.width / pinnedStackBounds.height, VALID_ASPECT_RATIO);
+            result[0] = isValidAspectRatio;
+            return isValidAspectRatio;
+        }, "Waiting for pinned stack to be resized");
+        assertTrue(result[0]);
+    }
+
+    public void testEnterPipExtremeAspectRatios() throws Exception {
+        // Assert that we could not create a pinned stack with an extreme aspect ratio
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(EXTREME_ASPECT_RATIO));
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+    }
+
+    public void testSetPipExtremeAspectRatios() throws Exception {
+        // Try to resize the a normal pinned stack to an extreme aspect ratio and ensure that
+        // fails (the aspect ratio remains the same)
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_ENTER_PIP_ASPECT_RATIO, Float.toString(VALID_ASPECT_RATIO),
+                EXTRA_SET_ASPECT_RATIO, Float.toString(EXTREME_ASPECT_RATIO));
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+        Rectangle pinnedStackBounds =
+                mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
+        assertTrue(floatEquals((float) pinnedStackBounds.width / pinnedStackBounds.height,
+                VALID_ASPECT_RATIO));
+    }
+
+    public void testDisallowPipLaunchFromStoppedActivity() throws Exception {
+        // Launch the bottom pip activity
+        launchActivity(PIP_ON_STOP_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {PIP_ON_STOP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Wait for the bottom pip activity to be stopped
+        mAmWmState.waitForActivityState(mDevice, PIP_ON_STOP_ACTIVITY, STATE_STOPPED);
+
+        // Assert that there is no pinned stack (that enterPictureInPicture() failed)
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+    }
+
+    public void testAutoEnterPictureInPicture() throws Exception {
+        // Launch a test activity so that we're not over home
+        launchActivity(TEST_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Launch the PIP activity with requestAutoEnterPip
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP_ON_MOVE_TO_BG, "true");
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+
+        // Go home and ensure that there is a pinned stack
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFocusedStackId() == HOME_STACK_ID;
+        }, "Waiting for home stack to be focused");
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+    }
+
+    public void testAutoEnterPictureInPictureLaunchActivity() throws Exception {
+        // Launch a test activity so that we're not over home
+        launchActivity(TEST_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Launch the PIP activity with requestAutoEnterPip, and have it start another activity on
+        // top of itself.  Wait for the new activity to be visible and ensure that the pinned stack
+        // was not created in the process
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP_ON_MOVE_TO_BG, "true",
+                EXTRA_START_ACTIVITY, getActivityComponentName(NON_RESIZEABLE_ACTIVITY));
+        mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+
+        // Go home while the pip activity is open and ensure the previous activity is not PIPed
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFocusedStackId() == HOME_STACK_ID;
+        }, "Waiting for home stack to be focused");
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+    }
+
+    public void testAutoEnterPictureInPictureFinish() throws Exception {
+        // Launch a test activity so that we're not over home
+        launchActivity(TEST_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Launch the PIP activity with requestAutoEnterPip, and set it to finish itself after
+        // some period.  Wait for the previous activity to be visible, and ensure that the pinned
+        // stack was not created in the process
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP_ON_MOVE_TO_BG, "true",
+                EXTRA_FINISH_SELF_ON_RESUME, "true");
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+    }
+
+    public void testAutoEnterPictureInPictureAspectRatio() throws Exception {
+        // Launch the PIP activity with requestAutoEnterPip, and set the aspect ratio
+        launchActivity(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP_ON_MOVE_TO_BG, "true",
+                EXTRA_SET_ASPECT_RATIO, Float.toString(VALID_ASPECT_RATIO));
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Go home while the pip activity is open to trigger auto-PIP
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFocusedStackId() == HOME_STACK_ID;
+        }, "Waiting for home stack to be focused");
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Hacky, but we need to wait for the auto-enter picture-in-picture animation to complete
+        // and before we can check the pinned stack bounds
+        final boolean[] result = new boolean[1];
+        mAmWmState.waitForWithAmState(mDevice, (state) -> {
+            Rectangle pinnedStackBounds = state.getStackById(PINNED_STACK_ID).getBounds();
+            boolean isValidAspectRatio = floatEquals(
+                    (float) pinnedStackBounds.width / pinnedStackBounds.height, VALID_ASPECT_RATIO);
+            result[0] = isValidAspectRatio;
+            return isValidAspectRatio;
+        }, "Waiting for pinned stack to be resized");
+        assertTrue(result[0]);
+    }
+
+    public void testAutoEnterPictureInPictureOverPip() throws Exception {
+        // Launch another PIP activity
+        launchActivity(LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {ALWAYS_FOCUSABLE_PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Launch the PIP activity with requestAutoEnterPip
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP_ON_MOVE_TO_BG, "true");
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Go home while the PIP activity is open to trigger auto-enter PIP
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFocusedStackId() == HOME_STACK_ID;
+        }, "Waiting for home stack to be focused");
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Ensure that auto-enter pip failed and that the resumed activity in the pinned stack is
+        // still the first activity
+        final ActivityStack pinnedStack = mAmWmState.getAmState().getStackById(PINNED_STACK_ID);
+        assertTrue(pinnedStack.getTasks().size() == 1);
+        assertTrue(pinnedStack.getTasks().get(0).mRealActivity.equals(getActivityComponentName(
+                ALWAYS_FOCUSABLE_PIP_ACTIVITY)));
+    }
+
+    public void testPipUnPipOverHome() throws Exception {
+        // Go home
+        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFocusedStackId() == HOME_STACK_ID;
+        }, "Waiting for home stack to be focused");
+        // Launch an auto pip activity
+        executeShellCommand(getAmStartCmd(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_REENTER_PIP_ON_EXIT, "true"));
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Tap the screen at a known location in the pinned stack bounds to trigger the activity
+        // to exit and re-enter pip
+        tapToFinishPip();
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFrontStackId(DEFAULT_DISPLAY_ID) == FULLSCREEN_WORKSPACE_STACK_ID;
+        }, "Waiting for PIP to exit to fullscreen");
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFrontStackId(DEFAULT_DISPLAY_ID) == PINNED_STACK_ID;
+        }, "Waiting to re-enter PIP");
+        mAmWmState.assertFocusedStack("Expected home stack focused", HOME_STACK_ID);
+    }
+
+    public void testPipUnPipOverApp() throws Exception {
+        // Launch a test activity so that we're not over home
+        executeShellCommand(getAmStartCmd(TEST_ACTIVITY));
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+
+        // Launch an auto pip activity
+        executeShellCommand(getAmStartCmd(PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true",
+                EXTRA_REENTER_PIP_ON_EXIT, "true"));
+        mAmWmState.computeState(mDevice, new String[] {PIP_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+        // Tap the screen at a known location in the pinned stack bounds to trigger the activity
+        // to exit and re-enter pip
+        tapToFinishPip();
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFrontStackId(DEFAULT_DISPLAY_ID) == FULLSCREEN_WORKSPACE_STACK_ID;
+        }, "Waiting for PIP to exit to fullscreen");
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            return amState.getFrontStackId(DEFAULT_DISPLAY_ID) == PINNED_STACK_ID;
+        }, "Waiting to re-enter PIP");
+        mAmWmState.assertFocusedStack("Expected fullscreen stack focused",
+                FULLSCREEN_WORKSPACE_STACK_ID);
+    }
+
+    /**
+     * Asserts that the pinned stack bounds does not intersect with the IME bounds.
+     */
+    private void assertPinnedStackDoesNotIntersectIME() throws Exception {
+        // Ensure that the IME is visible
+        WindowManagerState wmState = mAmWmState.getWmState();
+        wmState.computeState(mDevice);
+        WindowManagerState.WindowState imeWinState = wmState.getInputMethodWindowState();
+        assertTrue(imeWinState != null);
+
+        // Ensure that the PIP movement is constrained by the display bounds intersecting the
+        // non-IME bounds
+        Rectangle imeContentFrame = imeWinState.getContentFrame();
+        Rectangle imeContentInsets = imeWinState.getGivenContentInsets();
+        Rectangle imeBounds = new Rectangle(imeContentFrame.x + imeContentInsets.x,
+                imeContentFrame.y + imeContentInsets.y,
+                imeContentFrame.width - imeContentInsets.width,
+                imeContentFrame.height - imeContentInsets.height);
+        wmState.computeState(mDevice);
+        Rectangle pipMovementBounds = wmState.getPinnedStackMomentBounds();
+        assertTrue(!pipMovementBounds.intersects(imeBounds));
+    }
+
+    /**
+     * Asserts that the pinned stack bounds is contained in the display bounds.
+     */
+    private void assertPinnedStackActivityIsInDisplayBounds(String activity) throws Exception {
+        final WindowManagerState.WindowState windowState = getWindowState(activity);
+        final WindowManagerState.Display display = mAmWmState.getWmState().getDisplay(
+                windowState.getDisplayId());
+        final Rectangle displayRect = display.getDisplayRect();
+        final Rectangle pinnedStackBounds =
+                mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
+        assertTrue(displayRect.contains(pinnedStackBounds));
+    }
+
+    /**
+     * @return the window state for the given {@param activity}'s window.
+     */
+    private WindowManagerState.WindowState getWindowState(String activity) throws Exception {
+        String windowName = getWindowName(activity);
+        mAmWmState.computeState(mDevice, new String[] {activity});
+        final List<WindowManagerState.WindowState> tempWindowList = new ArrayList<>();
+        mAmWmState.getWmState().getMatchingVisibleWindowState(windowName, tempWindowList);
+        return tempWindowList.get(0);
+    }
+
+    /**
+     * Compares two floats with a common epsilon.
+     */
+    private boolean floatEquals(float f1, float f2) {
+        return Math.abs(f1 - f2) < FLOAT_COMPARE_EPSILON;
+    }
+
+    /**
+     * Triggers a tap over the pinned stack bounds to trigger the PIP to close.
+     */
+    private void tapToFinishPip() throws Exception {
+        Rectangle pinnedStackBounds =
+                mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
+        int tapX = pinnedStackBounds.x + pinnedStackBounds.width - 100;
+        int tapY = pinnedStackBounds.y + pinnedStackBounds.height - 100;
+        executeShellCommand(String.format("input tap %d %d", tapX, tapY));
+    }
+
+    private void pinnedStackTester(String startActivityCmd, String topActivityName,
+            boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
+
+        executeShellCommand(startActivityCmd);
+        if (moveTopToPinnedStack) {
+            executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
+        }
+
+        mAmWmState.waitForValidState(mDevice, topActivityName, PINNED_STACK_ID);
+        mAmWmState.computeState(mDevice, null);
+
+        if (supportsPip()) {
+            final String windowName = getWindowName(topActivityName);
+            mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+            mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
+            mAmWmState.assertVisibility(topActivityName, true);
+
+            if (isFocusable) {
+                mAmWmState.assertFocusedStack(
+                        "Pinned stack must be the focused stack.", PINNED_STACK_ID);
+                mAmWmState.assertFocusedActivity(
+                        "Pinned activity must be focused activity.", topActivityName);
+                mAmWmState.assertFocusedWindow(
+                        "Pinned window must be focused window.", windowName);
+                // Not checking for resumed state here because PiP overlay can be launched on top
+                // in different task by SystemUI.
+            } else {
+                mAmWmState.assertNotFocusedStack(
+                        "Pinned stack can't be the focused stack.", PINNED_STACK_ID);
+                mAmWmState.assertNotFocusedActivity(
+                        "Pinned activity can't be the focused activity.", topActivityName);
+                mAmWmState.assertNotResumedActivity(
+                        "Pinned activity can't be the resumed activity.", topActivityName);
+                mAmWmState.assertNotFocusedWindow(
+                        "Pinned window can't be focused window.", windowName);
+            }
+        } else {
+            mAmWmState.assertDoesNotContainStack(
+                    "Must not contain pinned stack.", PINNED_STACK_ID);
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
new file mode 100644
index 0000000..3c1ba76
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.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 java.lang.Exception;
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import junit.framework.Assert;
+
+import static com.android.ddmlib.Log.LogLevel.INFO;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerReplaceWindowTests
+ */
+public class ActivityManagerReplaceWindowTests extends ActivityManagerTestBase {
+
+    private static final String SLOW_CREATE_ACTIVITY_NAME = "SlowCreateActivity";
+    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
+
+    private List<String> mTempWindowTokens = new ArrayList();
+
+    public void testReplaceWindow_Dock_Relaunch() throws Exception {
+        testReplaceWindow_Dock(true);
+    }
+
+    public void testReplaceWindow_Dock_NoRelaunch() throws Exception {
+        testReplaceWindow_Dock(false);
+    }
+
+    private void testReplaceWindow_Dock(boolean relaunch) throws Exception {
+        final String activityName =
+                relaunch ? SLOW_CREATE_ACTIVITY_NAME : NO_RELAUNCH_ACTIVITY_NAME;
+        final String windowName = getWindowName(activityName);
+        final String amStartCmd = getAmStartCmd(activityName);
+
+        executeShellCommand(amStartCmd);
+
+        // Sleep 2 seconds, then check if the window is started properly.
+        // SlowCreateActivity will do a sleep inside its onCreate() to simulate a
+        // slow-starting app. So instead of relying on WindowManagerState's
+        // retrying mechanism, we do an explicit sleep to avoid excess spews
+        // from WindowManagerState.
+        if (SLOW_CREATE_ACTIVITY_NAME.equals(activityName)) {
+            Thread.sleep(2000);
+        }
+
+        CLog.logAndDisplay(INFO, "==========Before Docking========");
+        final String oldToken = getWindowToken(windowName, activityName);
+
+        // Move to docked stack
+        final int taskId = getActivityTaskId(activityName);
+        final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
+        executeShellCommand(cmd);
+
+        // Sleep 5 seconds, then check if the window is replaced properly.
+        Thread.sleep(5000);
+
+        CLog.logAndDisplay(INFO, "==========After Docking========");
+        final String newToken = getWindowToken(windowName, activityName);
+
+        // For both relaunch and not relaunch case, we'd like the window to be kept.
+        Assert.assertEquals("Window replaced while docking.", oldToken, newToken);
+    }
+
+    private String getWindowToken(String windowName, String activityName)
+            throws Exception {
+        mAmWmState.computeState(mDevice, new String[] {activityName});
+
+        mAmWmState.assertVisibility(activityName, true);
+
+        mAmWmState.getWmState().getMatchingWindowTokens(windowName, mTempWindowTokens);
+
+        Assert.assertEquals("Should have exactly one window for the activity.",
+                1, mTempWindowTokens.size());
+
+        return mTempWindowTokens.get(0);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.java
new file mode 100644
index 0000000..7e79a85
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerTransitionSelectionTests.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.server.cts;
+
+import static android.server.cts.WindowManagerState.TRANSIT_ACTIVITY_CLOSE;
+import static android.server.cts.WindowManagerState.TRANSIT_ACTIVITY_OPEN;
+import static android.server.cts.WindowManagerState.TRANSIT_TASK_CLOSE;
+import static android.server.cts.WindowManagerState.TRANSIT_TASK_OPEN;
+import static android.server.cts.WindowManagerState.TRANSIT_WALLPAPER_CLOSE;
+import static android.server.cts.WindowManagerState.TRANSIT_WALLPAPER_INTRA_CLOSE;
+import static android.server.cts.WindowManagerState.TRANSIT_WALLPAPER_INTRA_OPEN;
+import static android.server.cts.WindowManagerState.TRANSIT_WALLPAPER_OPEN;
+
+/**
+ * This test tests the transition type selection logic in ActivityManager/
+ * WindowManager. BottomActivity is started first, then TopActivity, and we
+ * check the transition type that the system selects when TopActivity enters
+ * or exits under various setups.
+ *
+ * Note that we only require the correct transition type to be reported (eg.
+ * TRANSIT_ACTIVITY_OPEN, TRANSIT_TASK_CLOSE, TRANSIT_WALLPAPER_OPEN, etc.).
+ * The exact animation is unspecified and can be overridden.
+ *
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerTransitionSelectionTests
+ */
+public class ActivityManagerTransitionSelectionTests extends ActivityManagerTestBase {
+
+    private static final String BOTTOM_ACTIVITY_NAME = "BottomActivity";
+    private static final String TOP_ACTIVITY_NAME = "TopActivity";
+    private static final String TRANSLUCENT_TOP_ACTIVITY_NAME = "TranslucentTopActivity";
+
+    //------------------------------------------------------------------------//
+
+    // Test activity open/close under normal timing
+    public void testOpenActivity_NeitherWallpaper() throws Exception {
+        testOpenActivity(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_ACTIVITY_OPEN);
+    }
+
+    public void testCloseActivity_NeitherWallpaper() throws Exception {
+        testCloseActivity(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_ACTIVITY_CLOSE);
+    }
+
+    public void testOpenActivity_BottomWallpaper() throws Exception {
+        testOpenActivity(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_CLOSE);
+    }
+
+    public void testCloseActivity_BottomWallpaper() throws Exception {
+        testCloseActivity(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testOpenActivity_BothWallpaper() throws Exception {
+        testOpenActivity(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_INTRA_OPEN);
+    }
+
+    public void testCloseActivity_BothWallpaper() throws Exception {
+        testCloseActivity(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    //------------------------------------------------------------------------//
+
+    // Test task open/close under normal timing
+    public void testOpenTask_NeitherWallpaper() throws Exception {
+        testOpenTask(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_TASK_OPEN);
+    }
+
+    public void testCloseTask_NeitherWallpaper() throws Exception {
+        testCloseTask(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_TASK_CLOSE);
+    }
+
+    public void testOpenTask_BottomWallpaper() throws Exception {
+        testOpenTask(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_CLOSE);
+    }
+
+    public void testCloseTask_BottomWallpaper() throws Exception {
+        testCloseTask(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testOpenTask_BothWallpaper() throws Exception {
+        testOpenTask(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_INTRA_OPEN);
+    }
+
+    public void testCloseTask_BothWallpaper() throws Exception {
+        testCloseTask(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                false /*slowStop*/, TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    //------------------------------------------------------------------------//
+
+    // Test activity close -- bottom activity slow in stopping
+    // These simulate the case where the bottom activity is resumed
+    // before AM receives its activitiyStopped
+    public void testCloseActivity_NeitherWallpaper_SlowStop() throws Exception {
+        testCloseActivity(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_ACTIVITY_CLOSE);
+    }
+
+    public void testCloseActivity_BottomWallpaper_SlowStop() throws Exception {
+        testCloseActivity(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testCloseActivity_BothWallpaper_SlowStop() throws Exception {
+        testCloseActivity(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    //------------------------------------------------------------------------//
+
+    // Test task close -- bottom task top activity slow in stopping
+    // These simulate the case where the bottom activity is resumed
+    // before AM receives its activitiyStopped
+    public void testCloseTask_NeitherWallpaper_SlowStop() throws Exception {
+        testCloseTask(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_TASK_CLOSE);
+    }
+
+    public void testCloseTask_BottomWallpaper_SlowStop() throws Exception {
+        testCloseTask(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testCloseTask_BothWallpaper_SlowStop() throws Exception {
+        testCloseTask(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                true /*slowStop*/, TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    //------------------------------------------------------------------------//
+
+    /// Test closing of translucent activity/task
+    public void testCloseActivity_NeitherWallpaper_Translucent() throws Exception {
+        testCloseActivityTranslucent(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                TRANSIT_ACTIVITY_CLOSE);
+    }
+
+    public void testCloseActivity_BottomWallpaper_Translucent() throws Exception {
+        testCloseActivityTranslucent(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testCloseActivity_BothWallpaper_Translucent() throws Exception {
+        testCloseActivityTranslucent(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    public void testCloseTask_NeitherWallpaper_Translucent() throws Exception {
+        testCloseTaskTranslucent(false /*bottomWallpaper*/, false /*topWallpaper*/,
+                TRANSIT_TASK_CLOSE);
+    }
+
+    public void testCloseTask_BottomWallpaper_Translucent() throws Exception {
+        testCloseTaskTranslucent(true /*bottomWallpaper*/, false /*topWallpaper*/,
+                TRANSIT_WALLPAPER_OPEN);
+    }
+
+    public void testCloseTask_BothWallpaper_Translucent() throws Exception {
+        testCloseTaskTranslucent(true /*bottomWallpaper*/, true /*topWallpaper*/,
+                TRANSIT_WALLPAPER_INTRA_CLOSE);
+    }
+
+    //------------------------------------------------------------------------//
+
+    private void testOpenActivity(boolean bottomWallpaper,
+            boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
+        testTransitionSelection(true /*testOpen*/, false /*testNewTask*/,
+                bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
+    }
+    private void testCloseActivity(boolean bottomWallpaper,
+            boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
+        testTransitionSelection(false /*testOpen*/, false /*testNewTask*/,
+                bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
+    }
+    private void testOpenTask(boolean bottomWallpaper,
+            boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
+        testTransitionSelection(true /*testOpen*/, true /*testNewTask*/,
+                bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
+    }
+    private void testCloseTask(boolean bottomWallpaper,
+            boolean topWallpaper, boolean slowStop, String expectedTransit) throws Exception {
+        testTransitionSelection(false /*testOpen*/, true /*testNewTask*/,
+                bottomWallpaper, topWallpaper, false /*topTranslucent*/, slowStop, expectedTransit);
+    }
+    private void testCloseActivityTranslucent(boolean bottomWallpaper,
+            boolean topWallpaper, String expectedTransit) throws Exception {
+        testTransitionSelection(false /*testOpen*/, false /*testNewTask*/,
+                bottomWallpaper, topWallpaper, true /*topTranslucent*/,
+                false /*slowStop*/, expectedTransit);
+    }
+    private void testCloseTaskTranslucent(boolean bottomWallpaper,
+            boolean topWallpaper, String expectedTransit) throws Exception {
+        testTransitionSelection(false /*testOpen*/, true /*testNewTask*/,
+                bottomWallpaper, topWallpaper, true /*topTranslucent*/,
+                false /*slowStop*/, expectedTransit);
+    }
+    //------------------------------------------------------------------------//
+
+    private void testTransitionSelection(
+            boolean testOpen, boolean testNewTask,
+            boolean bottomWallpaper, boolean topWallpaper, boolean topTranslucent,
+            boolean testSlowStop, String expectedTransit) throws Exception {
+        String bottomStartCmd = getAmStartCmd(BOTTOM_ACTIVITY_NAME);
+        if (bottomWallpaper) {
+            bottomStartCmd += " --ez USE_WALLPAPER true";
+        }
+        if (testSlowStop) {
+            bottomStartCmd += " --ei STOP_DELAY 3000";
+        }
+        executeShellCommand(bottomStartCmd);
+
+        final String topActivityName = topTranslucent ?
+                TRANSLUCENT_TOP_ACTIVITY_NAME : TOP_ACTIVITY_NAME;
+        final String[] bottomActivityArray = new String[] {BOTTOM_ACTIVITY_NAME};
+        final String[] topActivityArray = new String[] {topActivityName};
+
+        mAmWmState.computeState(mDevice, bottomActivityArray);
+
+        String topStartCmd = getAmStartCmd(topActivityName);
+        if (testNewTask) {
+            topStartCmd += " -f 0x18000000";
+        }
+        if (topWallpaper) {
+            topStartCmd += " --ez USE_WALLPAPER true";
+        }
+        if (!testOpen) {
+            topStartCmd += " --ei FINISH_DELAY 1000";
+        }
+        executeShellCommand(topStartCmd);
+        Thread.sleep(5000);
+        if (testOpen) {
+            mAmWmState.computeState(mDevice, topActivityArray);
+        } else {
+            mAmWmState.computeState(mDevice, bottomActivityArray);
+        }
+
+        assertEquals("Picked wrong transition", expectedTransit,
+                mAmWmState.getWmState().getLastTransition());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java
new file mode 100644
index 0000000..1179b12
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.AnimationBackgroundTests
+ */
+public class AnimationBackgroundTests extends ActivityManagerTestBase {
+
+    public void testAnimationBackground_duringAnimation() throws Exception {
+        launchActivity(LAUNCHING_ACTIVITY);
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTask */, "AnimationTestActivity");
+
+        // Make sure we are in the middle of the animation.
+        Thread.sleep(250);
+        mAmWmState.computeState(mDevice, null);
+        assertTrue("window animation background needs to be showing", mAmWmState.getWmState()
+                .getStack(FULLSCREEN_WORKSPACE_STACK_ID)
+                .isWindowAnimationBackgroundSurfaceShowing());
+    }
+
+    public void testAnimationBackground_gone() throws Exception {
+        launchActivity(LAUNCHING_ACTIVITY);
+        launchActivityFromLaunching(false /* toSide */, false /* randomData */,
+                false /* multipleTask */, "AnimationTestActivity");
+        mAmWmState.computeState(mDevice, new String[] { "AnimationTestActivity "});
+        assertFalse("window animation background needs to be gone", mAmWmState.getWmState()
+                .getStack(FULLSCREEN_WORKSPACE_STACK_ID)
+                .isWindowAnimationBackgroundSurfaceShowing());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.java
new file mode 100644
index 0000000..771eab2
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/DisplaySizeTest.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.server.cts;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+/**
+ * Ensure that compatibility dialog is shown when launching an application with
+ * an unsupported smallest width.
+ *
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.DisplaySizeTest
+ */
+public class DisplaySizeTest extends DeviceTestCase {
+    private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density";
+    private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density";
+
+    private static final String AM_START_COMMAND = "am start -n %s/%s.%s";
+    private static final String AM_FORCE_STOP = "am force-stop %s";
+
+    private static final int ACTIVITY_TIMEOUT_MILLIS = 1000;
+    private static final int WINDOW_TIMEOUT_MILLIS = 1000;
+
+    private ITestDevice mDevice;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevice = getDevice();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        try {
+            resetDensity();
+
+            // Ensure app process is stopped.
+            forceStopPackage("android.displaysize.app");
+            forceStopPackage("android.server.cts");
+        } catch (DeviceNotAvailableException e) {
+            // Do nothing.
+        }
+    }
+
+    public void testCompatibilityDialog() throws Exception {
+        // Launch some other app (not to perform density change on launcher).
+        startActivity("android.server.cts", "TestActivity");
+        verifyWindowDisplayed("TestActivity", ACTIVITY_TIMEOUT_MILLIS);
+
+        setUnsupportedDensity();
+
+        // Launch target app.
+        startActivity("android.displaysize.app", "SmallestWidthActivity");
+        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
+        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
+    }
+
+    public void testCompatibilityDialogWhenFocused() throws Exception {
+        startActivity("android.displaysize.app", "SmallestWidthActivity");
+        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
+
+        setUnsupportedDensity();
+
+        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
+    }
+
+    public void testCompatibilityDialogAfterReturn() throws Exception {
+        // Launch target app.
+        startActivity("android.displaysize.app", "SmallestWidthActivity");
+        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
+        // Launch another activity.
+        startOtherActivityOnTop("android.displaysize.app", "SmallestWidthActivity");
+        verifyWindowDisplayed("TestActivity", ACTIVITY_TIMEOUT_MILLIS);
+
+        setUnsupportedDensity();
+
+        // Go back.
+        mDevice.executeShellCommand("input keyevent 4");
+
+        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
+        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
+    }
+
+    private void setUnsupportedDensity() throws DeviceNotAvailableException {
+        // Set device to 0.85 zoom. It doesn't matter that we're zooming out
+        // since the feature verifies that we're in a non-default density.
+        final int stableDensity = getStableDensity();
+        final int targetDensity = (int) (stableDensity * 0.85);
+        setDensity(targetDensity);
+    }
+
+    private int getStableDensity() {
+        try {
+            final String densityProp;
+            if (mDevice.getSerialNumber().startsWith("emulator-")) {
+                densityProp = DENSITY_PROP_EMULATOR;
+            } else {
+                densityProp = DENSITY_PROP_DEVICE;
+            }
+
+            return Integer.parseInt(mDevice.getProperty(densityProp));
+        } catch (DeviceNotAvailableException e) {
+            return 0;
+        }
+    }
+
+    private void setDensity(int targetDensity) throws DeviceNotAvailableException {
+        mDevice.executeShellCommand("wm density " + targetDensity);
+
+        // Verify that the density is changed.
+        final String output = mDevice.executeShellCommand("wm density");
+        final boolean success = output.contains("Override density: " + targetDensity);
+
+        assertTrue("Failed to set density to " + targetDensity, success);
+    }
+
+    private void resetDensity() throws DeviceNotAvailableException {
+        mDevice.executeShellCommand("wm density reset");
+    }
+
+    private void forceStopPackage(String packageName) throws DeviceNotAvailableException {
+        final String forceStopCmd = String.format(AM_FORCE_STOP, packageName);
+        mDevice.executeShellCommand(forceStopCmd);
+    }
+
+    private void startActivity(String packageName, String activityName)
+            throws DeviceNotAvailableException {
+        mDevice.executeShellCommand(getStartCommand(packageName, activityName));
+    }
+
+    private void startOtherActivityOnTop(String packageName, String activityName)
+            throws DeviceNotAvailableException {
+        final String startCmd = getStartCommand(packageName, activityName)
+                + " -f 0x20000000 --ez launch_another_activity true";
+        mDevice.executeShellCommand(startCmd);
+    }
+
+    private String getStartCommand(String packageName, String activityName) {
+        return String.format(AM_START_COMMAND, packageName, packageName, activityName);
+    }
+
+    private void verifyWindowDisplayed(String windowName, long timeoutMillis)
+            throws DeviceNotAvailableException {
+        boolean success = false;
+
+        // Verify that compatibility dialog is shown within 1000ms.
+        final long timeoutTimeMillis = System.currentTimeMillis() + timeoutMillis;
+        while (!success && System.currentTimeMillis() < timeoutTimeMillis) {
+            final String output = mDevice.executeShellCommand("dumpsys window");
+            success = output.contains(windowName);
+        }
+
+        assertTrue(windowName + " was not displayed", success);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
new file mode 100644
index 0000000..9e23e23
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.KeyguardLockedTests
+ */
+public class KeyguardLockedTests extends KeyguardTestBase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setLockCredential();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        removeLockCredential();
+    }
+
+    public void testLockAndUnlock() throws Exception {
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        unlockDeviceWithCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        assertKeyguardGone();
+    }
+
+    public void testDismissKeyguard() throws Exception {
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        launchActivity("DismissKeyguardActivity");
+        enterAndConfirmLockCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        assertKeyguardGone();
+        mAmWmState.assertVisibility("DismissKeyguardActivity", true);
+    }
+
+    public void testDismissKeyguard_whileOccluded() throws Exception {
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        launchActivity("ShowWhenLockedActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity" });
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        launchActivity("DismissKeyguardActivity");
+        enterAndConfirmLockCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        assertKeyguardGone();
+        mAmWmState.assertVisibility("DismissKeyguardActivity", true);
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", false);
+    }
+
+    public void testDismissKeyguard_fromShowWhenLocked() throws Exception {
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        launchActivity("ShowWhenLockedActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity" });
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguard true");
+        enterAndConfirmLockCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        assertKeyguardGone();
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+    }
+
+    public void testDismissKeyguardActivity_method() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("DismissKeyguardMethodActivity");
+        enterAndConfirmLockCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_cancelled() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("DismissKeyguardMethodActivity");
+        pressBackButton();
+        assertOnDismissCancelledInLogcat();
+        mAmWmState.computeState(mDevice, new String[] {});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", false);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        unlockDeviceWithCredential();
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
new file mode 100644
index 0000000..ca86637
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
@@ -0,0 +1,71 @@
+/*
+ * 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 static android.server.cts.StateLogger.log;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class KeyguardTestBase extends ActivityManagerTestBase {
+
+    protected void assertShowingAndOccluded() {
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardOccluded);
+    }
+
+    protected void assertShowingAndNotOccluded() {
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardOccluded);
+    }
+
+    protected void assertKeyguardGone() {
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+    }
+
+    protected void assertOnDismissSucceededInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded");
+    }
+
+    protected void assertOnDismissCancelledInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled");
+    }
+
+    protected void assertOnDismissErrorInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError");
+    }
+
+    private void assertInLogcat(String activityName, String entry) throws Exception {
+        final Pattern pattern = Pattern.compile("(.+)" + entry);
+        int tries = 0;
+        while (tries < 5) {
+            final String[] lines = getDeviceLogsForComponent(activityName);
+            log("Looking at logcat");
+            for (int i = lines.length - 1; i >= 0; i--) {
+                final String line = lines[i].trim();
+                log(line);
+                Matcher matcher = pattern.matcher(line);
+                if (matcher.matches()) {
+                    return;
+                }
+            }
+            tries++;
+            Thread.sleep(500);
+        }
+        fail("Not in logcat: " + entry);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
new file mode 100644
index 0000000..093639a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -0,0 +1,290 @@
+/*
+ * 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 android.server.cts.WindowManagerState.WindowState;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.KeyguardTests
+ */
+public class KeyguardTests extends KeyguardTestBase {
+
+    public void testKeyguardHidesActivity() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("TestActivity");
+        mAmWmState.computeState(mDevice, new String[] { "TestActivity"});
+        mAmWmState.assertVisibility("TestActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertShowingAndNotOccluded();
+        mAmWmState.assertVisibility("TestActivity", false);
+        unlockDevice();
+    }
+
+    public void testShowWhenLockedActivity() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity"});
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    /**
+     * Tests whether dialogs from SHOW_WHEN_LOCKED activities are also visible if Keyguard is
+     * showing.
+     */
+    public void testShowWhenLockedActivity_withDialog() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedWithDialogActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedWithDialogActivity"});
+        mAmWmState.assertVisibility("ShowWhenLockedWithDialogActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedWithDialogActivity", true);
+        assertTrue(mAmWmState.getWmState().allWindowsVisible(
+                getWindowName("ShowWhenLockedWithDialogActivity")));
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    /**
+     * Tests whether multiple SHOW_WHEN_LOCKED activities are shown if the topmost is translucent.
+     */
+    public void testMultipleShowWhenLockedActivities() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedActivity");
+        launchActivity("ShowWhenLockedTranslucentActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity",
+                "ShowWhenLockedTranslucentActivity"});
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    /**
+     * If we have a translucent SHOW_WHEN_LOCKED_ACTIVITY, the wallpaper should also be showing.
+     */
+    public void testTranslucentShowWhenLockedActivity() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedTranslucentActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedTranslucentActivity"});
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        assertWallpaperShowing();
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    /**
+     * If we have a translucent SHOW_WHEN_LOCKED activity, the activity behind should not be shown.
+     */
+    public void testTranslucentDoesntRevealBehind() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("TestActivity");
+        launchActivity("ShowWhenLockedTranslucentActivity");
+        mAmWmState.computeState(mDevice, new String[] { "TestActivity",
+                "ShowWhenLockedTranslucentActivity"});
+        mAmWmState.assertVisibility("TestActivity", true);
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedTranslucentActivity", true);
+        mAmWmState.assertVisibility("TestActivity", false);
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    public void testDialogShowWhenLockedActivity() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedDialogActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedDialogActivity"});
+        mAmWmState.assertVisibility("ShowWhenLockedDialogActivity", true);
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        mAmWmState.assertVisibility("ShowWhenLockedDialogActivity", true);
+        assertWallpaperShowing();
+        assertShowingAndOccluded();
+        pressHomeButton();
+        unlockDevice();
+    }
+
+    /**
+     * Tests whether we can dismiss Keyguard when we start a FLAG_DISMISS_KEYGUARD activity.
+     */
+    public void testDismissKeyguardActivity() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("DismissKeyguardActivity");
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardActivity"});
+        mAmWmState.assertVisibility("DismissKeyguardActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+    }
+
+    public void testDismissKeyguardActivity_method() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("DismissKeyguardMethodActivity");
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_notTop() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("BroadcastReceiverActivity");
+        launchActivity("TestActivity");
+        executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguardMethod true");
+        assertOnDismissErrorInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        sleepDevice();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        launchActivity("TurnScreenOnDismissKeyguardActivity");
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "TurnScreenOnDismissKeyguardActivity"});
+        mAmWmState.assertVisibility("TurnScreenOnDismissKeyguardActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
+    /**
+     * Tests whether a FLAG_DISMISS_KEYGUARD activity repeatedly dismissed Keyguard, i.e. whenever
+     * lockscreen would show it gets dismissed immediately.
+     */
+    public void testDismissKeyguardActivity_repeating() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("DismissKeyguardActivity");
+        for (int i = 0; i < 3; i++) {
+            gotoKeyguard();
+            mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardActivity"});
+            mAmWmState.assertVisibility("DismissKeyguardActivity", true);
+            assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        }
+    }
+
+    public void testDismissKeyguard_fromShowWhenLocked() throws Exception {
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        launchActivity("ShowWhenLockedActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity" });
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguard true");
+        mAmWmState.waitForKeyguardGone(mDevice);
+        assertKeyguardGone();
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+    }
+
+    public void testKeyguardLock() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        launchActivity("KeyguardLockActivity");
+        mAmWmState.computeState(mDevice, new String[] { "KeyguardLockActivity" });
+        mAmWmState.assertVisibility("KeyguardLockActivity", true);
+        executeShellCommand("am broadcast -a trigger_broadcast --ez finish true");
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+    }
+
+    public void testUnoccludeRotationChange() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        gotoKeyguard();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        assertShowingAndNotOccluded();
+        executeShellCommand(getAmStartCmd("ShowWhenLockedActivity"));
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity" });
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
+        setDeviceRotation(1);
+        pressHomeButton();
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        mAmWmState.waitForDisplayUnfrozen(mDevice);
+        mAmWmState.assertSanity();
+        mAmWmState.assertHomeActivityVisible(false);
+        assertShowingAndNotOccluded();
+        mAmWmState.assertVisibility("ShowWhenLockedActivity", false);
+    }
+
+    private void assertWallpaperShowing() {
+        WindowState wallpaper =
+                mAmWmState.getWmState().findFirstWindowWithType(WindowState.TYPE_WALLPAPER);
+        assertNotNull(wallpaper);
+        assertTrue(wallpaper.isShown());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java
new file mode 100644
index 0000000..4aa663a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTransitionTests.java
@@ -0,0 +1,90 @@
+/*
+ * 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 static android.server.cts.WindowManagerState.TRANSIT_ACTIVITY_OPEN;
+import static android.server.cts.WindowManagerState.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.server.cts.WindowManagerState.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+import static android.server.cts.WindowManagerState.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.server.cts.WindowManagerState.TRANSIT_KEYGUARD_UNOCCLUDE;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.KeyguardTransitionTests
+ */
+public class KeyguardTransitionTests extends ActivityManagerTestBase {
+
+    public void testUnlock() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("TestActivity");
+        gotoKeyguard();
+        unlockDevice();
+        mAmWmState.computeState(mDevice, new String[] { "TestActivity"} );
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_GOING_AWAY,
+                mAmWmState.getWmState().getLastTransition());
+    }
+
+    public void testUnlockWallpaper() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("WallpaperActivity");
+        gotoKeyguard();
+        unlockDevice();
+        mAmWmState.computeState(mDevice, new String[] { "WallpaperActivity"} );
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+                mAmWmState.getWmState().getLastTransition());
+    }
+
+    public void testOcclude() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        gotoKeyguard();
+        launchActivity("ShowWhenLockedActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedActivity"} );
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_OCCLUDE,
+                mAmWmState.getWmState().getLastTransition());
+    }
+
+    public void testUnocclude() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedActivity");
+        gotoKeyguard();
+        launchActivity("TestActivity");
+        mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
+        mAmWmState.computeState(mDevice, null);
+        assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_UNOCCLUDE,
+                mAmWmState.getWmState().getLastTransition());
+    }
+
+    public void testNewActivityDuringOccluded() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        launchActivity("ShowWhenLockedActivity");
+        gotoKeyguard();
+        launchActivity("ShowWhenLockedWithDialogActivity");
+        mAmWmState.computeState(mDevice, new String[] { "ShowWhenLockedWithDialogActivity" });
+        assertEquals("Picked wrong transition", TRANSIT_ACTIVITY_OPEN,
+                mAmWmState.getWmState().getLastTransition());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
new file mode 100644
index 0000000..993ba94
--- /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
+
+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/activityandwindowmanager/util/run-test b/hostsidetests/services/activityandwindowmanager/util/run-test
new file mode 100755
index 0000000..131fbc5
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/run-test
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Helper script for running CTS tests with all the right params.
+# Example usage:
+#  run-test <package_name>  // To run all the tests in a package.
+#  run-test <package_name>.<class_name>  // To run all the tests in a class.
+#  run-test <package_name>.<class_name>#<method_name>  // To run a specific test in a class.
+
+echo " "
+echo "Running test...$1"
+echo " "
+cts-tradefed run commandAndExit cts-dev --module CtsServicesHostTestCases --test $1 --disable-reboot --skip-device-info --skip-all-system-status-check --skip-preconditions
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
new file mode 100644
index 0000000..7728761
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -0,0 +1,626 @@
+/*
+ * 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 static android.server.cts.ActivityManagerTestBase.FREEFORM_WORKSPACE_STACK_ID;
+import static android.server.cts.ActivityManagerTestBase.PINNED_STACK_ID;
+import static android.server.cts.StateLogger.log;
+
+import android.server.cts.ActivityManagerState.ActivityStack;
+import android.server.cts.ActivityManagerState.ActivityTask;
+import android.server.cts.WindowManagerState.WindowStack;
+import android.server.cts.WindowManagerState.WindowState;
+import android.server.cts.WindowManagerState.WindowTask;
+
+import com.android.tradefed.device.ITestDevice;
+
+import junit.framework.Assert;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+/** Combined state of the activity manager and window manager. */
+public class ActivityAndWindowManagersState extends Assert {
+
+    // Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
+    // (Needed in host-side tests to convert dp to px.)
+    private static final int DISPLAY_DENSITY_DEFAULT = 160;
+    public static final int DEFAULT_DISPLAY_ID = 0;
+
+    // Default minimal size of resizable task, used if none is set explicitly.
+    // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
+    private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220;
+
+    private ActivityManagerState mAmState = new ActivityManagerState();
+    private WindowManagerState mWmState = new WindowManagerState();
+
+    private final List<WindowManagerState.WindowState> mTempWindowList = new ArrayList<>();
+
+    private boolean mUseActivityNames = true;
+
+    /**
+     * Compute AM and WM state of device, check sanity and bounds.
+     * WM state will include only visible windows, stack and task bounds will be compared.
+     *
+     * @param device test device.
+     * @param waitForActivitiesVisible array of activity names to wait for.
+     */
+    public void computeState(ITestDevice device, String[] waitForActivitiesVisible)
+            throws Exception {
+        computeState(device, waitForActivitiesVisible, true);
+    }
+
+    /**
+     * Compute AM and WM state of device, check sanity and bounds.
+     *
+     * @param device test device.
+     * @param waitForActivitiesVisible array of activity names to wait for.
+     * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
+     *                                  'false' otherwise.
+     */
+    void computeState(ITestDevice device, String[] waitForActivitiesVisible,
+                      boolean compareTaskAndStackBounds) throws Exception {
+        waitForValidState(device, waitForActivitiesVisible, null /* stackIds */,
+                compareTaskAndStackBounds);
+
+        assertSanity();
+        assertValidBounds(compareTaskAndStackBounds);
+    }
+
+    /**
+     * By default computeState allows you to pass only the activity name it and
+     * it will generate the full window name for the main activity window. In the
+     * case of secondary application windows though this isn't helpful, as they
+     * may follow a different format, so this method lets you disable that behavior,
+     * prior to calling a computeState variant
+     */
+    void setUseActivityNamesForWindowNames(boolean useActivityNames) {
+        mUseActivityNames = useActivityNames;
+    }
+
+    /**
+     * Compute AM and WM state of device, wait for the activity records to be added, and
+     * wait for debugger window to show up.
+     *
+     * This should only be used when starting with -D (debugger) option, where we pop up the
+     * waiting-for-debugger window, but real activity window won't show up since we're waiting
+     * for debugger.
+     */
+    void waitForDebuggerWindowVisible(
+            ITestDevice device, String[] waitForActivityRecords) throws Exception {
+        int retriesLeft = 5;
+        do {
+            mAmState.computeState(device);
+            mWmState.computeState(device);
+            if (shouldWaitForDebuggerWindow() ||
+                    shouldWaitForActivityRecords(waitForActivityRecords)) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+    }
+
+    /**
+     * Wait for the activity to appear and for valid state in AM and WM.
+     *
+     * @param device test device.
+     * @param waitForActivityVisible name of activity to wait for.
+     */
+    void waitForValidState(ITestDevice device, String waitForActivityVisible)
+            throws Exception {
+        waitForValidState(device, new String[]{waitForActivityVisible}, null /* stackIds */,
+                false /* compareTaskAndStackBounds */);
+    }
+
+    /**
+     * Wait for the activity to appear in proper stack and for valid state in AM and WM.
+     *
+     * @param device test device.
+     * @param waitForActivityVisible name of activity to wait for.
+     * @param stackId id of the stack where provided activity should be found.
+     */
+    void waitForValidState(ITestDevice device, String waitForActivityVisible, int stackId)
+            throws Exception {
+        waitForValidState(device, new String[]{waitForActivityVisible}, new int[]{stackId},
+                false /* compareTaskAndStackBounds */);
+    }
+
+    /**
+     * Wait for the activities to appear in proper stacks and for valid state in AM and WM.
+     *
+     * @param device test device.
+     * @param waitForActivitiesVisible array of activity names to wait for.
+     * @param stackIds ids of stack where provided activities should be found.
+     *                 Pass null to skip this check.
+     */
+    void waitForValidState(ITestDevice device, String[] waitForActivitiesVisible, int[] stackIds,
+            boolean compareTaskAndStackBounds) throws Exception {
+        int retriesLeft = 5;
+        do {
+            // TODO: Get state of AM and WM at the same time to avoid mismatches caused by
+            // requesting dump in some intermediate state.
+            mAmState.computeState(device);
+            mWmState.computeState(device);
+            if (shouldWaitForValidStacks(compareTaskAndStackBounds)
+                    || shouldWaitForActivities(waitForActivitiesVisible, stackIds)) {
+                log("***Waiting for valid stacks and activities states...");
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+    }
+
+    void waitForHomeActivityVisible(ITestDevice device) throws Exception {
+        waitForWithAmState(device, ActivityManagerState::isHomeActivityVisible,
+                "***Waiting for home activity to be visible...");
+    }
+
+    void waitForKeyguardShowingAndNotOccluded(ITestDevice device) throws Exception {
+        waitForWithAmState(device, state -> state.getKeyguardControllerState().keyguardShowing
+                        && !state.getKeyguardControllerState().keyguardOccluded,
+                "***Waiting for Keyguard showing...");
+    }
+
+    void waitForKeyguardGone(ITestDevice device) throws Exception {
+        waitForWithAmState(device, state -> !state.getKeyguardControllerState().keyguardShowing,
+                "***Waiting for Keyguard gone...");
+    }
+
+    void waitForRotation(ITestDevice device, int rotation) throws Exception {
+        waitForWithWmState(device, state -> state.getRotation() == rotation,
+                "***Waiting for Rotation: " + rotation);
+    }
+
+    void waitForDisplayUnfrozen(ITestDevice device) throws Exception {
+        waitForWithWmState(device, state -> !state.isDisplayFrozen(),
+                "***Waiting for Display unfrozen");
+    }
+
+    void waitForActivityState(ITestDevice device, String activityName, String activityState)
+            throws Exception {
+        waitForWithAmState(device, state -> state.hasActivityState(activityName, activityState),
+                "***Waiting for Activity State: " + activityState);
+    }
+
+    void waitForWithAmState(ITestDevice device, Predicate<ActivityManagerState> waitCondition,
+            String message) throws Exception{
+        waitFor(device, (amState, wmState) -> waitCondition.test(amState), message);
+    }
+
+    void waitForWithWmState(ITestDevice device, Predicate<WindowManagerState> waitCondition,
+            String message) throws Exception{
+        waitFor(device, (amState, wmState) -> waitCondition.test(wmState), message);
+    }
+
+    void waitFor(ITestDevice device,
+            BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message)
+            throws Exception {
+        int retriesLeft = 5;
+        do {
+            mAmState.computeState(device);
+            mWmState.computeState(device);
+            if (!waitCondition.test(mAmState, mWmState)) {
+                log(message);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+    }
+
+    private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
+        if (!taskListsInAmAndWmAreEqual()) {
+            // We want to wait for equal task lists in AM and WM in case we caught them in the
+            // middle of some state change operations.
+            log("***taskListsInAmAndWmAreEqual=false");
+            return true;
+        }
+        if (!stackBoundsInAMAndWMAreEqual()) {
+            // We want to wait a little for the stacks in AM and WM to have equal bounds as there
+            // might be a transition animation ongoing when we got the states from WM AM separately.
+            log("***stackBoundsInAMAndWMAreEqual=false");
+            return true;
+        }
+        try {
+            // Temporary fix to avoid catching intermediate state with different task bounds in AM
+            // and WM.
+            assertValidBounds(compareTaskAndStackBounds);
+        } catch (AssertionError e) {
+            log("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
+            return true;
+        }
+        return false;
+    }
+
+    private boolean shouldWaitForActivities(String[] waitForActivitiesVisible, int[] stackIds) {
+        if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
+            return false;
+        }
+        // If the caller is interested in us waiting for some particular activity windows to be
+        // visible before compute the state. Check for the visibility of those activity windows
+        // and for placing them in correct stacks (if requested).
+        boolean allActivityWindowsVisible = true;
+        boolean tasksInCorrectStacks = true;
+        List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
+        for (int i = 0; i < waitForActivitiesVisible.length; i++) {
+            // Check if window is visible - it should be represented as one of the window states.
+            final String windowName = mUseActivityNames ?
+                    ActivityManagerTestBase.getWindowName(waitForActivitiesVisible[i])
+                    : waitForActivitiesVisible[i];
+            final String activityComponentName =
+                    ActivityManagerTestBase.getActivityComponentName(waitForActivitiesVisible[i]);
+
+            mWmState.getMatchingVisibleWindowState(windowName, matchingWindowStates);
+            boolean activityWindowVisible = !matchingWindowStates.isEmpty();
+            if (!activityWindowVisible) {
+                log("Activity window not visible: " + windowName);
+                allActivityWindowsVisible = false;
+            } else if (!mAmState.isActivityVisible(activityComponentName)) {
+                log("Activity not visible: " + activityComponentName);
+                allActivityWindowsVisible = false;
+            } else if (stackIds != null) {
+                // Check if window is already in stack requested by test.
+                boolean windowInCorrectStack = false;
+                for (WindowManagerState.WindowState ws : matchingWindowStates) {
+                    if (ws.getStackId() == stackIds[i]) {
+                        windowInCorrectStack = true;
+                        break;
+                    }
+                }
+                if (!windowInCorrectStack) {
+                    log("Window in incorrect stack: " + waitForActivitiesVisible[i]);
+                    tasksInCorrectStacks = false;
+                }
+            }
+        }
+        return !allActivityWindowsVisible || !tasksInCorrectStacks;
+    }
+
+    private boolean shouldWaitForDebuggerWindow() {
+        List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
+        mWmState.getMatchingVisibleWindowState("android.server.cts", matchingWindowStates);
+        for (WindowState ws : matchingWindowStates) {
+            if (ws.isDebuggerWindow()) {
+                return false;
+            }
+        }
+        log("Debugger window not available yet");
+        return true;
+    }
+
+    private boolean shouldWaitForActivityRecords(String[] waitForActivityRecords) {
+        if (waitForActivityRecords == null || waitForActivityRecords.length == 0) {
+            return false;
+        }
+        // Check if the activity records we're looking for is already added.
+        for (int i = 0; i < waitForActivityRecords.length; i++) {
+            if (!mAmState.isActivityVisible(waitForActivityRecords[i])) {
+                log("ActivityRecord " + waitForActivityRecords[i] + " not visible yet");
+                return true;
+            }
+        }
+        return false;
+    }
+
+    ActivityManagerState getAmState() {
+        return mAmState;
+    }
+
+    public WindowManagerState getWmState() {
+        return mWmState;
+    }
+
+    void assertSanity() throws Exception {
+        assertTrue("Must have stacks", mAmState.getStackCount() > 0);
+        if (!mAmState.getKeyguardControllerState().keyguardShowing) {
+            assertEquals("There should be one and only one resumed activity in the system.",
+                    1, mAmState.getResumedActivitiesCount());
+        }
+        assertNotNull("Must have focus activity.", mAmState.getFocusedActivity());
+
+        for (ActivityStack aStack : mAmState.getStacks()) {
+            final int stackId = aStack.mStackId;
+            for (ActivityTask aTask : aStack.getTasks()) {
+                assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId);
+            }
+        }
+
+        assertNotNull("Must have front window.", mWmState.getFrontWindow());
+        assertNotNull("Must have focused window.", mWmState.getFocusedWindow());
+        assertNotNull("Must have app.", mWmState.getFocusedApp());
+    }
+
+    void assertContainsStack(String msg, int stackId) throws Exception {
+        assertTrue(msg, mAmState.containsStack(stackId));
+        assertTrue(msg, mWmState.containsStack(stackId));
+    }
+
+    void assertDoesNotContainStack(String msg, int stackId) throws Exception {
+        assertFalse(msg, mAmState.containsStack(stackId));
+        assertFalse(msg, mWmState.containsStack(stackId));
+    }
+
+    void assertFrontStack(String msg, int stackId) throws Exception {
+        assertEquals(msg, stackId, mAmState.getFrontStackId(DEFAULT_DISPLAY_ID));
+        assertEquals(msg, stackId, mWmState.getFrontStackId(DEFAULT_DISPLAY_ID));
+    }
+
+    void assertFocusedStack(String msg, int stackId) throws Exception {
+        assertEquals(msg, stackId, mAmState.getFocusedStackId());
+    }
+
+    void assertNotFocusedStack(String msg, int stackId) throws Exception {
+        if (stackId == mAmState.getFocusedStackId()) {
+            failNotEquals(msg, stackId, mAmState.getFocusedStackId());
+        }
+    }
+
+    void assertFocusedActivity(String msg, String activityName) throws Exception {
+        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        assertEquals(msg, componentName, mAmState.getFocusedActivity());
+        assertEquals(msg, componentName, mWmState.getFocusedApp());
+    }
+
+    void assertNotFocusedActivity(String msg, String activityName) throws Exception {
+        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        if (mAmState.getFocusedActivity().equals(componentName)) {
+            failNotEquals(msg, mAmState.getFocusedActivity(), componentName);
+        }
+        if (mWmState.getFocusedApp().equals(componentName)) {
+            failNotEquals(msg, mWmState.getFocusedApp(), componentName);
+        }
+    }
+
+    void assertResumedActivity(String msg, String activityName) throws Exception {
+        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        assertEquals(msg, componentName, mAmState.getResumedActivity());
+    }
+
+    void assertNotResumedActivity(String msg, String activityName) throws Exception {
+        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        if (mAmState.getResumedActivity().equals(componentName)) {
+            failNotEquals(msg, mAmState.getResumedActivity(), componentName);
+        }
+    }
+
+    void assertFocusedWindow(String msg, String windowName) {
+        assertEquals(msg, windowName, mWmState.getFocusedWindow());
+    }
+
+    void assertNotFocusedWindow(String msg, String windowName) {
+        if (mWmState.getFocusedWindow().equals(windowName)) {
+            failNotEquals(msg, mWmState.getFocusedWindow(), windowName);
+        }
+    }
+
+    void assertFrontWindow(String msg, String windowName) {
+        assertEquals(msg, windowName, mWmState.getFrontWindow());
+    }
+
+    void assertVisibility(String activityName, boolean visible) {
+        final String activityComponentName =
+                ActivityManagerTestBase.getActivityComponentName(activityName);
+        final String windowName =
+                ActivityManagerTestBase.getWindowName(activityName);
+        assertVisibility(activityComponentName, windowName, visible);
+    }
+
+    private void assertVisibility(String activityComponentName, String windowName,
+            boolean visible) {
+        final boolean activityVisible = mAmState.isActivityVisible(activityComponentName);
+        final boolean windowVisible = mWmState.isWindowVisible(windowName);
+
+        if (visible) {
+            assertTrue("Activity=" + activityComponentName + " must be visible.", activityVisible);
+            assertTrue("Window=" + windowName + " must be visible.", windowVisible);
+        } else {
+            assertFalse("Activity=" + activityComponentName + " must NOT be visible.",
+                    activityVisible);
+            assertFalse("Window=" + windowName + " must NOT be visible.", windowVisible);
+        }
+    }
+
+    void assertHomeActivityVisible(boolean visible) {
+        String name = mAmState.getHomeActivityName();
+        assertNotNull(name);
+        assertVisibility(name, getWindowNameForActivityName(name), visible);
+    }
+
+    private String getWindowNameForActivityName(String activityName) {
+        return activityName.replaceAll("(.*)\\/\\.", "$1/$1.");
+    }
+
+    boolean taskListsInAmAndWmAreEqual() {
+        for (ActivityStack aStack : mAmState.getStacks()) {
+            final int stackId = aStack.mStackId;
+            final WindowStack wStack = mWmState.getStack(stackId);
+            if (wStack == null) {
+                log("Waiting for stack setup in WM, stackId=" + stackId);
+                return false;
+            }
+
+            for (ActivityTask aTask : aStack.getTasks()) {
+                if (wStack.getTask(aTask.mTaskId) == null) {
+                    log("Task is in AM but not in WM, waiting for it to settle, taskId="
+                            + aTask.mTaskId);
+                    return false;
+                }
+            }
+
+            for (WindowTask wTask : wStack.mTasks) {
+                if (aStack.getTask(wTask.mTaskId) == null) {
+                    log("Task is in WM but not in AM, waiting for it to settle, taskId="
+                            + wTask.mTaskId);
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    boolean stackBoundsInAMAndWMAreEqual() {
+        for (ActivityStack aStack : mAmState.getStacks()) {
+            final int stackId = aStack.mStackId;
+            final WindowStack wStack = mWmState.getStack(stackId);
+            if (aStack.isFullscreen() != wStack.isFullscreen()) {
+                log("Waiting for correct fullscreen state, stackId=" + stackId);
+                return false;
+            }
+
+            final Rectangle aStackBounds = aStack.getBounds();
+            final Rectangle wStackBounds = wStack.getBounds();
+
+            if (aStack.isFullscreen()) {
+                if (aStackBounds != null) {
+                    log("Waiting for correct stack state in AM, stackId=" + stackId);
+                    return false;
+                }
+            } else if (!Objects.equals(aStackBounds, wStackBounds)) {
+                // If stack is not fullscreen - comparing bounds. Not doing it always because
+                // for fullscreen stack bounds in WM can be either null or equal to display size.
+                log("Waiting for stack bound equality in AM and WM, stackId=" + stackId);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /** Check task bounds when docked to top/left. */
+    void assertDockedTaskBounds(int taskSize, String activityName) {
+        // Task size can be affected by default minimal size.
+        int defaultMinimalTaskSize = defaultMinimalTaskSize(
+                mAmState.getStackById(ActivityManagerTestBase.DOCKED_STACK_ID).mDisplayId);
+        int targetSize = Math.max(taskSize, defaultMinimalTaskSize);
+
+        assertEquals(new Rectangle(0, 0, targetSize, targetSize),
+                mAmState.getTaskByActivityName(activityName).getBounds());
+    }
+
+    void assertValidBounds(boolean compareTaskAndStackBounds) {
+        for (ActivityStack aStack : mAmState.getStacks()) {
+            final int stackId = aStack.mStackId;
+            final WindowStack wStack = mWmState.getStack(stackId);
+            assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack);
+
+            assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId,
+                    aStack.isFullscreen(), wStack.isFullscreen());
+
+            final Rectangle aStackBounds = aStack.getBounds();
+            final Rectangle wStackBounds = wStack.getBounds();
+
+            if (aStack.isFullscreen()) {
+                assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds);
+            } else {
+                assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId,
+                        aStackBounds, wStackBounds);
+            }
+
+            for (ActivityTask aTask : aStack.getTasks()) {
+                final int taskId = aTask.mTaskId;
+                final WindowTask wTask = wStack.getTask(taskId);
+                assertNotNull(
+                        "taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask);
+
+                final boolean aTaskIsFullscreen = aTask.isFullscreen();
+                final boolean wTaskIsFullscreen = wTask.isFullscreen();
+                assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId
+                        + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
+
+                final Rectangle aTaskBounds = aTask.getBounds();
+                final Rectangle wTaskBounds = wTask.getBounds();
+
+                if (aTaskIsFullscreen) {
+                    assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
+                            aTaskBounds);
+                } else {
+                    assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
+                            + ", stackId=" + stackId, aTaskBounds, wTaskBounds);
+
+                    if (compareTaskAndStackBounds && stackId != FREEFORM_WORKSPACE_STACK_ID) {
+                        int aTaskMinWidth = aTask.getMinWidth();
+                        int aTaskMinHeight = aTask.getMinHeight();
+
+                        if (aTaskMinWidth == -1 || aTaskMinHeight == -1) {
+                            // Minimal dimension(s) not set for task - it should be using defaults.
+                            int defaultMinimalSize = defaultMinimalTaskSize(aStack.mDisplayId);
+
+                            if (aTaskMinWidth == -1) {
+                                aTaskMinWidth = defaultMinimalSize;
+                            }
+                            if (aTaskMinHeight == -1) {
+                                aTaskMinHeight = defaultMinimalSize;
+                            }
+                        }
+
+                        if (aStackBounds.getWidth() >= aTaskMinWidth
+                                && aStackBounds.getHeight() >= aTaskMinHeight
+                                || stackId == PINNED_STACK_ID) {
+                            // Bounds are not smaller then minimal possible, so stack and task
+                            // bounds must be equal.
+                            assertEquals("Task bounds must be equal to stack bounds taskId="
+                                    + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
+                        } else {
+                            // Minimal dimensions affect task size, so bounds of task and stack must
+                            // be different - will compare dimensions instead.
+                            int targetWidth = (int) Math.max(aTaskMinWidth,
+                                    aStackBounds.getWidth());
+                            assertEquals("Task width must be set according to minimal width"
+                                            + " taskId=" + taskId + ", stackId=" + stackId,
+                                    targetWidth, (int) wTaskBounds.getWidth());
+                            int targetHeight = (int) Math.max(aTaskMinHeight,
+                                    aStackBounds.getHeight());
+                            assertEquals("Task height must be set according to minimal height"
+                                            + " taskId=" + taskId + ", stackId=" + stackId,
+                                    targetHeight, (int) wTaskBounds.getHeight());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    static int dpToPx(float dp, int densityDpi){
+        return (int) (dp * densityDpi / DISPLAY_DENSITY_DEFAULT + 0.5f);
+    }
+
+    int defaultMinimalTaskSize(int displayId) {
+        return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
new file mode 100644
index 0000000..f73cdd3
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -0,0 +1,778 @@
+/*
+ * 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.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import java.awt.Rectangle;
+import java.lang.Integer;
+import java.lang.String;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import static android.server.cts.ActivityManagerTestBase.HOME_STACK_ID;
+import static android.server.cts.StateLogger.log;
+import static android.server.cts.StateLogger.logE;
+
+class ActivityManagerState {
+    public static final int DUMP_MODE_ACTIVITIES = 0;
+
+    public static final String STATE_RESUMED = "RESUMED";
+    public static final String STATE_PAUSED = "PAUSED";
+    public static final String STATE_STOPPED = "STOPPED";
+    public static final String STATE_DESTROYED = "DESTROYED";
+
+    private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity activities";
+
+    // Copied from ActivityRecord.java
+    private static final int APPLICATION_ACTIVITY_TYPE = 0;
+    private static final int HOME_ACTIVITY_TYPE = 1;
+    private static final int RECENTS_ACTIVITY_TYPE = 2;
+
+    private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+).*");
+    private final Pattern mStackIdPattern = Pattern.compile("Stack #(\\d+)\\:");
+    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, mResumedActivityPattern, mFocusedStackPattern, mDisplayIdPattern };
+
+    // Stacks in z-order with the top most at the front of the list, starting with primary display.
+    private final List<ActivityStack> mStacks = new ArrayList();
+    // Stacks on all attached displays, in z-order with the top most at the front of the list.
+    private final Map<Integer, List<ActivityStack>> mDisplayStacks = new HashMap<>();
+    private KeyguardControllerState mKeyguardControllerState;
+    private int mFocusedStackId = -1;
+    private String mResumedActivityRecord = null;
+    private final List<String> mResumedActivities = new ArrayList();
+    private final LinkedList<String> mSysDump = new LinkedList();
+
+    void computeState(ITestDevice device) throws DeviceNotAvailableException {
+        computeState(device, DUMP_MODE_ACTIVITIES);
+    }
+
+    void computeState(ITestDevice device, int dumpMode) throws DeviceNotAvailableException {
+        // It is possible the system is in the middle of transition to the right state when we get
+        // the dump. We try a few times to get the information we need before giving up.
+        int retriesLeft = 3;
+        boolean retry = false;
+        String dump = null;
+
+        log("==============================");
+        log("     ActivityManagerState     ");
+        log("==============================");
+
+        do {
+            if (retry) {
+                log("***Incomplete AM state. Retrying...");
+                // Wait half a second between retries for activity manager to finish transitioning.
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            }
+
+            final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+            String dumpsysCmd = "";
+            switch (dumpMode) {
+                case DUMP_MODE_ACTIVITIES:
+                    dumpsysCmd = DUMPSYS_ACTIVITY_ACTIVITIES; break;
+            }
+            device.executeShellCommand(dumpsysCmd, outputReceiver);
+            dump = outputReceiver.getOutput();
+            parseSysDump(dump);
+
+            retry = mStacks.isEmpty() || mFocusedStackId == -1 || (mResumedActivityRecord == null
+                    || mResumedActivities.isEmpty()) && !mKeyguardControllerState.keyguardShowing;
+        } while (retry && retriesLeft-- > 0);
+
+        if (retry) {
+            log(dump);
+        }
+
+        if (mStacks.isEmpty()) {
+            logE("No stacks found...");
+        }
+        if (mFocusedStackId == -1) {
+            logE("No focused stack found...");
+        }
+        if (mResumedActivityRecord == null) {
+            logE("No focused activity found...");
+        }
+        if (mResumedActivities.isEmpty()) {
+            logE("No resumed activities found...");
+        }
+    }
+
+    private void parseSysDump(String sysDump) {
+        reset();
+
+        Collections.addAll(mSysDump, sysDump.split("\\n"));
+
+        int currentDisplayId = 0;
+        while (!mSysDump.isEmpty()) {
+            final ActivityStack stack = ActivityStack.create(mSysDump, mStackIdPattern,
+                    mExtractStackExitPatterns, currentDisplayId);
+
+            if (stack != null) {
+                mStacks.add(stack);
+                mDisplayStacks.get(currentDisplayId).add(stack);
+                if (stack.mResumedActivity != null) {
+                    mResumedActivities.add(stack.mResumedActivity);
+                }
+                continue;
+            }
+
+            KeyguardControllerState controller = KeyguardControllerState.create(
+                    mSysDump, new Pattern[0]);
+            if (controller != null) {
+                mKeyguardControllerState = controller;
+                continue;
+            }
+
+            final String line = mSysDump.pop().trim();
+
+            Matcher matcher = mFocusedStackPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String stackId = matcher.group(2);
+                log(stackId);
+                mFocusedStackId = Integer.parseInt(stackId);
+                continue;
+            }
+
+            matcher = mResumedActivityPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                mResumedActivityRecord = matcher.group(3);
+                log(mResumedActivityRecord);
+                continue;
+            }
+
+            matcher = mDisplayIdPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String displayId = matcher.group(1);
+                log(displayId);
+                currentDisplayId = Integer.parseInt(displayId);
+                mDisplayStacks.put(currentDisplayId, new ArrayList<>());
+            }
+        }
+    }
+
+    private void reset() {
+        mStacks.clear();
+        mFocusedStackId = -1;
+        mResumedActivityRecord = null;
+        mResumedActivities.clear();
+        mSysDump.clear();
+        mKeyguardControllerState = null;
+    }
+
+    int getFrontStackId(int displayId) {
+        return mDisplayStacks.get(displayId).get(0).mStackId;
+    }
+
+    int getFocusedStackId() {
+        return mFocusedStackId;
+    }
+
+    String getFocusedActivity() {
+        return mResumedActivityRecord;
+    }
+
+    String getResumedActivity() {
+        return mResumedActivities.get(0);
+    }
+
+    int getResumedActivitiesCount() {
+        return mResumedActivities.size();
+    }
+
+    public KeyguardControllerState getKeyguardControllerState() {
+        return mKeyguardControllerState;
+    }
+
+    boolean containsStack(int stackId) {
+        return getStackById(stackId) != null;
+    }
+
+    ActivityStack getStackById(int stackId) {
+        for (ActivityStack stack : mStacks) {
+            if (stackId == stack.mStackId) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
+    List<ActivityStack> getStacks() {
+        return new ArrayList(mStacks);
+    }
+
+    int getStackCount() {
+        return mStacks.size();
+    }
+
+    boolean isActivityVisible(String activityName) {
+        for (ActivityStack stack : mStacks) {
+            for (ActivityTask task : stack.mTasks) {
+               for (Activity activity : task.mActivities) {
+                   if (activity.name.equals(activityName)) {
+                       return activity.visible;
+                   }
+               }
+            }
+        }
+        return false;
+    }
+
+    boolean hasActivityState(String activityName, String activityState) {
+        String fullName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        for (ActivityStack stack : mStacks) {
+            for (ActivityTask task : stack.mTasks) {
+                for (Activity activity : task.mActivities) {
+                    if (activity.name.equals(fullName)) {
+                        return activity.state.equals(activityState);
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    int getActivityProcId(String activityName) {
+        for (ActivityStack stack : mStacks) {
+            for (ActivityTask task : stack.mTasks) {
+               for (Activity activity : task.mActivities) {
+                   if (activity.name.equals(activityName)) {
+                       return activity.procId;
+                   }
+               }
+            }
+        }
+        return -1;
+    }
+
+    boolean isHomeActivityVisible() {
+        final Activity homeActivity = getHomeActivity();
+        return homeActivity != null && homeActivity.visible;
+    }
+
+    String getHomeActivityName() {
+        Activity activity = getHomeActivity();
+        if (activity == null) {
+            return null;
+        }
+        return activity.name;
+    }
+
+    private Activity getHomeActivity() {
+        for (ActivityStack stack : mStacks) {
+            if (stack.mStackId != HOME_STACK_ID) {
+                continue;
+            }
+
+            for (ActivityTask task : stack.mTasks) {
+                if (task.mTaskType != HOME_ACTIVITY_TYPE) {
+                    continue;
+                }
+                return task.mActivities.get(task.mActivities.size() - 1);
+            }
+
+            return null;
+        }
+        return null;
+    }
+
+    ActivityTask getTaskByActivityName(String activityName) {
+        return getTaskByActivityName(activityName, -1);
+    }
+
+    ActivityTask getTaskByActivityName(String activityName, int stackId) {
+        String fullName = ActivityManagerTestBase.getActivityComponentName(activityName);
+        for (ActivityStack stack : mStacks) {
+            if (stackId == -1 || stackId == stack.mStackId) {
+                for (ActivityTask task : stack.mTasks) {
+                    for (Activity activity : task.mActivities) {
+                        if (activity.name.equals(fullName)) {
+                            return task;
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    static class ActivityStack extends ActivityContainer {
+
+        private static final Pattern TASK_ID_PATTERN = Pattern.compile("Task id #(\\d+)");
+        private static final Pattern RESUMED_ACTIVITY_PATTERN = Pattern.compile(
+                "mResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
+
+        int mDisplayId;
+        int mStackId;
+        String mResumedActivity;
+        ArrayList<ActivityTask> mTasks = new ArrayList();
+
+        private ActivityStack() {
+        }
+
+        static ActivityStack create(LinkedList<String> dump, Pattern stackIdPattern,
+                                    Pattern[] exitPatterns, int displayId) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = stackIdPattern.matcher(line);
+            if (!matcher.matches()) {
+                // Not a stack.
+                return null;
+            }
+            // For the stack Id line we just read.
+            dump.pop();
+
+            final ActivityStack stack = new ActivityStack();
+            stack.mDisplayId = displayId;
+            log(line);
+            final String stackId = matcher.group(1);
+            log(stackId);
+            stack.mStackId = Integer.parseInt(stackId);
+            stack.extract(dump, exitPatterns);
+            return stack;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+
+            final List<Pattern> taskExitPatterns = new ArrayList();
+            Collections.addAll(taskExitPatterns, exitPatterns);
+            taskExitPatterns.add(TASK_ID_PATTERN);
+            taskExitPatterns.add(RESUMED_ACTIVITY_PATTERN);
+            final Pattern[] taskExitPatternsArray =
+                    taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
+
+            while (!doneExtracting(dump, exitPatterns)) {
+                final ActivityTask task =
+                        ActivityTask.create(dump, TASK_ID_PATTERN, taskExitPatternsArray);
+
+                if (task != null) {
+                    mTasks.add(task);
+                    continue;
+                }
+
+                final String line = dump.pop().trim();
+
+                if (extractFullscreen(line)) {
+                    continue;
+                }
+
+                if (extractBounds(line)) {
+                    continue;
+                }
+
+                Matcher matcher = RESUMED_ACTIVITY_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    mResumedActivity = matcher.group(3);
+                    log(mResumedActivity);
+                    continue;
+                }
+            }
+        }
+
+        List<ActivityTask> getTasks() {
+            return new ArrayList(mTasks);
+        }
+
+        ActivityTask getTask(int taskId) {
+            for (ActivityTask task : mTasks) {
+                if (taskId == task.mTaskId) {
+                    return task;
+                }
+            }
+            return null;
+        }
+    }
+
+    static class ActivityTask extends ActivityContainer {
+        private static final Pattern TASK_RECORD_PATTERN = Pattern.compile("\\* TaskRecord\\"
+                + "{(\\S+) #(\\d+) (\\S+)=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}");
+
+        private static final Pattern LAST_NON_FULLSCREEN_BOUNDS_PATTERN = Pattern.compile(
+                "mLastNonFullscreenBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)");
+
+        private static final Pattern ORIG_ACTIVITY_PATTERN = Pattern.compile("origActivity=(\\S+)");
+        private static final Pattern REAL_ACTIVITY_PATTERN = Pattern.compile("realActivity=(\\S+)");
+
+        private static final Pattern ACTIVITY_NAME_PATTERN = Pattern.compile(
+                "\\* Hist #(\\d+)\\: ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}");
+
+        private static final Pattern TASK_TYPE_PATTERN = Pattern.compile("autoRemoveRecents=(\\S+) "
+                + "isPersistable=(\\S+) numFullscreen=(\\d+) taskType=(\\d+) "
+                + "mTaskToReturnTo=(\\d+)");
+
+        int mTaskId;
+        int mStackId;
+        Rectangle mLastNonFullscreenBounds;
+        String mRealActivity;
+        String mOrigActivity;
+        ArrayList<Activity> mActivities = new ArrayList();
+        int mTaskType = -1;
+        int mReturnToType = -1;
+
+        private ActivityTask() {
+        }
+
+        static ActivityTask create(
+                LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = taskIdPattern.matcher(line);
+            if (!matcher.matches()) {
+                // Not a task.
+                return null;
+            }
+            // For the task Id line we just read.
+            dump.pop();
+
+            final ActivityTask task = new ActivityTask();
+            log(line);
+            final String taskId = matcher.group(1);
+            log(taskId);
+            task.mTaskId = Integer.parseInt(taskId);
+            task.extract(dump, exitPatterns);
+            return task;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+            final List<Pattern> activityExitPatterns = new ArrayList();
+            Collections.addAll(activityExitPatterns, exitPatterns);
+            activityExitPatterns.add(ACTIVITY_NAME_PATTERN);
+            final Pattern[] activityExitPatternsArray =
+                    activityExitPatterns.toArray(new Pattern[activityExitPatterns.size()]);
+
+            while (!doneExtracting(dump, exitPatterns)) {
+                final Activity activity =
+                        Activity.create(dump, ACTIVITY_NAME_PATTERN, activityExitPatternsArray);
+
+                if (activity != null) {
+                    mActivities.add(activity);
+                    continue;
+                }
+
+                final String line = dump.pop().trim();
+
+                if (extractFullscreen(line)) {
+                    continue;
+                }
+
+                if (extractBounds(line)) {
+                    continue;
+                }
+
+                if (extractMinimalSize(line)) {
+                    continue;
+                }
+
+                Matcher matcher = TASK_RECORD_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String stackId = matcher.group(6);
+                    mStackId = Integer.valueOf(stackId);
+                    log(stackId);
+                    continue;
+                }
+
+                matcher = LAST_NON_FULLSCREEN_BOUNDS_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    mLastNonFullscreenBounds = extractBounds(matcher);
+                }
+
+                matcher = REAL_ACTIVITY_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    if (mRealActivity == null) {
+                        log(line);
+                        mRealActivity = matcher.group(1);
+                        log(mRealActivity);
+                    }
+                    continue;
+                }
+
+                matcher = ORIG_ACTIVITY_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    if (mOrigActivity == null) {
+                        log(line);
+                        mOrigActivity = matcher.group(1);
+                        log(mOrigActivity);
+                    }
+                    continue;
+                }
+
+                matcher = TASK_TYPE_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    mTaskType = Integer.valueOf(matcher.group(4));
+                    mReturnToType = Integer.valueOf(matcher.group(5));
+                    continue;
+                }
+            }
+        }
+    }
+
+    static class Activity {
+        private static final Pattern STATE_PATTERN = Pattern.compile("state=(\\S+).*");
+        private static final Pattern VISIBILITY_PATTERN = Pattern.compile("keysPaused=(\\S+) "
+                + "inHistory=(\\S+) visible=(\\S+) sleeping=(\\S+) idle=(\\S+) "
+                + "mStartingWindowState=(\\S+)");
+        private static final Pattern FRONT_OF_TASK_PATTERN = Pattern.compile("frontOfTask=(\\S+) "
+                + "task=TaskRecord\\{(\\S+) #(\\d+) A=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}");
+        private static final Pattern PROCESS_RECORD_PATTERN = Pattern.compile(
+                "app=ProcessRecord\\{(\\S+) (\\d+):(\\S+)/(.+)\\}");
+
+        String name;
+        String state;
+        boolean visible;
+        boolean frontOfTask;
+        int procId = -1;
+
+        private Activity() {
+        }
+
+        static Activity create(
+                LinkedList<String> dump, Pattern activityNamePattern, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = activityNamePattern.matcher(line);
+            if (!matcher.matches()) {
+                // Not an activity.
+                return null;
+            }
+            // For the activity name line we just read.
+            dump.pop();
+
+            final Activity activity = new Activity();
+            log(line);
+            activity.name = matcher.group(4);
+            log(activity.name);
+            activity.extract(dump, exitPatterns);
+            return activity;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+
+            while (!doneExtracting(dump, exitPatterns)) {
+                final String line = dump.pop().trim();
+
+                Matcher matcher = VISIBILITY_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String visibleString = matcher.group(3);
+                    visible = Boolean.valueOf(visibleString);
+                    log(visibleString);
+                    continue;
+                }
+
+                matcher = STATE_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    state = matcher.group(1);
+                    log(state);
+                    continue;
+                }
+
+                matcher = PROCESS_RECORD_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String procIdString = matcher.group(2);
+                    procId = Integer.valueOf(procIdString);
+                    log(procIdString);
+                    continue;
+                }
+
+                matcher = FRONT_OF_TASK_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String frontOfTaskString = matcher.group(1);
+                    frontOfTask = Boolean.valueOf(frontOfTaskString);
+                    log(frontOfTaskString);
+                    continue;
+                }
+            }
+        }
+    }
+
+    static abstract class ActivityContainer {
+        protected static final Pattern FULLSCREEN_PATTERN = Pattern.compile("mFullscreen=(\\S+)");
+        protected static final Pattern BOUNDS_PATTERN =
+                Pattern.compile("mBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)");
+        protected static final Pattern MIN_WIDTH_PATTERN =
+                Pattern.compile("mMinWidth=(\\d+)");
+        protected static final Pattern MIN_HEIGHT_PATTERN =
+                Pattern.compile("mMinHeight=(\\d+)");
+
+        protected boolean mFullscreen;
+        protected Rectangle mBounds;
+        protected int mMinWidth = -1;
+        protected int mMinHeight = -1;
+
+        boolean extractFullscreen(String line) {
+            final Matcher matcher = FULLSCREEN_PATTERN.matcher(line);
+            if (!matcher.matches()) {
+                return false;
+            }
+            log(line);
+            final String fullscreen = matcher.group(1);
+            log(fullscreen);
+            mFullscreen = Boolean.valueOf(fullscreen);
+            return true;
+        }
+
+        boolean extractBounds(String line) {
+            final Matcher matcher = BOUNDS_PATTERN.matcher(line);
+            if (!matcher.matches()) {
+                return false;
+            }
+            log(line);
+            mBounds = extractBounds(matcher);
+            return true;
+        }
+
+        static Rectangle extractBounds(Matcher matcher) {
+            final int left = Integer.valueOf(matcher.group(1));
+            final int top = Integer.valueOf(matcher.group(2));
+            final int right = Integer.valueOf(matcher.group(3));
+            final int bottom = Integer.valueOf(matcher.group(4));
+            final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
+
+            log(rect.toString());
+            return rect;
+        }
+
+        boolean extractMinimalSize(String line) {
+            final Matcher minWidthMatcher = MIN_WIDTH_PATTERN.matcher(line);
+            final Matcher minHeightMatcher = MIN_HEIGHT_PATTERN.matcher(line);
+
+            if (minWidthMatcher.matches()) {
+                log(line);
+                mMinWidth = Integer.valueOf(minWidthMatcher.group(1));
+            } else if (minHeightMatcher.matches()) {
+                log(line);
+                mMinHeight = Integer.valueOf(minHeightMatcher.group(1));
+            } else {
+                return false;
+            }
+            return true;
+        }
+
+        Rectangle getBounds() {
+            return mBounds;
+        }
+
+        boolean isFullscreen() {
+            return mFullscreen;
+        }
+
+        int getMinWidth() {
+            return mMinWidth;
+        }
+
+        int getMinHeight() {
+            return mMinHeight;
+        }
+    }
+
+    static class KeyguardControllerState {
+        private static final Pattern NAME_PATTERN = Pattern.compile("KeyguardController:");
+        private static final Pattern SHOWING_PATTERN = Pattern.compile("mKeyguardShowing=(\\S+)");
+        private static final Pattern OCCLUDED_PATTERN = Pattern.compile("mOccluded=(\\S+)");
+
+        boolean keyguardShowing;
+        boolean keyguardOccluded;
+
+        private KeyguardControllerState() {
+        }
+
+        static KeyguardControllerState create(LinkedList<String> dump, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = NAME_PATTERN.matcher(line);
+            if (!matcher.matches()) {
+                // Not KeyguardController
+                return null;
+            }
+
+            // For the KeyguardController line we just read.
+            dump.pop();
+
+            final KeyguardControllerState controller = new KeyguardControllerState();
+            controller.extract(dump, exitPatterns);
+            return controller;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+
+            while (!doneExtracting(dump, exitPatterns)) {
+                final String line = dump.pop().trim();
+
+                Matcher matcher = SHOWING_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String showingString = matcher.group(1);
+                    keyguardShowing = Boolean.valueOf(showingString);
+                    log(showingString);
+                    continue;
+                }
+
+                matcher = OCCLUDED_PATTERN.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String occludedString = matcher.group(1);
+                    keyguardOccluded = Boolean.valueOf(occludedString);
+                    log(occludedString);
+                    continue;
+                }
+            }
+        }
+    }
+
+    static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
+        if (dump.isEmpty()) {
+            return true;
+        }
+        final String line = dump.peek().trim();
+
+        for (Pattern pattern : exitPatterns) {
+            if (pattern.matcher(line).matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
new file mode 100644
index 0000000..0ab9e9e
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -0,0 +1,688 @@
+/*
+ * 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.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.lang.Exception;
+import java.lang.Integer;
+import java.lang.String;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static android.server.cts.StateLogger.log;
+import static android.server.cts.StateLogger.logE;
+
+public abstract class ActivityManagerTestBase extends DeviceTestCase {
+    private static final boolean PRETEND_DEVICE_SUPPORTS_PIP = false;
+    private static final boolean PRETEND_DEVICE_SUPPORTS_FREEFORM = false;
+
+    // Constants copied from ActivityManager.StackId. If they are changed there, these must be
+    // updated.
+    /** First static stack ID. */
+    public static final int FIRST_STATIC_STACK_ID = 0;
+
+    /** Home activity stack ID. */
+    public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
+
+    /** ID of stack where fullscreen activities are normally launched into. */
+    public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
+
+    /** ID of stack where freeform/resized activities are normally launched into. */
+    public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that occupies a dedicated region of the screen. */
+    public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that always on top (always visible) when it exist. */
+    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+
+    private static final String TASK_ID_PREFIX = "taskId";
+
+    private static final String AM_STACK_LIST = "am stack list";
+
+    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 ";
+
+    protected static final String AM_START_HOME_ACTIVITY_COMMAND =
+            "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
+
+    protected static final String AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND =
+            "am stack move-top-activity-to-pinned-stack 1 0 0 500 500";
+
+    static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
+
+    private static final String AM_RESIZE_DOCKED_STACK = "am stack resize-docked-stack ";
+
+    static final String AM_MOVE_TASK = "am stack move-task ";
+
+    private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
+    private static final String INPUT_KEYEVENT_BACK = "input keyevent 4";
+
+    private static final String LOCK_CREDENTIAL = "1234";
+
+    private static final int INVALID_DISPLAY_ID = -1;
+
+    static String componentName = "android.server.cts";
+
+    /** A reference to the device under test. */
+    protected ITestDevice mDevice;
+
+    private HashSet<String> mAvailableFeatures;
+
+    protected static String getAmStartCmd(final String activityName) {
+        return "am start -n " + getActivityComponentName(activityName);
+    }
+
+    /**
+     * @return the am command to start the given activity with the following extra key/value pairs.
+     *         {@param keyValuePairs} must be a list of arguments defining each key/value extra.
+     */
+    protected static String getAmStartCmd(final String activityName,
+            final String... keyValuePairs) {
+        String base = getAmStartCmd(activityName);
+        if (keyValuePairs.length % 2 != 0) {
+            throw new RuntimeException("keyValuePairs must be pairs of key/value arguments");
+        }
+        for (int i = 0; i < keyValuePairs.length; i += 2) {
+            base += " --es " + keyValuePairs[i] + " " + keyValuePairs[i + 1];
+        }
+        return base;
+    }
+
+    protected static String getAmStartCmd(final String activityName, final int displayId) {
+        return "am start -n " + getActivityComponentName(activityName) + " -f 0x18000000"
+                + " --display " + displayId;
+	}
+
+    protected static String getAmStartCmdOverHome(final String activityName) {
+        return "am start --activity-task-on-home -n " + getActivityComponentName(activityName);
+    }
+
+    static String getActivityComponentName(final String 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 getBaseWindowName() {
+        return componentName + "/" + componentName + ".";
+    }
+
+    static String getWindowName(final String activityName) {
+        return getBaseWindowName() + activityName;
+    }
+
+    protected ActivityAndWindowManagersState mAmWmState = new ActivityAndWindowManagersState();
+
+    private int mInitialAccelerometerRotation;
+    private int mUserRotation;
+    private float mFontScale;
+
+    private SurfaceTraceReceiver mSurfaceTraceReceiver;
+    private Thread mSurfaceTraceThread;
+
+    void installSurfaceObserver(SurfaceTraceReceiver.SurfaceObserver observer) {
+        mSurfaceTraceReceiver = new SurfaceTraceReceiver(observer);
+        mSurfaceTraceThread = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    mDevice.executeShellCommand("wm surface-trace", mSurfaceTraceReceiver);
+                } catch (DeviceNotAvailableException e) {
+                    logE("Device not available: " + e.toString());
+                }
+            }
+        };
+        mSurfaceTraceThread.start();
+    }
+
+    void removeSurfaceObserver() {
+        mSurfaceTraceReceiver.cancel();
+        mSurfaceTraceThread.interrupt();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Get the device, this gives a handle to run commands and install APKs.
+        mDevice = getDevice();
+        wakeUpAndUnlockDevice();
+        // Remove special stacks.
+        executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
+        executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
+        executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
+        // Store rotation settings.
+        mInitialAccelerometerRotation = getAccelerometerRotation();
+        mUserRotation = getUserRotation();
+        mFontScale = getFontScale();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        try {
+            executeShellCommand(AM_FORCE_STOP_TEST_PACKAGE);
+            // Restore rotation settings to the state they were before test.
+            setAccelerometerRotation(mInitialAccelerometerRotation);
+            setUserRotation(mUserRotation);
+            setFontScale(mFontScale);
+            // Remove special stacks.
+            executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
+            executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
+            executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
+            wakeUpAndUnlockDevice();
+        } catch (DeviceNotAvailableException e) {
+        }
+    }
+
+    protected String executeShellCommand(String command) throws DeviceNotAvailableException {
+        log("adb shell " + command);
+        return mDevice.executeShellCommand(command);
+    }
+
+    protected void executeShellCommand(String command, CollectingOutputReceiver outputReceiver)
+            throws DeviceNotAvailableException {
+        log("adb shell " + command);
+        mDevice.executeShellCommand(command, outputReceiver);
+    }
+
+    protected void launchActivity(final String targetActivityName, final String... keyValuePairs)
+            throws Exception {
+        executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
+
+        mAmWmState.waitForValidState(mDevice, targetActivityName);
+    }
+
+    protected void launchActivityOnDisplay(String targetActivityName, int displayId)
+            throws Exception {
+        executeShellCommand(getAmStartCmd(targetActivityName, displayId));
+
+        mAmWmState.waitForValidState(mDevice, targetActivityName);
+    }
+
+    protected void launchActivityFromLaunching(boolean toSide, boolean randomData,
+            boolean multipleTask, String targetActivityName) throws Exception {
+        launchActivityFromLaunching(toSide, randomData, multipleTask, targetActivityName,
+                INVALID_DISPLAY_ID);
+    }
+
+    /**
+     * Launch specific target activity. It uses existing instance of {@link #LAUNCHING_ACTIVITY}, so
+     * that one should be started first.
+     * @param toSide Launch to side in split-screen.
+     * @param randomData Make intent URI random by generating random data.
+     * @param multipleTask Allow multiple task launch.
+     * @param targetActivityName Target activity to be launched. Only class name should be provided,
+     *                           package name of {@link #LAUNCHING_ACTIVITY} will be added
+     *                           automatically.
+     * @param displayId Display id where target activity should be launched.
+     * @throws Exception
+     */
+    protected void launchActivityFromLaunching(boolean toSide, boolean randomData,
+            boolean multipleTask, String targetActivityName, int displayId) throws Exception {
+        StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(LAUNCHING_ACTIVITY));
+        commandBuilder.append(" -f 0x20000000");
+        if (toSide) {
+            commandBuilder.append(" --ez launch_to_the_side true");
+        }
+        if (randomData) {
+            commandBuilder.append(" --ez random_data true");
+        }
+        if (multipleTask) {
+            commandBuilder.append(" --ez multiple_task true");
+        }
+        if (targetActivityName != null) {
+            commandBuilder.append(" --es target_activity ").append(targetActivityName);
+        }
+        if (displayId != INVALID_DISPLAY_ID) {
+            commandBuilder.append(" --ei display_id ").append(displayId);
+        }
+        executeShellCommand(commandBuilder.toString());
+
+        mAmWmState.waitForValidState(mDevice, targetActivityName);
+    }
+
+    protected void launchActivityInStack(String activityName, int stackId) throws Exception {
+        executeShellCommand(getAmStartCmd(activityName) + " --stack " + stackId);
+
+        mAmWmState.waitForValidState(mDevice, activityName, stackId);
+    }
+
+    protected void launchActivityInDockStack(String activityName) throws Exception {
+        launchActivity(activityName);
+        moveActivityToDockStack(activityName);
+
+        mAmWmState.waitForValidState(mDevice, activityName, DOCKED_STACK_ID);
+    }
+
+    protected void launchActivityToSide(boolean randomData, boolean multipleTaskFlag,
+            String targetActivity) throws Exception {
+        final String activityToLaunch = targetActivity != null ? targetActivity : "TestActivity";
+        launchActivityFromLaunching(true /* toSide */, randomData, multipleTaskFlag,
+                activityToLaunch);
+
+        mAmWmState.waitForValidState(mDevice, activityToLaunch, FULLSCREEN_WORKSPACE_STACK_ID);
+    }
+
+    protected void moveActivityToDockStack(String activityName) throws Exception {
+        moveActivityToStack(activityName, DOCKED_STACK_ID);
+    }
+
+    protected void moveActivityToStack(String activityName, int stackId) throws Exception {
+        final int taskId = getActivityTaskId(activityName);
+        final String cmd = AM_MOVE_TASK + taskId + " " + stackId + " true";
+        executeShellCommand(cmd);
+
+        mAmWmState.waitForValidState(mDevice, activityName, stackId);
+    }
+
+    protected void resizeActivityTask(String activityName, int left, int top, int right, int bottom)
+            throws Exception {
+        final int taskId = getActivityTaskId(activityName);
+        final String cmd = "am task resize "
+                + taskId + " " + left + " " + top + " " + right + " " + bottom;
+        executeShellCommand(cmd);
+    }
+
+    protected void resizeDockedStack(
+            int stackWidth, int stackHeight, int taskWidth, int taskHeight)
+                    throws DeviceNotAvailableException {
+        executeShellCommand(AM_RESIZE_DOCKED_STACK
+                + "0 0 " + stackWidth + " " + stackHeight
+                + " 0 0 " + taskWidth + " " + taskHeight);
+    }
+
+    protected void pressHomeButton() throws DeviceNotAvailableException {
+        executeShellCommand(INPUT_KEYEVENT_HOME);
+    }
+
+    protected void pressBackButton() throws DeviceNotAvailableException {
+        executeShellCommand(INPUT_KEYEVENT_BACK);
+    }
+
+    // Utility method for debugging, not used directly here, but useful, so kept around.
+    protected void printStacksAndTasks() throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        executeShellCommand(AM_STACK_LIST, outputReceiver);
+        String output = outputReceiver.getOutput();
+        for (String line : output.split("\\n")) {
+            CLog.logAndDisplay(LogLevel.INFO, line);
+        }
+    }
+
+    protected int getActivityTaskId(String name) throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        executeShellCommand(AM_STACK_LIST, outputReceiver);
+        final String output = outputReceiver.getOutput();
+        final Pattern activityPattern = Pattern.compile("(.*) " + getWindowName(name) + " (.*)");
+        for (String line : output.split("\\n")) {
+            Matcher matcher = activityPattern.matcher(line);
+            if (matcher.matches()) {
+                for (String word : line.split("\\s+")) {
+                    if (word.startsWith(TASK_ID_PREFIX)) {
+                        final String withColon = word.split("=")[1];
+                        return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    protected boolean supportsPip() throws DeviceNotAvailableException {
+        return hasDeviceFeature("android.software.picture_in_picture")
+                || PRETEND_DEVICE_SUPPORTS_PIP;
+    }
+
+    protected boolean supportsFreeform() throws DeviceNotAvailableException {
+        return hasDeviceFeature("android.software.freeform_window_management")
+                || PRETEND_DEVICE_SUPPORTS_FREEFORM;
+    }
+
+    protected boolean isHandheld() throws DeviceNotAvailableException {
+        return !hasDeviceFeature("android.software.leanback")
+                && !hasDeviceFeature("android.software.watch");
+    }
+
+    protected boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
+        if (mAvailableFeatures == null) {
+            // TODO: Move this logic to ITestDevice.
+            final String output = runCommandAndPrintOutput("pm list features");
+
+            // Extract the id of the new user.
+            mAvailableFeatures = new HashSet<>();
+            for (String feature: output.split("\\s+")) {
+                // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
+                String[] tokens = feature.split(":");
+                assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
+                        tokens.length > 1);
+                assertEquals(feature, "feature", tokens[0]);
+                mAvailableFeatures.add(tokens[1]);
+            }
+        }
+        boolean result = mAvailableFeatures.contains(requiredFeature);
+        if (!result) {
+            CLog.logAndDisplay(LogLevel.INFO, "Device doesn't support " + requiredFeature);
+        }
+        return result;
+    }
+
+    private boolean isDisplayOn() throws DeviceNotAvailableException {
+        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand("dumpsys power", outputReceiver);
+
+        for (String line : outputReceiver.getOutput().split("\\n")) {
+            line = line.trim();
+
+            final Matcher matcher = sDisplayStatePattern.matcher(line);
+            if (matcher.matches()) {
+                final String state = matcher.group(1);
+                log("power state=" + state);
+                return "ON".equals(state);
+            }
+        }
+        log("power state :(");
+        return false;
+    }
+
+    protected void sleepDevice() throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        runCommandAndPrintOutput("input keyevent 26");
+        do {
+            if (isDisplayOn()) {
+                log("***Waiting for display to turn off...");
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+    }
+
+    protected void wakeUpAndUnlockDevice() throws DeviceNotAvailableException {
+        wakeUpDevice();
+        unlockDevice();
+    }
+
+    protected void wakeUpDevice() throws DeviceNotAvailableException {
+        runCommandAndPrintOutput("input keyevent 224");
+    }
+
+    protected void unlockDevice() throws DeviceNotAvailableException {
+        runCommandAndPrintOutput("input keyevent 82");
+    }
+
+    protected void unlockDeviceWithCredential() throws Exception {
+        runCommandAndPrintOutput("input keyevent 82");
+        enterAndConfirmLockCredential();
+    }
+
+    protected void enterAndConfirmLockCredential() throws Exception {
+        runCommandAndPrintOutput("input text " + LOCK_CREDENTIAL);
+        runCommandAndPrintOutput("input keyevent KEYCODE_ENTER");
+    }
+
+    protected void gotoKeyguard() throws DeviceNotAvailableException {
+        sleepDevice();
+        wakeUpDevice();
+    }
+
+    protected void setLockCredential() throws DeviceNotAvailableException {
+        runCommandAndPrintOutput("locksettings set-pin " + LOCK_CREDENTIAL);
+    }
+
+    protected void removeLockCredential() throws DeviceNotAvailableException {
+        runCommandAndPrintOutput("locksettings clear --old " + LOCK_CREDENTIAL);
+    }
+
+    /**
+     * Sets the device rotation, value corresponds to one of {@link Surface.ROTATION_0},
+     * {@link Surface.ROTATION_90}, {@link Surface.ROTATION_180}, {@link Surface.ROTATION_270}.
+     */
+    protected void setDeviceRotation(int rotation) throws Exception {
+        setAccelerometerRotation(0);
+        setUserRotation(rotation);
+        mAmWmState.waitForRotation(mDevice, rotation);
+    }
+
+    private int getAccelerometerRotation() throws DeviceNotAvailableException {
+        final String rotation =
+                runCommandAndPrintOutput("settings get system accelerometer_rotation");
+        return Integer.parseInt(rotation.trim());
+    }
+
+    private void setAccelerometerRotation(int rotation) throws DeviceNotAvailableException {
+        runCommandAndPrintOutput(
+                "settings put system accelerometer_rotation " + rotation);
+    }
+
+    private int getUserRotation() throws DeviceNotAvailableException {
+        final String rotation =
+                runCommandAndPrintOutput("settings get system user_rotation").trim();
+        if ("null".equals(rotation)) {
+            return -1;
+        }
+        return Integer.parseInt(rotation);
+    }
+
+    private void setUserRotation(int rotation) throws DeviceNotAvailableException {
+        if (rotation == -1) {
+            runCommandAndPrintOutput(
+                    "settings delete system user_rotation");
+        } else {
+            runCommandAndPrintOutput(
+                    "settings put system user_rotation " + rotation);
+        }
+    }
+
+    protected void setFontScale(float fontScale) throws DeviceNotAvailableException {
+        if (fontScale == 0.0f) {
+            runCommandAndPrintOutput(
+                    "settings delete system font_scale");
+        } else {
+            runCommandAndPrintOutput(
+                    "settings put system font_scale " + fontScale);
+        }
+    }
+
+    protected float getFontScale() throws DeviceNotAvailableException {
+        try {
+            final String fontScale =
+                    runCommandAndPrintOutput("settings get system font_scale").trim();
+            return Float.parseFloat(fontScale);
+        } catch (NumberFormatException e) {
+            // If we don't have a valid font scale key, return 0.0f now so
+            // that we delete the key in tearDown().
+            return 0.0f;
+        }
+    }
+
+    protected String runCommandAndPrintOutput(String command) throws DeviceNotAvailableException {
+        final String output = executeShellCommand(command);
+        log(output);
+        return output;
+    }
+
+    protected void clearLogcat() throws DeviceNotAvailableException {
+        mDevice.executeAdbCommand("logcat", "-c");
+    }
+
+    protected void assertActivityLifecycle(String activityName, boolean relaunched)
+            throws DeviceNotAvailableException {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+
+        if (relaunched) {
+            if (lifecycleCounts.mDestroyCount < 1) {
+                fail(activityName + " must have been destroyed. mDestroyCount="
+                        + lifecycleCounts.mDestroyCount);
+            }
+            if (lifecycleCounts.mCreateCount < 1) {
+                fail(activityName + " must have been (re)created. mCreateCount="
+                        + lifecycleCounts.mCreateCount);
+            }
+        } else {
+            if (lifecycleCounts.mDestroyCount > 0) {
+                fail(activityName + " must *NOT* have been destroyed. mDestroyCount="
+                        + lifecycleCounts.mDestroyCount);
+            }
+            if (lifecycleCounts.mCreateCount > 0) {
+                fail(activityName + " must *NOT* have been (re)created. mCreateCount="
+                        + lifecycleCounts.mCreateCount);
+            }
+            if (lifecycleCounts.mConfigurationChangedCount < 1) {
+                fail(activityName + " must have received configuration changed. "
+                        + "mConfigurationChangedCount="
+                        + lifecycleCounts.mConfigurationChangedCount);
+            }
+        }
+    }
+
+    protected void assertRelaunchOrConfigChanged(
+            String activityName, int numRelaunch, int numConfigChange)
+            throws DeviceNotAvailableException {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+
+        if (lifecycleCounts.mDestroyCount != numRelaunch) {
+            fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+                    + " time(s), expecting " + numRelaunch);
+        } else if (lifecycleCounts.mCreateCount != numRelaunch) {
+            fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+                    + " time(s), expecting " + numRelaunch);
+        } else if (lifecycleCounts.mConfigurationChangedCount != numConfigChange) {
+            fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
+                    + " onConfigurationChanged() calls, expecting " + numConfigChange);
+        }
+    }
+
+    protected String[] getDeviceLogsForComponent(String componentName)
+            throws DeviceNotAvailableException {
+        return mDevice.executeAdbCommand(
+                "logcat", "-v", "brief", "-d", componentName + ":I", "*:S").split("\\n");
+    }
+
+    protected String[] getDeviceLogsForComponents(final String[] componentNames)
+            throws DeviceNotAvailableException {
+        String filters = "";
+        for (int i = 0; i < componentNames.length; i++) {
+            filters += componentNames[i] + ":I ";
+        }
+        return mDevice.executeAdbCommand(
+                "logcat", "-v", "brief", "-d", filters, "*:S").split("\\n");
+    }
+
+    private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
+    private static final Pattern sConfigurationChangedPattern =
+            Pattern.compile("(.+): onConfigurationChanged");
+    private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
+    private static final Pattern sNewConfigPattern = Pattern.compile(
+            "(.+): config size=\\((\\d+),(\\d+)\\) displaySize=\\((\\d+),(\\d+)\\)" +
+            " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+) densityDpi=(\\d+)");
+    private static final Pattern sDisplayStatePattern =
+            Pattern.compile("Display Power: state=(.+)");
+
+    protected class ReportedSizes {
+        int widthDp;
+        int heightDp;
+        int displayWidth;
+        int displayHeight;
+        int metricsWidth;
+        int metricsHeight;
+        int smallestWidthDp;
+        int densityDpi;
+
+        @Override
+        public String toString() {
+            return "ReportedSizes: {widthDp=" + widthDp + " heightDp=" + heightDp +
+                    " displayWidth=" + displayWidth + " displayHeight=" + displayHeight +
+                    " metricsWidth=" + metricsWidth + " metricsHeight=" + metricsHeight +
+                    " smallestWidthDp=" + smallestWidthDp + " densityDpi=" + densityDpi + "}";
+        }
+    }
+
+    protected ReportedSizes getLastReportedSizesForActivity(String activityName)
+            throws DeviceNotAvailableException {
+        final String[] lines = getDeviceLogsForComponent(activityName);
+        for (int i = lines.length - 1; i >= 0; i--) {
+            final String line = lines[i].trim();
+            final Matcher matcher = sNewConfigPattern.matcher(line);
+            if (matcher.matches()) {
+                ReportedSizes details = new ReportedSizes();
+                details.widthDp = Integer.parseInt(matcher.group(2));
+                details.heightDp = Integer.parseInt(matcher.group(3));
+                details.displayWidth = Integer.parseInt(matcher.group(4));
+                details.displayHeight = Integer.parseInt(matcher.group(5));
+                details.metricsWidth = Integer.parseInt(matcher.group(6));
+                details.metricsHeight = Integer.parseInt(matcher.group(7));
+                details.smallestWidthDp = Integer.parseInt(matcher.group(8));
+                details.densityDpi = Integer.parseInt(matcher.group(9));
+                return details;
+            }
+        }
+        return null;
+    }
+
+    private class ActivityLifecycleCounts {
+        int mCreateCount;
+        int mConfigurationChangedCount;
+        int mDestroyCount;
+
+        public ActivityLifecycleCounts(String activityName) throws DeviceNotAvailableException {
+            for (String line : getDeviceLogsForComponent(activityName)) {
+                line = line.trim();
+
+                Matcher matcher = sCreatePattern.matcher(line);
+                if (matcher.matches()) {
+                    mCreateCount++;
+                    continue;
+                }
+
+                matcher = sConfigurationChangedPattern.matcher(line);
+                if (matcher.matches()) {
+                    mConfigurationChangedCount++;
+                    continue;
+                }
+
+                matcher = sDestroyPattern.matcher(line);
+                if (matcher.matches()) {
+                    mDestroyCount++;
+                    continue;
+                }
+            }
+        }
+    }
+
+    protected void stopTestCase() throws Exception {
+        executeShellCommand("am force-stop " + componentName);
+    }
+}
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/activityandwindowmanager/util/src/android/server/cts/SurfaceTraceReceiver.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/SurfaceTraceReceiver.java
new file mode 100644
index 0000000..8026e80
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/SurfaceTraceReceiver.java
@@ -0,0 +1,380 @@
+/*
+ * 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.IShellOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.awt.Rectangle;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.lang.System;
+import junit.framework.Assert;
+
+import static android.server.cts.StateLogger.logE;
+
+// Parses a trace of surface commands from the WM (in real time)
+// and dispenses them via the SurfaceObserver interface.
+//
+// Data enters through addOutput
+public class SurfaceTraceReceiver implements IShellOutputReceiver {
+    final SurfaceObserver mObserver;
+
+    private State mState = State.CMD;
+    private String mCurrentWindowName = null;
+    private int mArgPosition = 0;
+    private float[] mTmpFloats = new float[10];
+    private int[] mTmpInts = new int[10];
+    private Rectangle.Float mTmpRect = new Rectangle.Float();
+    private byte[] mUnprocessedBytes = new byte[16384];
+    private byte[] mFullData = new byte[32768];
+    private int mUnprocessedBytesLength;
+
+    private boolean mCancelled = false;
+
+    interface SurfaceObserver {
+        default void setAlpha(String windowName, float alpha) {}
+        default void setLayer(String windowName, int layer) {}
+        default void setPosition(String windowName, float x, float y) {}
+        default void setSize(String widnowName, int width, int height) {}
+        default void setLayerStack(String windowName, int layerStack) {}
+        default void setMatrix(String windowName, float dsdx, float dtdx, float dsdy, float dtdy) {}
+        default void setCrop(String windowName, Rectangle.Float crop) {}
+        default void setFinalCrop(String windowName, Rectangle.Float finalCrop) {}
+        default void hide(String windowName) {}
+        default void show(String windowName) {}
+        default void setGeometryAppliesWithResize(String windowName) {}
+        default void openTransaction() {}
+        default void closeTransaction() {}
+    };
+
+    enum State {
+        CMD,
+        SET_ALPHA,
+        SET_LAYER,
+        SET_POSITION,
+        SET_SIZE,
+        SET_CROP,
+        SET_FINAL_CROP,
+        SET_LAYER_STACK,
+        SET_MATRIX,
+        HIDE,
+        SHOW,
+        GEOMETRY_APPLIES_WITH_RESIZE
+    };
+
+    SurfaceTraceReceiver(SurfaceObserver observer) {
+        mObserver = observer;
+    }
+
+    // Reset state and prepare to accept a new command.
+    void nextCmd(DataInputStream d) {
+        mState = State.CMD;
+        mCurrentWindowName = null;
+        mArgPosition = 0;
+
+        try {
+            // Consume the sigil
+            d.readByte();
+            d.readByte();
+            d.readByte();
+            d.readByte();
+        } catch (Exception e) {
+            logE("Exception consuming sigil: " + e);
+        }
+    }
+
+    // When the command parsing functions below are called, the window name
+    // will already be parsed. The responsibility of these functions
+    // is to parse other arguments 1 by 1 and accumlate them until the appropriate number
+    // is reached. At that point the parser should emit an event to the observer and
+    // call nextCmd
+    void parseAlpha(DataInputStream d) throws IOException {
+        float alpha = d.readFloat();
+        mObserver.setAlpha(mCurrentWindowName, alpha);
+        nextCmd(d);
+    }
+
+    void parseLayer(DataInputStream d) throws IOException {
+        int layer = d.readInt();
+        mObserver.setLayer(mCurrentWindowName, layer);
+        nextCmd(d);
+    }
+
+    void parsePosition(DataInputStream d) throws IOException {
+        mTmpFloats[mArgPosition] = d.readFloat();
+        mArgPosition++;
+        if (mArgPosition == 2)  {
+            mObserver.setPosition(mCurrentWindowName, mTmpFloats[0], mTmpFloats[1]);
+            nextCmd(d);
+        }
+    }
+
+    void parseSize(DataInputStream d) throws IOException {
+        mTmpInts[mArgPosition] = d.readInt();
+        mArgPosition++;
+        if (mArgPosition == 2) {
+            mObserver.setSize(mCurrentWindowName, mTmpInts[0], mTmpInts[1]);
+            nextCmd(d);
+        }
+    }
+
+    // Careful Android rectangle rep is top-left-right-bottom awt is top-left-width-height
+    void parseCrop(DataInputStream d) throws IOException {
+        mTmpFloats[mArgPosition] = d.readFloat();
+        mArgPosition++;
+        if (mArgPosition == 4) {
+            mTmpRect.setRect(mTmpFloats[0], mTmpFloats[1], mTmpFloats[2]-mTmpFloats[0],
+                    mTmpFloats[3]-mTmpFloats[1]);
+            mObserver.setCrop(mCurrentWindowName, mTmpRect);
+            nextCmd(d);
+        }
+    }
+
+    void parseFinalCrop(DataInputStream d) throws IOException {
+        mTmpFloats[mArgPosition] = d.readInt();
+        mArgPosition++;
+        if (mArgPosition == 4) {
+            mTmpRect.setRect(mTmpFloats[0], mTmpFloats[1], mTmpFloats[2]-mTmpFloats[0],
+                    mTmpFloats[3]-mTmpFloats[1]);
+            mObserver.setFinalCrop(mCurrentWindowName, mTmpRect);
+            nextCmd(d);
+        }
+    }
+
+    void parseLayerStack(DataInputStream d) throws IOException {
+        int layerStack = d.readInt();
+        mObserver.setLayerStack(mCurrentWindowName, layerStack);
+        nextCmd(d);
+    }
+
+    void parseSetMatrix(DataInputStream d) throws IOException {
+        mTmpFloats[mArgPosition] = d.readFloat();
+        mArgPosition++;
+        if (mArgPosition == 4) {
+            mObserver.setMatrix(mCurrentWindowName, mTmpFloats[0],
+                    mTmpFloats[1], mTmpFloats[2], mTmpFloats[3]);
+            nextCmd(d);
+        }
+    }
+
+    void parseHide(DataInputStream d) throws IOException {
+        mObserver.hide(mCurrentWindowName);
+        nextCmd(d);
+    }
+
+    void parseShow(DataInputStream d) throws IOException {
+        mObserver.show(mCurrentWindowName);
+        nextCmd(d);
+    }
+
+    void parseGeometryAppliesWithResize(DataInputStream d) throws IOException {
+        mObserver.setGeometryAppliesWithResize(mCurrentWindowName);
+        nextCmd(d);
+    }
+
+    public int indexAfterLastSigil(byte[] data, int offset, int length) {
+        int idx = offset + length - 1;
+        int sigilsNeeded = 4;
+        byte sigil = (byte)0xfc;
+        while (idx > offset) {
+            if (data[idx] == sigil) {
+                sigilsNeeded--;
+                if (sigilsNeeded == 0) {
+                    return idx+4;
+                }
+            } else {
+                sigilsNeeded = 4;
+            }
+            idx--;
+        }
+        return idx; // idx == offset at this point
+    }
+
+    // The tricky bit here is ADB may break up our words, and not send us complete messages,
+    // or even complete integers! To ensure we process the data in appropciate chunks,
+    // We look for a sigil (0xfcfcfcfc) and only process data when it ends in as igil.
+    // Otherwise we save it and wait to receive a sigil, then process the merged data.
+    public void addOutput(byte[] data, int offset, int length) {
+        byte[] combinedData = data;
+
+        // First we have to merge any unprocessed bytes from the last call in to
+        // a combined array.
+        if (mUnprocessedBytesLength > 0) {
+            System.arraycopy(mUnprocessedBytes, 0, mFullData, 0, mUnprocessedBytesLength);
+            System.arraycopy(data, offset, mFullData, mUnprocessedBytesLength, length);
+            combinedData = mFullData;
+            length = mUnprocessedBytesLength + length;
+            offset = 0;
+            mUnprocessedBytesLength = 0;
+        }
+
+        // Now we find the last sigil in our combined array. Everything before this index is
+        // a properly terminated message ready to be parsed.
+        int completedIndex = indexAfterLastSigil(combinedData, offset, length);
+        // If there are any bytes left after the last sigil, save them for next time.
+        if (completedIndex != length + offset) {
+            mUnprocessedBytesLength = (length+offset)-(completedIndex);
+            System.arraycopy(combinedData, completedIndex,
+                    mUnprocessedBytes, 0, mUnprocessedBytesLength);
+        }
+        //  If there was no sigil, we have nothing to process yet.
+        if (completedIndex <= offset) {
+            return;
+        }
+        ByteArrayInputStream b = new ByteArrayInputStream(combinedData, offset, completedIndex - offset);
+        DataInputStream d = new DataInputStream(b);
+
+        // We may not receive an entire message at once (for example we may receive
+        // a command without its arguments), so we track our current state, over multiple
+        // addOutput calls. When we are in State.CMD it means we next expect a new command.
+        // If we are not expecting a command, then all commands with arguments, begin with
+        // a window name. Once we have the window name, individual parseAlpha,
+        // parseLayer, etc...statements will parse command arguments one at a time. Once
+        // the appropriate number of arguments is collected the observer will be invoked
+        // and the state reset. For commands which have no arguments (e.g. open/close transaction),
+        // parseCmd can emit the observer event and call nextCmd() right away.
+        try {
+            while (b.available() > 0) {
+                if (mState != State.CMD && mCurrentWindowName == null) {
+                    mCurrentWindowName = d.readUTF();
+                    if (b.available() == 0) {
+                        return;
+                    }
+                }
+                switch (mState) {
+                case CMD: {
+                    String cmd = d.readUTF();
+                    parseCmd(d, cmd);
+                    break;
+                }
+                case SET_ALPHA: {
+                    parseAlpha(d);
+                    break;
+                }
+                case SET_LAYER: {
+                    parseLayer(d);
+                    break;
+                }
+                case SET_POSITION: {
+                    parsePosition(d);
+                    break;
+                }
+                case SET_SIZE: {
+                    parseSize(d);
+                    break;
+                }
+                case SET_CROP: {
+                    parseCrop(d);
+                    break;
+                }
+                case SET_FINAL_CROP: {
+                    parseFinalCrop(d);
+                    break;
+                }
+                case SET_LAYER_STACK: {
+                    parseLayerStack(d);
+                    break;
+                }
+                case SET_MATRIX: {
+                    parseSetMatrix(d);
+                    break;
+                }
+                case HIDE: {
+                    parseHide(d);
+                    break;
+                }
+                case SHOW: {
+                    parseShow(d);
+                    break;
+                }
+                case GEOMETRY_APPLIES_WITH_RESIZE: {
+                    parseGeometryAppliesWithResize(d);
+                    break;
+                }
+                }
+            }
+        } catch (Exception e) {
+            logE("Error in surface trace receiver: " + e.toString());
+        }
+    }
+
+    void parseCmd(DataInputStream d, String cmd) {
+        switch (cmd) {
+        case "Alpha":
+            mState = State.SET_ALPHA;
+            break;
+        case "Layer":
+            mState = State.SET_LAYER;
+            break;
+        case "Position":
+            mState = State.SET_POSITION;
+            break;
+        case "Size":
+            mState = State.SET_SIZE;
+            break;
+        case "Crop":
+            mState = State.SET_CROP;
+            break;
+        case "FinalCrop":
+            mState = State.SET_FINAL_CROP;
+            break;
+        case "LayerStack":
+            mState = State.SET_LAYER_STACK;
+            break;
+        case "Matrix":
+            mState = State.SET_MATRIX;
+            break;
+        case "Hide":
+            mState = State.HIDE;
+            break;
+        case "Show":
+            mState = State.SHOW;
+            break;
+        case "GeometryAppliesWithResize":
+            mState = State.GEOMETRY_APPLIES_WITH_RESIZE;
+            break;
+        case "OpenTransaction":
+            mObserver.openTransaction();
+            nextCmd(d);
+            break;
+        case "CloseTransaction":
+            mObserver.closeTransaction();
+            nextCmd(d);
+            break;
+        default:
+            Assert.fail("Unexpected surface command: " + cmd);
+            break;
+        }
+    }
+
+    @Override
+    public void flush() {
+    }
+
+    void cancel() {
+        mCancelled = true;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return mCancelled;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
new file mode 100644
index 0000000..87fe69d
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -0,0 +1,1051 @@
+/*
+ * 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 static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
+import static android.server.cts.StateLogger.log;
+import static android.server.cts.StateLogger.logE;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.sun.org.apache.xpath.internal.operations.Bool;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class WindowManagerState {
+
+    public static  final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
+    public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE";
+    public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN";
+    public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE";
+
+    public static final String TRANSIT_WALLPAPER_OPEN = "TRANSIT_WALLPAPER_OPEN";
+    public static final String TRANSIT_WALLPAPER_CLOSE = "TRANSIT_WALLPAPER_CLOSE";
+    public static final String TRANSIT_WALLPAPER_INTRA_OPEN = "TRANSIT_WALLPAPER_INTRA_OPEN";
+    public static final String TRANSIT_WALLPAPER_INTRA_CLOSE = "TRANSIT_WALLPAPER_INTRA_CLOSE";
+
+    public static final String TRANSIT_KEYGUARD_GOING_AWAY = "TRANSIT_KEYGUARD_GOING_AWAY";
+    public static final String TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
+            "TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
+    public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE";
+    public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE";
+
+    private static final String DUMPSYS_WINDOW = "dumpsys window -a";
+
+    private static final Pattern sWindowPattern =
+            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:");
+    private static final Pattern sStartingWindowPattern =
+            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Starting (.+)\\}\\:");
+    private static final Pattern sExitingWindowPattern =
+            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+) EXITING\\}\\:");
+    private static final Pattern sDebuggerWindowPattern =
+            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger: (.+)\\}\\:");
+
+    private static final Pattern sFocusedWindowPattern = Pattern.compile(
+            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) (\\S+)\\}");
+    private static final Pattern sAppErrorFocusedWindowPattern = Pattern.compile(
+            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Application Error\\: (\\S+)\\}");
+    private static final Pattern sWaitingForDebuggerFocusedWindowPattern = Pattern.compile(
+            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger\\: (\\S+)\\}");
+
+    private static final Pattern sFocusedAppPattern =
+            Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) "
+                    + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)");
+    private static final Pattern sStableBoundsPattern = Pattern.compile(
+            "mStable=\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\)");
+    private static final Pattern sDefaultPinnedStackBoundsPattern = Pattern.compile(
+            "defaultBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
+    private static final Pattern sPinnedStackMovementBoundsPattern = Pattern.compile(
+            "movementBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
+    private static final Pattern sRotationPattern = Pattern.compile(
+            "mRotation=(\\d).*");
+    private static final Pattern sLastOrientationPattern = Pattern.compile(
+            ".*mLastOrientation=(\\d)");
+
+    private static final Pattern sLastAppTransitionPattern =
+            Pattern.compile("mLastUsedAppTransition=(.+)");
+
+    private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
+
+    private static final Pattern sInputMethodWindowPattern =
+            Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*");
+
+    private static final Pattern sDisplayIdPattern =
+            Pattern.compile("Display: mDisplayId=(\\d+)");
+
+    private static final Pattern sDisplayFrozenPattern =
+            Pattern.compile("mDisplayFrozen=([a-z]*) .*");
+
+    private static final Pattern[] sExtractStackExitPatterns = {
+            sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
+            sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
+            sWaitingForDebuggerFocusedWindowPattern,
+            sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern,
+            sPinnedStackMovementBoundsPattern, sDisplayIdPattern };
+
+    // Windows in z-order with the top most at the front of the list.
+    private List<WindowState> mWindowStates = new ArrayList();
+    // Stacks in z-order with the top most at the front of the list, starting with primary display.
+    private final List<WindowStack> mStacks = new ArrayList();
+    // Stacks on all attached displays, in z-order with the top most at the front of the list.
+    private final Map<Integer, List<WindowStack>> mDisplayStacks
+            = new HashMap<>();
+    private List<Display> mDisplays = new ArrayList();
+    private String mFocusedWindow = null;
+    private String mFocusedApp = null;
+    private String mLastTransition = null;
+    private String mInputMethodWindowAppToken = null;
+    private Rectangle mStableBounds = new Rectangle();
+    private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
+    private final Rectangle mPinnedStackMovementBounds = new Rectangle();
+    private final LinkedList<String> mSysDump = new LinkedList();
+    private int mRotation;
+    private int mLastOrientation;
+    private boolean mDisplayFrozen;
+
+    void computeState(ITestDevice device) throws DeviceNotAvailableException {
+        // It is possible the system is in the middle of transition to the right state when we get
+        // the dump. We try a few times to get the information we need before giving up.
+        int retriesLeft = 3;
+        boolean retry = false;
+        String dump = null;
+
+        log("==============================");
+        log("      WindowManagerState      ");
+        log("==============================");
+        do {
+            if (retry) {
+                log("***Incomplete WM state. Retrying...");
+                // Wait half a second between retries for window manager to finish transitioning...
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            }
+
+            final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+            device.executeShellCommand(DUMPSYS_WINDOW, outputReceiver);
+            dump = outputReceiver.getOutput();
+            parseSysDump(dump);
+
+            retry = mWindowStates.isEmpty() || mFocusedWindow == null || mFocusedApp == null;
+        } while (retry && retriesLeft-- > 0);
+
+        if (retry) {
+            log(dump);
+        }
+
+        if (mWindowStates.isEmpty()) {
+            logE("No Windows found...");
+        }
+        if (mFocusedWindow == null) {
+            logE("No Focused Window...");
+        }
+        if (mFocusedApp == null) {
+            logE("No Focused App...");
+        }
+    }
+
+    private void parseSysDump(String sysDump) {
+        reset();
+
+        Collections.addAll(mSysDump, sysDump.split("\\n"));
+
+        int currentDisplayId = DEFAULT_DISPLAY_ID;
+        while (!mSysDump.isEmpty()) {
+            final Display display =
+                    Display.create(mSysDump, sExtractStackExitPatterns);
+            if (display != null) {
+                log(display.toString());
+                mDisplays.add(display);
+                currentDisplayId = display.mDisplayId;
+                mDisplayStacks.put(currentDisplayId, new ArrayList<>());
+                continue;
+            }
+
+            final WindowStack stack =
+                    WindowStack.create(mSysDump, sStackIdPattern, sExtractStackExitPatterns);
+
+            if (stack != null) {
+                mStacks.add(stack);
+                mDisplayStacks.get(currentDisplayId).add(stack);
+                continue;
+            }
+
+
+            final WindowState ws = WindowState.create(mSysDump, sExtractStackExitPatterns);
+            if (ws != null) {
+                log(ws.toString());
+
+                // Check to see if we are in the middle of transitioning. If we are, we want to
+                // skip dumping until window manager is done transitioning windows.
+                if (ws.isStartingWindow()) {
+                    log("Skipping dump due to starting window transition...");
+                    return;
+                }
+
+                if (ws.isExitingWindow()) {
+                    log("Skipping dump due to exiting window transition...");
+                    return;
+                }
+
+                mWindowStates.add(ws);
+                continue;
+            }
+
+            final String line = mSysDump.pop().trim();
+
+            Matcher matcher = sFocusedWindowPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String focusedWindow = matcher.group(3);
+                log(focusedWindow);
+                mFocusedWindow = focusedWindow;
+                continue;
+            }
+
+            matcher = sAppErrorFocusedWindowPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String focusedWindow = matcher.group(3);
+                log(focusedWindow);
+                mFocusedWindow = focusedWindow;
+                continue;
+            }
+
+            matcher = sWaitingForDebuggerFocusedWindowPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String focusedWindow = matcher.group(3);
+                log(focusedWindow);
+                mFocusedWindow = focusedWindow;
+                continue;
+            }
+
+            matcher = sFocusedAppPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String focusedApp = matcher.group(5);
+                log(focusedApp);
+                mFocusedApp = focusedApp;
+                continue;
+            }
+
+            matcher = sLastAppTransitionPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String lastAppTransitionPattern = matcher.group(1);
+                log(lastAppTransitionPattern);
+                mLastTransition = lastAppTransitionPattern;
+                continue;
+            }
+
+            matcher = sStableBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mStableBounds.setBounds(left, top, right - left, bottom - top);
+                log(mStableBounds.toString());
+                continue;
+            }
+
+            matcher = sDefaultPinnedStackBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mDefaultPinnedStackBounds.setBounds(left, top, right - left, bottom - top);
+                log(mDefaultPinnedStackBounds.toString());
+                continue;
+            }
+
+            matcher = sPinnedStackMovementBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mPinnedStackMovementBounds.setBounds(left, top, right - left, bottom - top);
+                log(mPinnedStackMovementBounds.toString());
+                continue;
+            }
+
+            matcher = sInputMethodWindowPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                mInputMethodWindowAppToken = matcher.group(1);
+                log(mInputMethodWindowAppToken);
+                continue;
+            }
+
+            matcher = sRotationPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                mRotation = Integer.parseInt(matcher.group(1));
+                continue;
+            }
+
+            matcher = sLastOrientationPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                mLastOrientation = Integer.parseInt(matcher.group(1));
+                continue;
+            }
+
+            matcher = sDisplayFrozenPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                mDisplayFrozen = Boolean.parseBoolean(matcher.group(1));
+                continue;
+            }
+        }
+    }
+
+    void getMatchingWindowTokens(final String windowName, List<String> tokenList) {
+        tokenList.clear();
+
+        for (WindowState ws : mWindowStates) {
+            if (windowName.equals(ws.getName())) {
+                tokenList.add(ws.getToken());
+            }
+        }
+    }
+
+    public void getMatchingVisibleWindowState(final String windowName,
+            List<WindowState> windowList) {
+        windowList.clear();
+        for (WindowState ws : mWindowStates) {
+            if (ws.isShown() && windowName.equals(ws.getName())) {
+                windowList.add(ws);
+            }
+        }
+    }
+
+    WindowState getWindowStateForAppToken(String appToken) {
+        for (WindowState ws : mWindowStates) {
+            if (ws.getToken().equals(appToken)) {
+                return ws;
+            }
+        }
+        return null;
+    }
+
+    Display getDisplay(int displayId) {
+        for (Display display : mDisplays) {
+            if (displayId == display.getDisplayId()) {
+                return display;
+            }
+        }
+        return null;
+    }
+
+    String getFrontWindow() {
+        if (mWindowStates == null || mWindowStates.isEmpty()) {
+            return null;
+        }
+        return mWindowStates.get(0).getName();
+    }
+
+    String getFocusedWindow() {
+        return mFocusedWindow;
+    }
+
+    String getFocusedApp() {
+        return mFocusedApp;
+    }
+
+    String getLastTransition() {
+        return mLastTransition;
+    }
+
+    int getFrontStackId(int displayId) {
+        return mDisplayStacks.get(displayId).get(0).mStackId;
+    }
+
+    public int getRotation() {
+        return mRotation;
+    }
+
+    int getLastOrientation() {
+        return mLastOrientation;
+    }
+
+    boolean containsStack(int stackId) {
+        for (WindowStack stack : mStacks) {
+            if (stackId == stack.mStackId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean isWindowVisible(String windowName) {
+        for (WindowState window : mWindowStates) {
+            if (window.getName().equals(windowName)) {
+                return window.isShown();
+            }
+        }
+        return false;
+    }
+
+    boolean allWindowsVisible(String windowName) {
+        boolean allVisible = false;
+        for (WindowState window : mWindowStates) {
+            if (window.getName().equals(windowName)) {
+                if (!window.isShown()) {
+                    log("[VISIBLE] not visible" + windowName);
+                    return false;
+                }
+                log("[VISIBLE] visible" + windowName);
+                allVisible = true;
+            }
+        }
+        return allVisible;
+    }
+
+    WindowStack getStack(int stackId) {
+        for (WindowStack stack : mStacks) {
+            if (stackId == stack.mStackId) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
+    WindowState getInputMethodWindowState() {
+        return getWindowStateForAppToken(mInputMethodWindowAppToken);
+    }
+
+    Rectangle getStableBounds() {
+        return mStableBounds;
+    }
+
+    Rectangle getDefaultPinnedStackBounds() {
+        return mDefaultPinnedStackBounds;
+    }
+
+    Rectangle getPinnedStackMomentBounds() {
+        return mPinnedStackMovementBounds;
+    }
+
+    WindowState findFirstWindowWithType(int type) {
+        for (WindowState window : mWindowStates) {
+            if (window.getType() == type) {
+                return window;
+            }
+        }
+        return null;
+    }
+
+    public boolean isDisplayFrozen() {
+        return mDisplayFrozen;
+    }
+
+    private void reset() {
+        mSysDump.clear();
+        mStacks.clear();
+        mDisplays.clear();
+        mWindowStates.clear();
+        mFocusedWindow = null;
+        mFocusedApp = null;
+        mInputMethodWindowAppToken = null;
+    }
+
+    static class WindowStack extends WindowContainer {
+
+        private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)");
+        private static final Pattern sWindowAnimationBackgroundSurfacePattern =
+                Pattern.compile("mWindowAnimationBackgroundSurface:");
+
+        int mStackId;
+        ArrayList<WindowTask> mTasks = new ArrayList();
+        boolean mWindowAnimationBackgroundSurfaceShowing;
+
+        private WindowStack() {
+
+        }
+
+        static WindowStack create(
+                LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = stackIdPattern.matcher(line);
+            if (!matcher.matches()) {
+                // Not a stack.
+                return null;
+            }
+            // For the stack Id line we just read.
+            dump.pop();
+
+            final WindowStack stack = new WindowStack();
+            log(line);
+            final String stackId = matcher.group(1);
+            log(stackId);
+            stack.mStackId = Integer.parseInt(stackId);
+            stack.extract(dump, exitPatterns);
+            return stack;
+        }
+
+        void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+
+            final List<Pattern> taskExitPatterns = new ArrayList();
+            Collections.addAll(taskExitPatterns, exitPatterns);
+            taskExitPatterns.add(sTaskIdPattern);
+            taskExitPatterns.add(sWindowAnimationBackgroundSurfacePattern);
+            final Pattern[] taskExitPatternsArray =
+                    taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
+
+            while (!doneExtracting(dump, exitPatterns)) {
+                final WindowTask task =
+                        WindowTask.create(dump, sTaskIdPattern, taskExitPatternsArray);
+
+                if (task != null) {
+                    mTasks.add(task);
+                    continue;
+                }
+
+                final String line = dump.pop().trim();
+
+                if (extractFullscreen(line)) {
+                    continue;
+                }
+
+                if (extractBounds(line)) {
+                    continue;
+                }
+
+                if (extractWindowAnimationBackgroundSurface(line)) {
+                    continue;
+                }
+            }
+        }
+
+        boolean extractWindowAnimationBackgroundSurface(String line) {
+            if (sWindowAnimationBackgroundSurfacePattern.matcher(line).matches()) {
+                log(line);
+                mWindowAnimationBackgroundSurfaceShowing = true;
+                return true;
+            }
+            return false;
+        }
+
+        WindowTask getTask(int taskId) {
+            for (WindowTask task : mTasks) {
+                if (taskId == task.mTaskId) {
+                    return task;
+                }
+            }
+            return null;
+        }
+
+        boolean isWindowAnimationBackgroundSurfaceShowing() {
+            return mWindowAnimationBackgroundSurfaceShowing;
+        }
+    }
+
+    static class WindowTask extends WindowContainer {
+        private static final Pattern sTempInsetBoundsPattern =
+                Pattern.compile("mTempInsetBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
+
+        private static final Pattern sAppTokenPattern = Pattern.compile(
+                "Activity #(\\d+) AppWindowToken\\{(\\S+) token=Token\\{(\\S+) "
+                + "ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}\\}\\}");
+
+
+        int mTaskId;
+        Rectangle mTempInsetBounds;
+        List<String> mAppTokens = new ArrayList();
+
+        private WindowTask() {
+        }
+
+        static WindowTask create(
+                LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            final Matcher matcher = taskIdPattern.matcher(line);
+            if (!matcher.matches()) {
+                // Not a task.
+                return null;
+            }
+            // For the task Id line we just read.
+            dump.pop();
+
+            final WindowTask task = new WindowTask();
+            log(line);
+            final String taskId = matcher.group(1);
+            log(taskId);
+            task.mTaskId = Integer.parseInt(taskId);
+            task.extract(dump, exitPatterns);
+            return task;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+            while (!doneExtracting(dump, exitPatterns)) {
+                final String line = dump.pop().trim();
+
+                if (extractFullscreen(line)) {
+                    continue;
+                }
+
+                if (extractBounds(line)) {
+                    continue;
+                }
+
+                Matcher matcher = sTempInsetBoundsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    mTempInsetBounds = extractBounds(matcher);
+                }
+
+                matcher = sAppTokenPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    final String appToken = matcher.group(6);
+                    log(appToken);
+                    mAppTokens.add(appToken);
+                    continue;
+                }
+            }
+        }
+    }
+
+    static abstract class WindowContainer {
+        protected static final Pattern sFullscreenPattern = Pattern.compile("mFillsParent=(\\S+)");
+        protected static final Pattern sBoundsPattern =
+                Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]");
+
+        protected boolean mFullscreen;
+        protected Rectangle mBounds;
+
+        static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
+            if (dump.isEmpty()) {
+                return true;
+            }
+            final String line = dump.peek().trim();
+
+            for (Pattern pattern : exitPatterns) {
+                if (pattern.matcher(line).matches()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean extractFullscreen(String line) {
+            final Matcher matcher = sFullscreenPattern.matcher(line);
+            if (!matcher.matches()) {
+                return false;
+            }
+            log(line);
+            final String fullscreen = matcher.group(1);
+            log(fullscreen);
+            mFullscreen = Boolean.valueOf(fullscreen);
+            return true;
+        }
+
+        boolean extractBounds(String line) {
+            final Matcher matcher = sBoundsPattern.matcher(line);
+            if (!matcher.matches()) {
+                return false;
+            }
+            log(line);
+            mBounds = extractBounds(matcher);
+            return true;
+        }
+
+        static Rectangle extractBounds(Matcher matcher) {
+            final int left = Integer.valueOf(matcher.group(1));
+            final int top = Integer.valueOf(matcher.group(2));
+            final int right = Integer.valueOf(matcher.group(3));
+            final int bottom = Integer.valueOf(matcher.group(4));
+            final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
+
+            log(rect.toString());
+            return rect;
+        }
+
+        static void extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList) {
+            for (Rectangle rect : rectList) {
+                if (rect == null) {
+                    return;
+                }
+                final int left = Integer.valueOf(matcher.group(groupIndex++));
+                final int top = Integer.valueOf(matcher.group(groupIndex++));
+                final int right = Integer.valueOf(matcher.group(groupIndex++));
+                final int bottom = Integer.valueOf(matcher.group(groupIndex++));
+                rect.setBounds(left, top, right - left, bottom - top);
+            }
+        }
+
+        Rectangle getBounds() {
+            return mBounds;
+        }
+
+        boolean isFullscreen() {
+            return mFullscreen;
+        }
+    }
+
+    static class Display extends WindowContainer {
+        private static final String TAG = "[Display] ";
+
+        private static final Pattern sDisplayInfoPattern =
+                Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
+
+        private final int mDisplayId;
+        private Rectangle mDisplayRect = new Rectangle();
+        private Rectangle mAppRect = new Rectangle();
+        private int mDpi;
+
+        private Display(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        int getDisplayId() {
+            return mDisplayId;
+        }
+
+        int getDpi() {
+            return mDpi;
+        }
+
+        Rectangle getDisplayRect() {
+            return mDisplayRect;
+        }
+
+        Rectangle getAppRect() {
+            return mAppRect;
+        }
+
+        static Display create(LinkedList<String> dump, Pattern[] exitPatterns) {
+            // TODO: exit pattern for displays?
+            final String line = dump.peek().trim();
+
+            Matcher matcher = sDisplayIdPattern.matcher(line);
+            if (!matcher.matches()) {
+                return null;
+            }
+
+            log(TAG + "DISPLAY_ID: " + line);
+            dump.pop();
+
+            final int displayId = Integer.valueOf(matcher.group(1));
+            final Display display = new Display(displayId);
+            display.extract(dump, exitPatterns);
+            return display;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+            while (!doneExtracting(dump, exitPatterns)) {
+                final String line = dump.pop().trim();
+
+                final Matcher matcher = sDisplayInfoPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "DISPLAY_INFO: " + line);
+                    mDpi = Integer.valueOf(matcher.group(2));
+
+                    final int displayWidth = Integer.valueOf(matcher.group(3));
+                    final int displayHeight = Integer.valueOf(matcher.group(4));
+                    mDisplayRect.setBounds(0, 0, displayWidth, displayHeight);
+
+                    final int appWidth = Integer.valueOf(matcher.group(5));
+                    final int appHeight = Integer.valueOf(matcher.group(6));
+                    mAppRect.setBounds(0, 0, appWidth, appHeight);
+
+                    // break as we don't need other info for now
+                    break;
+                }
+                // Extract other info here if needed
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Display #" + mDisplayId + ": mDisplayRect=" + mDisplayRect
+                    + " mAppRect=" + mAppRect;
+        }
+    }
+
+    public static class WindowState extends WindowContainer {
+        private static final String TAG = "[WindowState] ";
+
+        public static final int TYPE_WALLPAPER = 2013;
+
+        private static final int WINDOW_TYPE_NORMAL   = 0;
+        private static final int WINDOW_TYPE_STARTING = 1;
+        private static final int WINDOW_TYPE_EXITING  = 2;
+        private static final int WINDOW_TYPE_DEBUGGER = 3;
+
+        private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]";
+        private static final String NEGATIVE_VALUES_ALLOWED_RECT_STR =
+                "\\[([-\\d]+),([-\\d]+)\\]\\[([-\\d]+),([-\\d]+)\\]";
+        private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+");
+        private static final Pattern sFramePattern =
+                Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
+        private static final Pattern sContentFramePattern =
+            Pattern.compile("content=" + RECT_STR + " .+");
+        private static final Pattern sWindowAssociationPattern =
+                Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
+        private static final Pattern sSurfaceInsetsPattern =
+            Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+");
+        private static final Pattern sContentInsetsPattern =
+                Pattern.compile("Cur insets.+content=" + NEGATIVE_VALUES_ALLOWED_RECT_STR + ".+");
+        private static final Pattern sGivenContentInsetsPattern =
+                Pattern.compile("mGivenContentInsets=" + RECT_STR + ".+");
+        private static final Pattern sCropPattern =
+            Pattern.compile(".+mLastClipRect=" + RECT_STR + ".*");
+        private static final Pattern sSurfacePattern =
+                Pattern.compile("Surface: shown=(\\S+) layer=(\\d+) alpha=[\\d.]+ rect=\\([\\d.-]+,[\\d.-]+\\) [\\d.]+ x [\\d.]+");
+        private static final Pattern sAttrsPattern=
+                Pattern.compile("mAttrs=WM\\.LayoutParams\\{.*ty=(\\d+).*\\}");
+
+
+        private final String mName;
+        private final String mAppToken;
+        private final int mWindowType;
+        private int mType;
+        private int mDisplayId;
+        private int mStackId;
+        private int mLayer;
+        private boolean mShown;
+        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 mContentInsets = new Rectangle();
+        private Rectangle mGivenContentInsets = new Rectangle();
+        private Rectangle mCrop = new Rectangle();
+
+
+        private WindowState(Matcher matcher, int windowType) {
+            mName = matcher.group(4);
+            mAppToken = matcher.group(2);
+            mWindowType = windowType;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        String getToken() {
+            return mAppToken;
+        }
+
+        boolean isStartingWindow() {
+            return mWindowType == WINDOW_TYPE_STARTING;
+        }
+
+        boolean isExitingWindow() {
+            return mWindowType == WINDOW_TYPE_EXITING;
+        }
+
+        boolean isDebuggerWindow() {
+            return mWindowType == WINDOW_TYPE_DEBUGGER;
+        }
+
+        int getDisplayId() {
+            return mDisplayId;
+        }
+
+        int getStackId() {
+            return mStackId;
+        }
+
+        int getLayer() {
+            return mLayer;
+        }
+
+        Rectangle getContainingFrame() {
+            return mContainingFrame;
+        }
+
+        Rectangle getFrame() {
+            return mFrame;
+        }
+
+        Rectangle getSurfaceInsets() {
+            return mSurfaceInsets;
+        }
+
+        Rectangle getContentInsets() {
+            return mContentInsets;
+        }
+
+        Rectangle getGivenContentInsets() {
+            return mGivenContentInsets;
+        }
+
+        Rectangle getContentFrame() {
+            return mContentFrame;
+        }
+
+        Rectangle getParentFrame() {
+            return mParentFrame;
+        }
+
+        Rectangle getCrop() {
+            return mCrop;
+        }
+
+        boolean isShown() {
+            return mShown;
+        }
+
+        int getType() {
+            return mType;
+        }
+
+        static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) {
+            final String line = dump.peek().trim();
+
+            Matcher matcher = sWindowPattern.matcher(line);
+            if (!matcher.matches()) {
+                return null;
+            }
+
+            log(TAG + "WINDOW: " + line);
+            dump.pop();
+
+            final WindowState window;
+            Matcher specialMatcher;
+            if ((specialMatcher = sStartingWindowPattern.matcher(line)).matches()) {
+                log(TAG + "STARTING: " + line);
+                window = new WindowState(specialMatcher, WINDOW_TYPE_STARTING);
+            } else if ((specialMatcher = sExitingWindowPattern.matcher(line)).matches()) {
+                log(TAG + "EXITING: " + line);
+                window = new WindowState(specialMatcher, WINDOW_TYPE_EXITING);
+            } else if ((specialMatcher = sDebuggerWindowPattern.matcher(line)).matches()) {
+                log(TAG + "DEBUGGER: " + line);
+                window = new WindowState(specialMatcher, WINDOW_TYPE_DEBUGGER);
+            } else {
+                window = new WindowState(matcher, WINDOW_TYPE_NORMAL);
+            }
+
+            window.extract(dump, exitPatterns);
+            return window;
+        }
+
+        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
+            while (!doneExtracting(dump, exitPatterns)) {
+                final String line = dump.pop().trim();
+
+                Matcher matcher = sWindowAssociationPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "WINDOW_ASSOCIATION: " + line);
+                    mDisplayId = Integer.valueOf(matcher.group(1));
+                    mStackId = Integer.valueOf(matcher.group(2));
+                    continue;
+                }
+
+                matcher = sMainFramePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "MAIN WINDOW FRAME: " + line);
+                    mFrame = extractBounds(matcher);
+                    continue;
+                }
+
+                matcher = sFramePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "FRAME: " + line);
+                    extractMultipleBounds(matcher, 1, mContainingFrame, mParentFrame);
+                    continue;
+                }
+
+                matcher = sContentFramePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CONTENT FRAME: " + line);
+                    mContentFrame = extractBounds(matcher);
+                }
+
+                matcher = sSurfaceInsetsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "INSETS: " + line);
+                    mSurfaceInsets = extractBounds(matcher);
+                }
+
+                matcher = sContentInsetsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CONTENT INSETS: " + line);
+                    mContentInsets = extractBounds(matcher);
+                }
+
+                matcher = sCropPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CROP: " + line);
+                    mCrop = extractBounds(matcher);
+                }
+
+                matcher = sSurfacePattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "SURFACE: " + line);
+                    mShown = Boolean.valueOf(matcher.group(1));
+                    mLayer = Integer.valueOf(matcher.group(2));
+                }
+
+                matcher = sAttrsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "ATTRS: " + line);
+                    mType = Integer.valueOf(matcher.group(1));
+                }
+
+                matcher = sGivenContentInsetsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "GIVEN CONTENT INSETS: " + line);
+                    mGivenContentInsets = extractBounds(matcher);
+                }
+
+                // Extract other info here if needed
+            }
+        }
+
+        private static String getWindowTypeSuffix(int windowType) {
+            switch (windowType) {
+            case WINDOW_TYPE_STARTING: return " STARTING";
+            case WINDOW_TYPE_EXITING: return " EXITING";
+            case WINDOW_TYPE_DEBUGGER: return " DEBUGGER";
+            default: break;
+            }
+            return "";
+        }
+
+        @Override
+        public String toString() {
+            return "WindowState: {" + mAppToken + " " + mName
+                    + getWindowTypeSuffix(mWindowType) + "}"
+                    + " cf=" + mContainingFrame + " pf=" + mParentFrame;
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
new file mode 100644
index 0000000..fd07930
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE := CtsWindowManagerHostTestCases
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed CtsServicesHostTestCases
+LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
+
+LOCAL_CTS_TEST_PACKAGE := android.server.cts
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml
new file mode 100644
index 0000000..67c4879
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<configuration description="Config for CTS drag and drop host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <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="CtsWindowManagerHostTestCases.jar" />
+        <option name="runtime-hint" value="20m40s" />
+    </test>
+</configuration>
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/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
new file mode 100644
index 0000000..7cb7b8b
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
@@ -0,0 +1,131 @@
+/*
+ * 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.wm.cts.dndsourceapp;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.FileUriExposedException;
+import android.os.PersistableBundle;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+
+import java.io.File;
+
+public class DragSource extends Activity{
+    private static final String LOG_TAG = "DragSource";
+
+    private static final String RESULT_KEY_START_DRAG = "START_DRAG";
+    private static final String RESULT_KEY_DETAILS = "DETAILS";
+    private static final String RESULT_OK = "OK";
+    private static final String RESULT_EXCEPTION = "Exception";
+
+    private static final String URI_PREFIX =
+            "content://" + DragSourceContentProvider.AUTHORITY + "/data";
+
+    private static final String MAGIC_VALUE = "42";
+    private static final long TIMEOUT_CANCEL = 150;
+
+    private TextView mTextView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        View view = getLayoutInflater().inflate(R.layout.source_activity, null);
+        setContentView(view);
+
+        final Uri plainUri = Uri.parse(URI_PREFIX + "/" + MAGIC_VALUE);
+
+        setUpDragSource("disallow_global", plainUri, 0);
+        setUpDragSource("cancel_soon", plainUri, View.DRAG_FLAG_GLOBAL);
+
+        setUpDragSource("grant_none", plainUri, View.DRAG_FLAG_GLOBAL);
+        setUpDragSource("grant_read", plainUri,
+                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
+        setUpDragSource("grant_write", plainUri,
+                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_WRITE);
+        setUpDragSource("grant_read_persistable", plainUri,
+                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
+                        View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION);
+
+        final Uri prefixUri = Uri.parse(URI_PREFIX);
+
+        setUpDragSource("grant_read_prefix", prefixUri,
+                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
+                        View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION);
+        setUpDragSource("grant_read_noprefix", prefixUri,
+                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
+
+        final Uri fileUri = Uri.fromFile(new File("/sdcard/sample.jpg"));
+
+        setUpDragSource("file_local", fileUri, 0);
+        setUpDragSource("file_global", fileUri, View.DRAG_FLAG_GLOBAL);
+    }
+
+    private void setUpDragSource(String mode, final Uri uri, final int flags) {
+        if (!mode.equals(getIntent().getStringExtra("mode"))) {
+            return;
+        }
+        mTextView = (TextView) findViewById(R.id.drag_source);
+        mTextView.setText(mode);
+        mTextView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (event.getAction() != MotionEvent.ACTION_DOWN) {
+                    return false;
+                }
+                try {
+                    final ClipDescription clipDescription = new ClipDescription("", new String[] {
+                            ClipDescription.MIMETYPE_TEXT_URILIST });
+                    PersistableBundle extras = new PersistableBundle(1);
+                    extras.putString("extraKey", "extraValue");
+                    clipDescription.setExtras(extras);
+                    final ClipData clipData = new ClipData(clipDescription, new ClipData.Item(uri));
+                    v.startDragAndDrop(
+                            clipData,
+                            new View.DragShadowBuilder(v),
+                            null,
+                            flags);
+                    logResult(RESULT_KEY_START_DRAG, RESULT_OK);
+                } catch (FileUriExposedException e) {
+                    logResult(RESULT_KEY_DETAILS, e.getMessage());
+                    logResult(RESULT_KEY_START_DRAG, RESULT_EXCEPTION);
+                }
+                if (mode.equals("cancel_soon")) {
+                    new Handler().postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            v.cancelDragAndDrop();
+                        }
+                    }, TIMEOUT_CANCEL);
+                }
+                return true;
+            }
+        });
+    }
+
+    private void logResult(String key, String value) {
+        Log.i(LOG_TAG, key + "=" + value);
+        mTextView.setText(mTextView.getText() + "\n" + key + "=" + value);
+    }
+}
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/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
new file mode 100644
index 0000000..8892c6f
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.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.wm.cts.dndtargetapp;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.util.Log;
+import android.view.DragAndDropPermissions;
+import android.view.DragEvent;
+import android.view.View;
+import android.widget.TextView;
+
+public class DropTarget extends Activity {
+    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";
+
+    private TextView mTextView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        View view = getLayoutInflater().inflate(R.layout.target_activity, null);
+        setContentView(view);
+
+        setUpDropTarget("request_none", new OnDragUriReadListener(false));
+        setUpDropTarget("request_read", new OnDragUriReadListener());
+        setUpDropTarget("request_write", new OnDragUriWriteListener());
+        setUpDropTarget("request_read_nested", new OnDragUriReadPrefixListener());
+        setUpDropTarget("request_take_persistable", new OnDragUriTakePersistableListener());
+    }
+
+    private void setUpDropTarget(String mode, OnDragUriListener listener) {
+        if (!mode.equals(getIntent().getStringExtra("mode"))) {
+            return;
+        }
+        mTextView = (TextView)findViewById(R.id.drag_target);
+        mTextView.setText(mode);
+        mTextView.setOnDragListener(listener);
+    }
+
+    private String checkExtraValue(DragEvent event) {
+        PersistableBundle extras = event.getClipDescription().getExtras();
+        if (extras == null) {
+            return "Null";
+        }
+
+        final String value = extras.getString("extraKey");
+        if ("extraValue".equals(value)) {
+            return RESULT_OK;
+        }
+        return value;
+    }
+
+    private void logResult(String key, String value) {
+        Log.i(LOG_TAG, key + "=" + value);
+        mTextView.setText(mTextView.getText() + "\n" + key + "=" + value);
+    }
+
+    private abstract class OnDragUriListener implements View.OnDragListener {
+        private final boolean requestPermissions;
+
+        public OnDragUriListener(boolean requestPermissions) {
+            this.requestPermissions = requestPermissions;
+        }
+
+        @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);
+                    logResult(RESULT_KEY_EXTRAS, checkExtraValue(event));
+                    return true;
+
+                case DragEvent.ACTION_DRAG_ENTERED:
+                    return true;
+
+                case DragEvent.ACTION_DRAG_LOCATION:
+                    return true;
+
+                case DragEvent.ACTION_DRAG_EXITED:
+                    return true;
+
+                case DragEvent.ACTION_DROP:
+                    // 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:
+                    return false;
+            }
+        }
+
+        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) {
+                return "Null ClipData";
+            }
+            if (clipData.getItemCount() == 0) {
+                return "Empty ClipData";
+            }
+            ClipData.Item item = clipData.getItemAt(0);
+            if (item == null) {
+                return "Null ClipData.Item";
+            }
+            Uri uri = item.getUri();
+            if (uri == null) {
+                return "Null Uri";
+            }
+
+            DragAndDropPermissions permissions = null;
+            if (requestPermissions) {
+                permissions = requestDragAndDropPermissions(event);
+                if (permissions == null) {
+                    return "Null DragAndDropPermissions";
+                }
+            }
+
+            try {
+                return processUri(uri);
+            } finally {
+                if (permissions != null) {
+                    permissions.release();
+                }
+            }
+        }
+
+        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);
+        }
+
+        OnDragUriReadListener() {
+            super(true);
+        }
+
+        protected String processUri(Uri uri) {
+            return checkQueryResult(uri, MAGIC_VALUE);
+        }
+
+        protected String checkQueryResult(Uri uri, String expectedValue) {
+            Cursor cursor = null;
+            try {
+                cursor = getContentResolver().query(uri, null, null, null, null);
+                if (cursor == null) {
+                    return "Null Cursor";
+                }
+                cursor.moveToPosition(0);
+                String value = cursor.getString(0);
+                if (!expectedValue.equals(value)) {
+                    return "Wrong value: " + value;
+                }
+                return RESULT_OK;
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+        }
+    }
+
+    private class OnDragUriWriteListener extends OnDragUriListener {
+        OnDragUriWriteListener() {
+            super(true);
+        }
+
+        protected String processUri(Uri uri) {
+            ContentValues values = new ContentValues();
+            values.put("key", 100);
+            getContentResolver().update(uri, values, null, null);
+            return RESULT_OK;
+        }
+    }
+
+    private class OnDragUriReadPrefixListener extends OnDragUriReadListener {
+        @Override
+        protected String processUri(Uri uri) {
+            final String result1 = queryPrefixed(uri, "1");
+            if (!result1.equals(RESULT_OK)) {
+                return result1;
+            }
+            final String result2 = queryPrefixed(uri, "2");
+            if (!result2.equals(RESULT_OK)) {
+                return result2;
+            }
+            return queryPrefixed(uri, "3");
+        }
+
+        private String queryPrefixed(Uri uri, String selector) {
+            final Uri prefixedUri = Uri.parse(uri.toString() + "/" + selector);
+            return checkQueryResult(prefixedUri, selector);
+        }
+    }
+
+    private class OnDragUriTakePersistableListener extends OnDragUriListener {
+        OnDragUriTakePersistableListener() {
+            super(true);
+        }
+
+        @Override
+        protected String processUri(Uri uri) {
+            getContentResolver().takePersistableUriPermission(
+                    uri, View.DRAG_FLAG_GLOBAL_URI_READ);
+            getContentResolver().releasePersistableUriPermission(
+                    uri, View.DRAG_FLAG_GLOBAL_URI_READ);
+            return RESULT_OK;
+        }
+    }
+}
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/activityandwindowmanager/windowmanager/frametestapp/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
new file mode 100644
index 0000000..e5aa610
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := test_current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsDeviceWindowFramesTestApp
+
+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..ca38ea2
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<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"
+        />
+        <activity android:name=".MovingSurfaceViewTestActivity"
+                  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/MovingSurfaceViewTestActivity.java b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingSurfaceViewTestActivity.java
new file mode 100644
index 0000000..96cfe01
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingSurfaceViewTestActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+// This activity will parent a SurfaceView to the main window, and then move
+// the main window around. We can use this to verify the SurfaceView
+// is properly updated.
+public class MovingSurfaceViewTestActivity extends Activity {
+    SurfaceView mSurfaceView;
+    int mX = 0;
+    int mY = 0;
+
+    final Runnable moveWindow = new Runnable() {
+            @Override
+            public void run() {
+                final Window w = getWindow();
+                final WindowManager.LayoutParams attribs = w.getAttributes();
+                attribs.x = mX % 1000;
+                attribs.y = mY % 1000;
+                w.setAttributes(attribs);
+                mX += 5;
+                mY += 5;
+                mSurfaceView.postDelayed(this, 50);
+            }
+    };
+
+    protected void onCreate(Bundle icicle) {
+        final LayoutParams p = new LayoutParams(100, 100);
+        final Window w = getWindow();
+        w.setLayout(100, 100);
+
+        mSurfaceView = new SurfaceView(this);
+        setContentView(mSurfaceView, p);
+
+        super.onCreate(icicle);
+    }
+
+    protected void onResume() {
+        mSurfaceView.postDelayed(moveWindow, 50);
+        super.onResume();
+    }
+}
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/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
new file mode 100644
index 0000000..008a6ef
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
@@ -0,0 +1,480 @@
+/*
+ * 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.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CrossAppDragAndDropTests extends DeviceTestCase {
+    // Constants copied from ActivityManager.StackId. If they are changed there, these must be
+    // updated.
+    /** ID of stack where fullscreen activities are normally launched into. */
+    private static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
+
+    /** ID of stack where freeform/resized activities are normally launched into. */
+    private static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that occupies a dedicated region of the screen. */
+    private static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
+
+    /** ID of stack that always on top (always visible) when it exists. */
+    private static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+
+    private static final String AM_FORCE_STOP = "am force-stop ";
+    private static final String AM_MOVE_TASK = "am stack move-task ";
+    private static final String AM_REMOVE_STACK = "am stack remove ";
+    private static final String AM_START_N = "am start -n ";
+    private static final String AM_STACK_LIST = "am stack list";
+    private static final String INPUT_MOUSE_SWIPE = "input mouse swipe ";
+    private static final String TASK_ID_PREFIX = "taskId";
+
+    private static final int SWIPE_DURATION_MS = 500;
+
+    private static final String SOURCE_PACKAGE_NAME = "android.wm.cts.dndsourceapp";
+    private static final String TARGET_PACKAGE_NAME = "android.wm.cts.dndtargetapp";
+    private static final String TARGET_23_PACKAGE_NAME = "android.wm.cts.dndtargetappsdk23";
+
+
+    private static final String SOURCE_ACTIVITY_NAME = "DragSource";
+    private static final String TARGET_ACTIVITY_NAME = "DropTarget";
+
+    private static final String FILE_GLOBAL = "file_global";
+    private static final String FILE_LOCAL = "file_local";
+    private static final String DISALLOW_GLOBAL = "disallow_global";
+    private static final String CANCEL_SOON = "cancel_soon";
+    private static final String GRANT_NONE = "grant_none";
+    private static final String GRANT_READ = "grant_read";
+    private static final String GRANT_WRITE = "grant_write";
+    private static final String GRANT_READ_PREFIX = "grant_read_prefix";
+    private static final String GRANT_READ_NOPREFIX = "grant_read_noprefix";
+    private static final String GRANT_READ_PERSISTABLE = "grant_read_persistable";
+
+    private static final String REQUEST_NONE = "request_none";
+    private static final String REQUEST_READ = "request_read";
+    private static final String REQUEST_READ_NESTED = "request_read_nested";
+    private static final String REQUEST_TAKE_PERSISTABLE = "request_take_persistable";
+    private static final String REQUEST_WRITE = "request_write";
+
+    private static final String SOURCE_LOG_TAG = "DragSource";
+    private static final String TARGET_LOG_TAG = "DropTarget";
+
+    private static final String RESULT_KEY_START_DRAG = "START_DRAG";
+    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_MISSING = "Missing";
+    private static final String RESULT_OK = "OK";
+    private static final String RESULT_EXCEPTION = "Exception";
+    private static final String RESULT_NULL_DROP_PERMISSIONS = "Null DragAndDropPermissions";
+
+    private ITestDevice mDevice;
+
+    private Map<String, String> mSourceResults;
+    private Map<String, String> mTargetResults;
+
+    private String mSourcePackageName;
+    private String mTargetPackageName;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevice = getDevice();
+
+        if (!supportsDragAndDrop()) {
+            return;
+        }
+
+        mSourcePackageName = SOURCE_PACKAGE_NAME;
+        mTargetPackageName = TARGET_PACKAGE_NAME;
+        cleanupState();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        if (!supportsDragAndDrop()) {
+            return;
+        }
+
+        mDevice.executeShellCommand(AM_FORCE_STOP + mSourcePackageName);
+        mDevice.executeShellCommand(AM_FORCE_STOP + mTargetPackageName);
+    }
+
+    private String executeShellCommand(String command) throws DeviceNotAvailableException {
+        return mDevice.executeShellCommand(command);
+    }
+
+    private void clearLogs() throws DeviceNotAvailableException {
+        executeShellCommand("logcat -c");
+    }
+
+    private String getStartCommand(String componentName, String modeExtra) {
+        return AM_START_N + componentName + " -e mode " + modeExtra;
+    }
+
+    private String getMoveTaskCommand(int taskId, int stackId) throws Exception {
+        return AM_MOVE_TASK + taskId + " " + stackId + " true";
+    }
+
+    private String getComponentName(String packageName, String activityName) {
+        return packageName + "/" + packageName + "." + activityName;
+    }
+
+    /**
+     * Make sure that the special activity stacks are removed and the ActivityManager/WindowManager
+     * is in a good state.
+     */
+    private void cleanupState() throws Exception {
+        executeShellCommand(AM_FORCE_STOP + SOURCE_PACKAGE_NAME);
+        executeShellCommand(AM_FORCE_STOP + TARGET_PACKAGE_NAME);
+        executeShellCommand(AM_FORCE_STOP + TARGET_23_PACKAGE_NAME);
+        unlockDevice();
+
+        // Reinitialize the docked stack to force the window manager to reset its default bounds.
+        // See b/29068935.
+        clearLogs();
+        final String componentName = getComponentName(mSourcePackageName, SOURCE_ACTIVITY_NAME);
+        executeShellCommand(getStartCommand(componentName, null) + " --stack " +
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        final int taskId = getActivityTaskId(componentName);
+        // Moving a task from the full screen stack to the docked stack resets
+        // WindowManagerService#mDockedStackCreateBounds.
+        executeShellCommand(getMoveTaskCommand(taskId, DOCKED_STACK_ID));
+        waitForResume(mSourcePackageName, SOURCE_ACTIVITY_NAME);
+        executeShellCommand(AM_FORCE_STOP + SOURCE_PACKAGE_NAME);
+
+        // Remove special stacks.
+        executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
+        executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
+        executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
+    }
+
+    private void launchDockedActivity(String packageName, String activityName, String mode)
+            throws Exception {
+        clearLogs();
+        final String componentName = getComponentName(packageName, activityName);
+        executeShellCommand(getStartCommand(componentName, mode) + " --stack " + DOCKED_STACK_ID);
+        waitForResume(packageName, activityName);
+    }
+
+    private void launchFullscreenActivity(String packageName, String activityName, String mode)
+            throws Exception {
+        clearLogs();
+        final String componentName = getComponentName(packageName, activityName);
+        executeShellCommand(getStartCommand(componentName, mode) + " --stack "
+                + FULLSCREEN_WORKSPACE_STACK_ID);
+        waitForResume(packageName, activityName);
+    }
+
+    private void waitForResume(String packageName, String activityName) throws Exception {
+        final String fullActivityName = packageName + "." + activityName;
+        int retryCount = 3;
+        do {
+            Thread.sleep(500);
+            String logs = executeShellCommand("logcat -d -b events");
+            for (String line : logs.split("\\n")) {
+                if(line.contains("am_on_resume_called") && line.contains(fullActivityName)) {
+                    return;
+                }
+            }
+        } while (retryCount-- > 0);
+
+        throw new Exception(fullActivityName + " has failed to start");
+    }
+
+    private void injectInput(Point from, Point to, int durationMs) throws Exception {
+        executeShellCommand(
+                INPUT_MOUSE_SWIPE + from.x + " " + from.y + " " + to.x + " " + to.y + " " +
+                durationMs);
+    }
+
+    static class Point {
+        public int x, y;
+
+        public Point(int _x, int _y) {
+            x=_x;
+            y=_y;
+        }
+
+        public Point() {}
+    }
+
+    private String findTaskInfo(String name) throws Exception {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+        final String output = outputReceiver.getOutput();
+        for (String line : output.split("\\n")) {
+            final String truncatedLine;
+            // Only look for the activity name before the "topActivity" string.
+            final int pos = line.indexOf("topActivity");
+            if (pos > 0) {
+                truncatedLine = line.substring(0, pos);
+            } else {
+                truncatedLine = line;
+            }
+            if (truncatedLine.contains(name)) {
+                return truncatedLine;
+            }
+        }
+        return "";
+    }
+
+    private boolean getWindowBounds(String name, Point from, Point to) throws Exception {
+        final String taskInfo = findTaskInfo(name);
+        final String[] sections = taskInfo.split("\\[");
+        if (sections.length > 2) {
+            try {
+                parsePoint(sections[1], from);
+                parsePoint(sections[2], to);
+                return true;
+            } catch (Exception e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    private int getActivityTaskId(String name) throws Exception {
+        final String taskInfo = findTaskInfo(name);
+        for (String word : taskInfo.split("\\s+")) {
+            if (word.startsWith(TASK_ID_PREFIX)) {
+                final String withColon = word.split("=")[1];
+                return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
+            }
+        }
+        return -1;
+    }
+
+    private Point getWindowCenter(String name) throws Exception {
+        Point p1 = new Point();
+        Point p2 = new Point();
+        if (getWindowBounds(name, p1, p2)) {
+            return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
+        }
+        return null;
+    }
+
+    private void parsePoint(String string, Point point) {
+        final String[] parts = string.split("[,|\\]]");
+        point.x = Integer.parseInt(parts[0]);
+        point.y = Integer.parseInt(parts[1]);
+    }
+
+    private void unlockDevice() throws DeviceNotAvailableException {
+        // Wake up the device, if necessary.
+        executeShellCommand("input keyevent 224");
+        // Unlock the screen.
+        executeShellCommand("input keyevent 82");
+    }
+
+    private Map<String, String> getLogResults(String className, String lastResultKey)
+            throws Exception {
+        int retryCount = 10;
+        Map<String, String> output = new HashMap<String, String>();
+        do {
+
+            String logs = executeShellCommand("logcat -v brief -d " + className + ":I" + " *:S");
+            for (String line : logs.split("\\n")) {
+                if (line.startsWith("I/" + className)) {
+                    String payload = line.split(":")[1].trim();
+                    final String[] split = payload.split("=");
+                    if (split.length > 1) {
+                        output.put(split[0], split[1]);
+                    }
+                }
+            }
+            if (output.containsKey(lastResultKey)) {
+                return output;
+            }
+        } while (retryCount-- > 0);
+        return output;
+    }
+
+    private void assertDropResult(String sourceMode, String targetMode, String expectedDropResult)
+            throws Exception {
+        assertDragAndDropResults(sourceMode, targetMode, RESULT_OK, expectedDropResult, RESULT_OK);
+    }
+
+    private void assertNoGlobalDragEvents(String sourceMode, String expectedStartDragResult)
+            throws Exception {
+        assertDragAndDropResults(
+                sourceMode, REQUEST_NONE, expectedStartDragResult, RESULT_MISSING, RESULT_MISSING);
+    }
+
+    private void assertDragAndDropResults(String sourceMode, String targetMode,
+                                          String expectedStartDragResult, String expectedDropResult,
+                                          String expectedListenerResults) throws Exception {
+        if (!supportsDragAndDrop()) {
+            return;
+        }
+
+        launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
+        launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
+
+        clearLogs();
+
+        injectInput(
+                getWindowCenter(getComponentName(mSourcePackageName, SOURCE_ACTIVITY_NAME)),
+                getWindowCenter(getComponentName(mTargetPackageName, TARGET_ACTIVITY_NAME)),
+                SWIPE_DURATION_MS);
+
+        mSourceResults = getLogResults(SOURCE_LOG_TAG, RESULT_KEY_START_DRAG);
+        assertSourceResult(RESULT_KEY_START_DRAG, expectedStartDragResult);
+
+        mTargetResults = getLogResults(TARGET_LOG_TAG, RESULT_KEY_DRAG_ENDED);
+        assertTargetResult(RESULT_KEY_DROP_RESULT, expectedDropResult);
+        if (!RESULT_MISSING.equals(expectedDropResult)) {
+            assertTargetResult(RESULT_KEY_ACCESS_BEFORE, RESULT_EXCEPTION);
+            assertTargetResult(RESULT_KEY_ACCESS_AFTER, RESULT_EXCEPTION);
+        }
+        assertListenerResults(expectedListenerResults);
+    }
+
+    private void assertListenerResults(String expectedResult) throws Exception {
+        assertTargetResult(RESULT_KEY_DRAG_STARTED, expectedResult);
+        assertTargetResult(RESULT_KEY_DRAG_ENDED, expectedResult);
+        assertTargetResult(RESULT_KEY_EXTRAS, expectedResult);
+
+        assertTargetResult(RESULT_KEY_CLIP_DATA_ERROR, RESULT_MISSING);
+        assertTargetResult(RESULT_KEY_CLIP_DESCR_ERROR, RESULT_MISSING);
+        assertTargetResult(RESULT_KEY_LOCAL_STATE_ERROR, RESULT_MISSING);
+    }
+
+    private void assertSourceResult(String resultKey, String expectedResult) throws Exception {
+        assertResult(mSourceResults, resultKey, expectedResult);
+    }
+
+    private void assertTargetResult(String resultKey, String expectedResult) throws Exception {
+        assertResult(mTargetResults, resultKey, expectedResult);
+    }
+
+    private void assertResult(Map<String, String> results, String resultKey, String expectedResult)
+            throws Exception {
+        if (!supportsDragAndDrop()) {
+            return;
+        }
+
+        if (RESULT_MISSING.equals(expectedResult)) {
+            if (results.containsKey(resultKey)) {
+                fail("Unexpected " + resultKey + "=" + results.get(resultKey));
+            }
+        } else {
+            assertTrue("Missing " + resultKey, results.containsKey(resultKey));
+            assertEquals(resultKey + " result mismatch,", expectedResult,
+                    results.get(resultKey));
+        }
+    }
+
+    private boolean supportsDragAndDrop() throws Exception {
+        String supportsMultiwindow = mDevice.executeShellCommand("am supports-multiwindow").trim();
+        if ("true".equals(supportsMultiwindow)) {
+            return true;
+        } else if ("false".equals(supportsMultiwindow)) {
+            return false;
+        } else {
+            throw new Exception(
+                    "device does not support \"am supports-multiwindow\" shell command.");
+        }
+    }
+
+    public void testCancelSoon() throws Exception {
+        assertDropResult(CANCEL_SOON, REQUEST_NONE, RESULT_MISSING);
+    }
+
+    public void testDisallowGlobal() throws Exception {
+        assertNoGlobalDragEvents(DISALLOW_GLOBAL, RESULT_OK);
+    }
+
+    public void testDisallowGlobalBelowSdk24() throws Exception {
+        mTargetPackageName = TARGET_23_PACKAGE_NAME;
+        assertNoGlobalDragEvents(GRANT_NONE, RESULT_OK);
+    }
+
+    public void testFileUriLocal() throws Exception {
+        assertNoGlobalDragEvents(FILE_LOCAL, RESULT_OK);
+    }
+
+    public void testFileUriGlobal() throws Exception {
+        assertNoGlobalDragEvents(FILE_GLOBAL, RESULT_EXCEPTION);
+    }
+
+    public void testGrantNoneRequestNone() throws Exception {
+        assertDropResult(GRANT_NONE, REQUEST_NONE, RESULT_EXCEPTION);
+    }
+
+    public void testGrantNoneRequestRead() throws Exception {
+        assertDropResult(GRANT_NONE, REQUEST_READ, RESULT_NULL_DROP_PERMISSIONS);
+    }
+
+    public void testGrantNoneRequestWrite() throws Exception {
+        assertDropResult(GRANT_NONE, REQUEST_WRITE, RESULT_NULL_DROP_PERMISSIONS);
+    }
+
+    public void testGrantReadRequestNone() throws Exception {
+        assertDropResult(GRANT_READ, REQUEST_NONE, RESULT_EXCEPTION);
+    }
+
+    public void testGrantReadRequestRead() throws Exception {
+        assertDropResult(GRANT_READ, REQUEST_READ, RESULT_OK);
+    }
+
+    public void testGrantReadRequestWrite() throws Exception {
+        assertDropResult(GRANT_READ, REQUEST_WRITE, RESULT_EXCEPTION);
+    }
+
+    public void testGrantReadNoPrefixRequestReadNested() throws Exception {
+        assertDropResult(GRANT_READ_NOPREFIX, REQUEST_READ_NESTED, RESULT_EXCEPTION);
+    }
+
+    public void testGrantReadPrefixRequestReadNested() throws Exception {
+        assertDropResult(GRANT_READ_PREFIX, REQUEST_READ_NESTED, RESULT_OK);
+    }
+
+    public void testGrantPersistableRequestTakePersistable() throws Exception {
+        assertDropResult(GRANT_READ_PERSISTABLE, REQUEST_TAKE_PERSISTABLE, RESULT_OK);
+    }
+
+    public void testGrantReadRequestTakePersistable() throws Exception {
+        assertDropResult(GRANT_READ, REQUEST_TAKE_PERSISTABLE, RESULT_EXCEPTION);
+    }
+
+    public void testGrantWriteRequestNone() throws Exception {
+        assertDropResult(GRANT_WRITE, REQUEST_NONE, RESULT_EXCEPTION);
+    }
+
+    public void testGrantWriteRequestRead() throws Exception {
+        assertDropResult(GRANT_WRITE, REQUEST_READ, RESULT_EXCEPTION);
+    }
+
+    public void testGrantWriteRequestWrite() throws Exception {
+        assertDropResult(GRANT_WRITE, REQUEST_WRITE, RESULT_OK);
+    }
+}
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..56b1b40
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
@@ -0,0 +1,212 @@
+/*
+ * 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.log.LogUtil.CLog;
+
+import android.server.cts.WindowManagerState.WindowState;
+
+public class DialogFrameTests extends ParentChildTestBase {
+    private List<WindowState> mWindowList = new ArrayList();
+
+    @Override
+    String intentKey() {
+        return "android.server.FrameTestApp.DialogTestCase";
+    }
+
+    @Override
+    String activityName() {
+        return "DialogTestActivity";
+    }
+
+    WindowState getSingleWindow(String windowName) {
+        try {
+            mAmWmState.getWmState().getMatchingVisibleWindowState(
+                    getBaseWindowName() + windowName, mWindowList);
+            return mWindowList.get(0);
+        } catch (Exception e) {
+            CLog.logAndDisplay(LogLevel.INFO, "Couldn't find window: " + windowName);
+            return null;
+        }
+    }
+
+    void doSingleTest(ParentChildTest 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);
+    }
+
+    // With Width and Height as MATCH_PARENT we should fill
+    // the same content frame as the main activity window
+    public void testMatchParentDialog() throws Exception {
+        doParentChildTest("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 {
+        doParentChildTest("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 {
+        doParentChildTest("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 {
+        doParentChildTest("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 {
+        doParentChildTest("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 {
+    //        doParentChildTest("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 {
+        doParentChildTest("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 {
+        doParentChildTest("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;
+        doParentChildTest("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;
+        doParentChildTest("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 {
+        doParentChildTest("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/ParentChildTestBase.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/ParentChildTestBase.java
new file mode 100644
index 0000000..5518f08
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/ParentChildTestBase.java
@@ -0,0 +1,71 @@
+/*
+ * 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.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.server.cts.WindowManagerState.WindowState;
+import android.server.cts.ActivityManagerTestBase;
+
+public abstract class ParentChildTestBase extends ActivityManagerTestBase {
+    private static final String COMPONENT_NAME = "android.server.FrameTestApp";
+
+    interface ParentChildTest {
+        void doTest(WindowState parent, WindowState child);
+    }
+
+    public void startTestCase(String testCase) throws Exception {
+        setComponentName(COMPONENT_NAME);
+        String cmd = getAmStartCmd(activityName(), intentKey(), testCase);
+        CLog.logAndDisplay(LogLevel.INFO, cmd);
+        executeShellCommand(cmd);
+    }
+
+    public void startTestCaseDocked(String testCase) throws Exception {
+        setComponentName(COMPONENT_NAME);
+        String cmd = getAmStartCmd(activityName(), intentKey(), testCase);
+        CLog.logAndDisplay(LogLevel.INFO, cmd);
+        executeShellCommand(cmd);
+        moveActivityToDockStack(activityName());
+    }
+
+    abstract String intentKey();
+    abstract String activityName();
+
+    abstract void doSingleTest(ParentChildTest t) throws Exception;
+
+    void doFullscreenTest(String testCase, ParentChildTest t) throws Exception {
+        CLog.logAndDisplay(LogLevel.INFO, "Running test fullscreen");
+        startTestCase(testCase);
+        doSingleTest(t);
+        stopTestCase();
+    }
+
+    void doDockedTest(String testCase, ParentChildTest t) throws Exception {
+        CLog.logAndDisplay(LogLevel.INFO, "Running test docked");
+        startTestCaseDocked(testCase);
+        doSingleTest(t);
+        stopTestCase();
+    }
+
+    void doParentChildTest(String testCase, ParentChildTest t) throws Exception {
+        doFullscreenTest(testCase, t);
+        doDockedTest(testCase, t);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewMovementTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewMovementTests.java
new file mode 100644
index 0000000..ecada0e
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewMovementTests.java
@@ -0,0 +1,114 @@
+/*
+ * 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 static android.server.cts.StateLogger.logE;
+
+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 SurfaceViewMovementTests extends SurfaceViewTests {
+    private List<WindowState> mWindowList = new ArrayList();
+
+    @Override
+    String activityName() {
+        return "MovingSurfaceViewTestActivity";
+    }
+
+    Object monitor = new Object();
+    boolean testPassed = false;
+    String svName = null;
+    String mainName = null;
+
+    SurfaceTraceReceiver.SurfaceObserver observer = new SurfaceTraceReceiver.SurfaceObserver() {
+        int transactionCount = 0;
+        boolean sawSVMove = false;
+        boolean sawMainMove = false;
+        int timesSeen = 0;
+
+        @Override
+        public void openTransaction() {
+            transactionCount++;
+            sawSVMove = false;
+            sawMainMove = false;
+        }
+
+        @Override
+        public void closeTransaction() {
+            transactionCount--;
+            if (transactionCount != 0) {
+                return;
+            }
+            synchronized (monitor) {
+                if (sawSVMove ^ sawMainMove ) {
+                    monitor.notifyAll();
+                    return;
+                }
+                if (timesSeen > 10) {
+                    testPassed = true;
+                    monitor.notifyAll();
+                }
+            }
+        }
+
+        @Override
+        public void setPosition(String windowName, float x, float y) {
+            if (windowName.equals(svName)) {
+                sawSVMove = true;
+                timesSeen++;
+            } else if (windowName.equals(mainName)) {
+                sawMainMove = true;
+            }
+        }
+    };
+
+    /**
+     * Here we test that a SurfaceView moves in the same transaction
+     * as its parent. We launch an activity with a SurfaceView which will
+     * move around its own main window. Then we listen to WindowManager transactions.
+     * Since the SurfaceView is static within the window, if we ever see one of
+     * them move xor the other one we have a problem!
+     */
+    public void testSurfaceMovesWithParent() throws Exception {
+        doFullscreenTest("MovesWithParent",
+            (WindowState parent, WindowState sv) -> {
+                    svName = sv.getName();
+                    mainName = parent.getName();
+                    installSurfaceObserver(observer);
+                    try {
+                        synchronized (monitor) {
+                            monitor.wait(5000);
+                        }
+                    } catch (InterruptedException e) {
+                    } finally {
+                        assertTrue(testPassed);
+                        removeSurfaceObserver();
+                    }
+            });
+    }
+}
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..651abe3
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/SurfaceViewTests.java
@@ -0,0 +1,94 @@
+/*
+ * 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.log.LogUtil.CLog;
+
+import android.server.cts.WindowManagerState.WindowState;
+
+public class SurfaceViewTests extends ParentChildTestBase {
+    private List<WindowState> mWindowList = new ArrayList();
+
+    @Override
+    String intentKey() {
+        return "android.server.FrameTestApp.SurfaceViewTestCase";
+    }
+
+    @Override
+    String activityName() {
+        return "SurfaceViewTestActivity";
+    }
+
+    WindowState getSingleWindow(String fullWindowName) {
+        try {
+            mAmWmState.getWmState().getMatchingVisibleWindowState(fullWindowName, mWindowList);
+            return mWindowList.get(0);
+        } catch (Exception e) {
+            CLog.logAndDisplay(LogLevel.INFO, "Couldn't find window: " + fullWindowName);
+            return null;
+        }
+    }
+
+    void doSingleTest(ParentChildTest t) throws Exception {
+        String svName = "SurfaceView - " + getBaseWindowName() + activityName();
+        final String[] waitForVisible = new String[] { svName };
+
+        mAmWmState.setUseActivityNamesForWindowNames(false);
+        mAmWmState.computeState(mDevice, waitForVisible);
+        WindowState sv = getSingleWindow(svName);
+        WindowState parent = getSingleWindow(getBaseWindowName() + activityName());
+
+        t.doTest(parent, sv);
+    }
+
+    public void testSurfaceViewOnBottom() throws Exception {
+        doParentChildTest("OnBottom",
+            (WindowState parent, WindowState sv) -> {
+                assertFalse(sv.getLayer() >= parent.getLayer());
+            });
+    }
+
+    public void testSurfaceViewOnTop() throws Exception {
+        doParentChildTest("OnTop",
+            (WindowState parent, WindowState sv) -> {
+                assertFalse(parent.getLayer() >= sv.getLayer());
+            });
+    }
+
+    public void testSurfaceViewOversized() throws Exception {
+        final int oversizedDimension = 8000;
+        doParentChildTest("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/hostsidetests/services/activitymanager/Android.mk b/hostsidetests/services/activitymanager/Android.mk
deleted file mode 100644
index 51a6ed4..0000000
--- a/hostsidetests/services/activitymanager/Android.mk
+++ /dev/null
@@ -1,36 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Must match the package name in CtsTestCaseList.mk
-LOCAL_MODULE := CtsServicesHostTestCases
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_CTS_TEST_PACKAGE := android.server
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
deleted file mode 100755
index bb1f8f3..0000000
--- a/hostsidetests/services/activitymanager/app/AndroidManifest.xml
+++ /dev/null
@@ -1,177 +0,0 @@
-<?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.app">
-
-    <application>
-        <activity android:name=".TestActivity"
-                android:resizeableActivity="true"
-                android:exported="true"
-        />
-        <activity android:name=".ResizeableActivity"
-                android:resizeableActivity="true"
-                android:exported="true"
-                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-        />
-        <activity android:name=".NonResizeableActivity"
-                android:resizeableActivity="false"
-                android:exported="true"
-        />
-        <activity android:name=".DockedActivity"
-                android:resizeableActivity="true"
-                android:exported="true"
-                android:taskAffinity="nobody.but.DockedActivity"
-        />
-        <activity android:name=".TranslucentActivity"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar"
-            android:resizeableActivity="true"
-            android:taskAffinity="nobody.but.TranslucentActivity"
-            android:exported="true"
-        />
-        <activity android:name=".NoRelaunchActivity"
-                android:resizeableActivity="true"
-                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|fontScale"
-                android:exported="true"
-                android:taskAffinity="nobody.but.NoRelaunchActivity"
-        />
-        <activity android:name=".SlowCreateActivity"
-                android:resizeableActivity="true"
-                android:exported="true"
-        />
-        <activity android:name=".LaunchingActivity"
-                android:resizeableActivity="true"
-                android:exported="true"
-                android:taskAffinity="nobody.but.LaunchToSideActivity"
-        />
-        <activity android:name=".PipActivity"
-                android:resizeableActivity="true"
-                android:supportsPictureInPicture="true"
-                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                android:exported="true"
-        />
-        <activity android:name=".AutoEnterPipActivity"
-                  android:resizeableActivity="true"
-                  android:supportsPictureInPicture="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true"
-        />
-        <activity android:name=".AlwaysFocusablePipActivity"
-                  android:theme="@style/Theme.Transparent"
-                  android:resizeableActivity="true"
-                  android:supportsPictureInPicture="true"
-                  androidprv:alwaysFocusable="true"
-                  android:exported="true"
-                  android:taskAffinity="nobody.but.AlwaysFocusablePipActivity"
-        />
-        <activity android:name=".LaunchIntoPinnedStackPipActivity"
-                  android:resizeableActivity="true"
-                  android:supportsPictureInPicture="true"
-                  androidprv:alwaysFocusable="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true"
-        />
-        <activity android:name=".VisibleBehindActivity"
-                  android:resizeableActivity="true"
-                  android:supportsPictureInPicture="true"
-                  android:exported="true"
-                  android:taskAffinity="nobody.but.VisibleBehindActivity"
-        />
-        <activity android:name=".LaunchPipOnPipActivity"
-                  android:resizeableActivity="true"
-                  android:supportsPictureInPicture="true"
-                  android:taskAffinity="nobody.but.LaunchPipOnPipActivity"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true"
-        />
-        <activity android:name=".FreeformActivity"
-                  android:resizeableActivity="true"
-                  android:taskAffinity="nobody.but.FreeformActivity"
-                  android:exported="true"
-        />
-        <activity android:name=".TopLeftLayoutActivity"
-                  android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true">
-                  <layout android:defaultWidth="240dp"
-                          android:defaultHeight="160dp"
-                          android:gravity="top|left"
-                          android:minWidth="100dp"
-                          android:minHeight="80dp"
-                  />
-        </activity>
-        <activity android:name=".TopRightLayoutActivity"
-                  android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true">
-                  <layout android:defaultWidth="25%"
-                          android:defaultHeight="35%"
-                          android:gravity="top|right"
-                          android:minWidth="100dp"
-                          android:minHeight="80dp"
-                  />
-        </activity>
-        <activity android:name=".BottomLeftLayoutActivity"
-                  android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true">
-                  <layout android:defaultWidth="25%"
-                          android:defaultHeight="35%"
-                          android:gravity="bottom|left"
-                          android:minWidth="100dp"
-                          android:minHeight="80dp"
-                  />
-        </activity>
-        <activity android:name=".BottomRightLayoutActivity"
-                  android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
-                  android:exported="true">
-                  <layout android:defaultWidth="240dp"
-                          android:defaultHeight="160dp"
-                          android:gravity="bottom|right"
-                          android:minWidth="100dp"
-                          android:minHeight="80dp"
-                  />
-        </activity>
-        <activity android:name=".TurnScreenOnActivity"
-                  android:exported="true"
-        />
-        <activity android:name=".SingleTaskActivity"
-            android:exported="true"
-            android:launchMode="singleTask"
-        />
-        <activity android:name=".SingleInstanceActivity"
-            android:exported="true"
-            android:launchMode="singleInstance"
-        />
-        <activity android:name=".TrampolineActivity"
-                  android:exported="true"
-                  android:theme="@android:style/Theme.NoDisplay"
-        />
-        <activity android:name=".BroadcastReceiverActivity"
-                  android:resizeableActivity="true"
-                  android:exported="true"
-        />
-        <activity-alias android:enabled="true"
-                android:exported="true"
-                android:name=".EntryPointAliasActivity"
-                android:targetActivity=".TrampolineActivity" >
-        </activity-alias>
-    </application>
-</manifest>
-
diff --git a/hostsidetests/services/activitymanager/app/res/values/styles.xml b/hostsidetests/services/activitymanager/app/res/values/styles.xml
deleted file mode 100644
index 59ebad2..0000000
--- a/hostsidetests/services/activitymanager/app/res/values/styles.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<resources>
-    <style name="Theme.Transparent" parent="android:Theme">
-        <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowBackground">@android:color/transparent</item>
-        <item name="android:windowNoTitle">true</item>
-    </style>
-</resources>
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.java
deleted file mode 100644
index 8abb1c5..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AbstractLifecycleLogActivity.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.server.app;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.WindowManager;
-
-public abstract class AbstractLifecycleLogActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        Log.i(getTag(), "onCreate");
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        Log.i(getTag(), "onConfigurationChanged");
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        Log.i(getTag(), "onDestroy");
-    }
-
-    protected abstract String getTag();
-
-    protected void dumpDisplaySize(Configuration config) {
-        // Dump the display size as seen by this Activity.
-        final WindowManager wm = getSystemService(WindowManager.class);
-        final Display display = wm.getDefaultDisplay();
-        final Point point = new Point();
-        display.getSize(point);
-        final DisplayMetrics metrics = getResources().getDisplayMetrics();
-
-        final String line = "config" +
-                " size=" + buildCoordString(config.screenWidthDp, config.screenHeightDp) +
-                " displaySize=" + buildCoordString(point.x, point.y) +
-                " metricsSize=" + buildCoordString(metrics.widthPixels, metrics.heightPixels) +
-                " smallestScreenWidth=" + config.smallestScreenWidthDp;
-
-        Log.i(getTag(), line);
-    }
-
-    protected static String buildCoordString(int x, int y) {
-        return "(" + x + "," + y + ")";
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java
deleted file mode 100644
index b5c736d..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AlwaysFocusablePipActivity.java
+++ /dev/null
@@ -1,38 +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.server.app;
-
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.graphics.Rect;
-
-public class AlwaysFocusablePipActivity extends Activity {
-
-    static void launchAlwaysFocusablePipActivity(Activity caller) {
-        final Intent intent = new Intent(caller, AlwaysFocusablePipActivity.class);
-        intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
-
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchBounds(new Rect(0, 0, 500, 500));
-        options.setLaunchStackId(4 /* ActivityManager.StackId.PINNED_STACK_ID */);
-        caller.startActivity(intent, options.toBundle());
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
deleted file mode 100644
index 97bc041..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
+++ /dev/null
@@ -1,27 +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 android.server.app;
-
-import android.app.Activity;
-
-public class AutoEnterPipActivity extends Activity {
-    @Override
-    protected void onResume() {
-        super.onResume();
-        enterPictureInPictureMode();
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
deleted file mode 100644
index 27a6fe2..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomLeftLayoutActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class BottomLeftLayoutActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java
deleted file mode 100644
index 7a91510..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BottomRightLayoutActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class BottomRightLayoutActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/BroadcastReceiverActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/BroadcastReceiverActivity.java
deleted file mode 100644
index d55fea0..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/BroadcastReceiverActivity.java
+++ /dev/null
@@ -1,63 +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.server.app;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-
-/**
- * Activity that registers broadcast receiver .
- */
-public class BroadcastReceiverActivity extends Activity {
-
-    public static final String ACTION_TRIGGER_BROADCAST = "trigger_broadcast";
-
-    private TestBroadcastReceiver mBroadcastReceiver = new TestBroadcastReceiver();
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        IntentFilter broadcastFilter = new IntentFilter(ACTION_TRIGGER_BROADCAST);
-
-        registerReceiver(mBroadcastReceiver, broadcastFilter);
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-
-        unregisterReceiver(mBroadcastReceiver);
-    }
-
-    public class TestBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final Bundle extras = intent.getExtras();
-            if (extras == null) {
-                return;
-            }
-            if (extras.getBoolean("finish")) {
-                finish();
-            }
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java
deleted file mode 100644
index 427fd29..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/DockedActivity.java
+++ /dev/null
@@ -1,22 +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 android.server.app;
-
-import android.app.Activity;
-
-public class DockedActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java
deleted file mode 100644
index 6daf3d98..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/FreeformActivity.java
+++ /dev/null
@@ -1,39 +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.server.app;
-
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.graphics.Rect;
-
-public class FreeformActivity extends Activity {
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        final Intent intent = new Intent(this, TestActivity.class);
-        intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
-
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchBounds(new Rect(0, 0, 900, 900));
-        this.startActivity(intent, options.toBundle());
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java
deleted file mode 100644
index 45386bf..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchIntoPinnedStackPipActivity.java
+++ /dev/null
@@ -1,27 +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.server.app;
-
-import android.app.Activity;
-
-public class LaunchIntoPinnedStackPipActivity extends Activity {
-    @Override
-    protected void onResume() {
-        super.onResume();
-        AlwaysFocusablePipActivity.launchAlwaysFocusablePipActivity(this);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
deleted file mode 100644
index d7b4cc1..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
+++ /dev/null
@@ -1,27 +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.server.app;
-
-import android.app.Activity;
-
-public class LaunchPipOnPipActivity extends Activity {
-    @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
-        AlwaysFocusablePipActivity.launchAlwaysFocusablePipActivity(this);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchingActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchingActivity.java
deleted file mode 100644
index 83ebf09..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchingActivity.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package android.server.app;
-
-import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.net.Uri;
-import android.os.Bundle;
-
-/**
- * Activity that launches another activities when new intent is received.
- */
-public class LaunchingActivity extends Activity {
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        final Bundle extras = intent.getExtras();
-        if (extras == null) {
-            return;
-        }
-
-        Intent newIntent = new Intent();
-        String targetActivity = extras.getString("target_activity");
-        if (targetActivity != null) {
-            String packageName = getApplicationContext().getPackageName();
-            newIntent.setComponent(new ComponentName(packageName,
-                    packageName + "." + targetActivity));
-        } else {
-            newIntent.setClass(this, TestActivity.class);
-        }
-
-        if (extras.getBoolean("launch_to_the_side")) {
-            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_ADJACENT);
-            if (extras.getBoolean("multiple_task")) {
-                newIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
-            }
-            if (extras.getBoolean("random_data")) {
-                Uri data = new Uri.Builder()
-                        .path(String.valueOf(System.currentTimeMillis()))
-                        .build();
-                newIntent.setData(data);
-            }
-        } else {
-            // We're all set, just launch.
-        }
-
-        startActivity(newIntent);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java
deleted file mode 100644
index 0058c13..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/NoRelaunchActivity.java
+++ /dev/null
@@ -1,27 +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.server.app;
-
-public class NoRelaunchActivity extends AbstractLifecycleLogActivity {
-
-    private static final String TAG = NoRelaunchActivity.class.getSimpleName();
-
-    @Override
-    protected String getTag() {
-        return TAG;
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
deleted file mode 100644
index 6312b47..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/NonResizeableActivity.java
+++ /dev/null
@@ -1,27 +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.server.app;
-
-public class NonResizeableActivity extends AbstractLifecycleLogActivity {
-
-     private static final String TAG = NonResizeableActivity.class.getSimpleName();
-
-    @Override
-    protected String getTag() {
-        return TAG;
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
deleted file mode 100644
index b750389..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
+++ /dev/null
@@ -1,22 +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 android.server.app;
-
-import android.app.Activity;
-
-public class PipActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java
deleted file mode 100644
index 4d46a83..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/ResizeableActivity.java
+++ /dev/null
@@ -1,38 +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.server.app;
-
-import android.content.res.Configuration;
-import android.os.Bundle;
-
-public class ResizeableActivity extends AbstractLifecycleLogActivity {
-    @Override
-    protected String getTag() {
-        return "ResizeableActivity";
-    }
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        dumpDisplaySize(getResources().getConfiguration());
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        dumpDisplaySize(newConfig);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java
deleted file mode 100644
index b745adc..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleInstanceActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class SingleInstanceActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java
deleted file mode 100644
index 0a99ea3..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SingleTaskActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class SingleTaskActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
deleted file mode 100644
index 481f5be..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/SlowCreateActivity.java
+++ /dev/null
@@ -1,30 +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.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);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
deleted file mode 100644
index f469a1c..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
+++ /dev/null
@@ -1,41 +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 android.server.app;
-
-import android.content.res.Configuration;
-
-public class TestActivity extends AbstractLifecycleLogActivity {
-
-    private static final String TAG = TestActivity.class.getSimpleName();
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        dumpDisplaySize(getResources().getConfiguration());
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        dumpDisplaySize(newConfig);
-    }
-
-    @Override
-    protected String getTag() {
-        return TAG;
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java
deleted file mode 100644
index 3a0267b..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TopLeftLayoutActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class TopLeftLayoutActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java
deleted file mode 100644
index eb3b1b0..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TopRightLayoutActivity.java
+++ /dev/null
@@ -1,22 +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.server.app;
-
-import android.app.Activity;
-
-public class TopRightLayoutActivity extends Activity {
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java
deleted file mode 100644
index 4b80482..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TrampolineActivity.java
+++ /dev/null
@@ -1,50 +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.server.app;
-
-import android.os.Bundle;
-
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
-import android.content.Intent;
-
-public class TrampolineActivity extends AbstractLifecycleLogActivity {
-
-    private static final String TAG = TrampolineActivity.class.getSimpleName();
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        // Add a delay here to expose more easily a failure case where the real target
-        // activity is visible before it's launched, because its task is being brought
-        // to foreground. We need to verify that 'am start' is unblocked correctly.
-        try {
-            Thread.sleep(2000);
-        } catch(InterruptedException e) {}
-        Intent intent = new Intent(this, SingleTaskActivity.class);
-        intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK);
-
-        startActivity(intent);
-        finish();
-    }
-
-    @Override
-    protected String getTag() {
-        return TAG;
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java
deleted file mode 100644
index 800080e..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TranslucentActivity.java
+++ /dev/null
@@ -1,23 +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.server.app;
-
-import android.app.Activity;
-
-public class TranslucentActivity extends Activity {
-
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java
deleted file mode 100644
index 838a1d6..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/TurnScreenOnActivity.java
+++ /dev/null
@@ -1,32 +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.server.app;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public class TurnScreenOnActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
-                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
-                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
-                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
-        super.onCreate(savedInstanceState);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java
deleted file mode 100644
index cc8f273..0000000
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/VisibleBehindActivity.java
+++ /dev/null
@@ -1,31 +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.server.app;
-
-import android.app.Activity;
-import android.util.Log;
-
-public class VisibleBehindActivity extends Activity {
-    private static final String TAG = "VisibleBehindActivity";
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (requestVisibleBehind(true)) {
-            Log.e(TAG, "Failed to request visibility behind...");
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java b/hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
deleted file mode 100644
index b3f8c39..0000000
--- a/hostsidetests/services/activitymanager/appDisplaySize/src/android/displaysize/app/SmallestWidthActivity.java
+++ /dev/null
@@ -1,38 +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.displaysize.app;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class SmallestWidthActivity extends Activity {
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-
-        final Bundle extras = intent.getExtras();
-        if (extras != null && extras.getBoolean("launch_another_activity")) {
-            Intent startIntent = new Intent();
-            startIntent.setComponent(
-                    new ComponentName("android.server.app", "android.server.app.TestActivity"));
-            startActivity(startIntent);
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
deleted file mode 100644
index bb7f521..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
+++ /dev/null
@@ -1,500 +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.server.cts;
-
-import com.android.tradefed.device.ITestDevice;
-
-import junit.framework.Assert;
-
-import android.server.cts.ActivityManagerState.ActivityStack;
-import android.server.cts.ActivityManagerState.ActivityTask;
-import android.server.cts.WindowManagerState.WindowStack;
-import android.server.cts.WindowManagerState.WindowTask;
-
-import java.awt.Rectangle;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import static android.server.cts.ActivityManagerTestBase.FREEFORM_WORKSPACE_STACK_ID;
-import static android.server.cts.ActivityManagerTestBase.PINNED_STACK_ID;
-import static android.server.cts.StateLogger.log;
-
-/** Combined state of the activity manager and window manager. */
-class ActivityAndWindowManagersState extends Assert {
-
-    // Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
-    // (Needed in host-side tests to convert dp to px.)
-    private static final int DISPLAY_DENSITY_DEFAULT = 160;
-
-    // Default minimal size of resizable task, used if none is set explicitly.
-    // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
-    private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220;
-
-    private ActivityManagerState mAmState = new ActivityManagerState();
-    private WindowManagerState mWmState = new WindowManagerState();
-
-    private final List<WindowManagerState.WindowState> mTempWindowList = new ArrayList<>();
-
-    /**
-     * Compute AM and WM state of device, check sanity and bounds.
-     * WM state will include only visible windows, stack and task bounds will be compared.
-     *
-     * @param device test device.
-     * @param waitForActivitiesVisible array of activity names to wait for.
-     */
-    void computeState(ITestDevice device, String[] waitForActivitiesVisible) throws Exception {
-        computeState(device, waitForActivitiesVisible, true);
-    }
-
-    /**
-     * Compute AM and WM state of device, check sanity and bounds.
-     * WM state will include only visible windows.
-     *
-     * @param device test device.
-     * @param waitForActivitiesVisible array of activity names to wait for.
-     * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
-     *                                  'false' otherwise.
-     */
-    void computeState(ITestDevice device, String[] waitForActivitiesVisible,
-                      boolean compareTaskAndStackBounds) throws Exception {
-        computeState(device, true, waitForActivitiesVisible, compareTaskAndStackBounds);
-    }
-
-    /**
-     * Compute AM and WM state of device, check sanity and bounds.
-     * Stack and task bounds will be compared.
-     *
-     * @param device test device.
-     * @param visibleOnly pass 'true' to include only visible windows in WM state.
-     * @param waitForActivitiesVisible array of activity names to wait for.
-     */
-    void computeState(ITestDevice device, boolean visibleOnly, String[] waitForActivitiesVisible)
-            throws Exception {
-        computeState(device, visibleOnly, waitForActivitiesVisible, true);
-    }
-
-    /**
-     * Compute AM and WM state of device, check sanity and bounds.
-     *
-     * @param device test device.
-     * @param visibleOnly pass 'true' if WM state should include only visible windows.
-     * @param waitForActivitiesVisible array of activity names to wait for.
-     * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
-     *                                  'false' otherwise.
-     */
-    void computeState(ITestDevice device, boolean visibleOnly, String[] waitForActivitiesVisible,
-                      boolean compareTaskAndStackBounds) throws Exception {
-        waitForValidState(device, visibleOnly, waitForActivitiesVisible, null,
-                compareTaskAndStackBounds);
-
-        assertSanity();
-        assertValidBounds(compareTaskAndStackBounds);
-    }
-
-    /**
-     * Wait for consistent state in AM and WM.
-     *
-     * @param device test device.
-     * @param visibleOnly pass 'true' if WM state should include only visible windows.
-     * @param waitForActivitiesVisible array of activity names to wait for.
-     * @param stackIds ids of stack where provided activities should be found.
-     *                 Pass null to skip this check.
-     */
-    void waitForValidState(ITestDevice device, boolean visibleOnly,
-                           String[] waitForActivitiesVisible, int[] stackIds,
-                           boolean compareTaskAndStackBounds) throws Exception {
-        int retriesLeft = 5;
-        do {
-            // TODO: Get state of AM and WM at the same time to avoid mismatches caused by
-            // requesting dump in some intermediate state.
-            mAmState.computeState(device);
-            mWmState.computeState(device, visibleOnly);
-            if (shouldWaitForValidStacks(compareTaskAndStackBounds)
-                    || shouldWaitForActivities(waitForActivitiesVisible, stackIds)) {
-                log("***Waiting for valid stacks and activities states...");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                    log(e.toString());
-                    // Well I guess we are not waiting...
-                }
-            } else {
-                break;
-            }
-        } while (retriesLeft-- > 0);
-    }
-
-    void waitForHomeActivityVisible(ITestDevice device) throws Exception {
-        int retriesLeft = 5;
-        do {
-            mAmState.computeState(device);
-            if (!mAmState.isHomeActivityVisible()) {
-                log("***Waiting for home activity to be visible...");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                    log(e.toString());
-                    // Well I guess we are not waiting...
-                }
-            } else {
-                break;
-            }
-        } while (retriesLeft-- > 0);
-    }
-
-    private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
-        if (!taskListsInAmAndWmAreEqual()) {
-            // We want to wait for equal task lists in AM and WM in case we caught them in the
-            // middle of some state change operations.
-            log("***taskListsInAmAndWmAreEqual=false");
-            return true;
-        }
-        if (!stackBoundsInAMAndWMAreEqual()) {
-            // We want to wait a little for the stacks in AM and WM to have equal bounds as there
-            // might be a transition animation ongoing when we got the states from WM AM separately.
-            log("***stackBoundsInAMAndWMAreEqual=false");
-            return true;
-        }
-        try {
-            // Temporary fix to avoid catching intermediate state with different task bounds in AM
-            // and WM.
-            assertValidBounds(compareTaskAndStackBounds);
-        } catch (AssertionError e) {
-            log("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
-            return true;
-        }
-        return false;
-    }
-
-    private boolean shouldWaitForActivities(String[] waitForActivitiesVisible, int[] stackIds) {
-        if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
-            return false;
-        }
-        // If the caller is interested in us waiting for some particular activity windows to be
-        // visible before compute the state. Check for the visibility of those activity windows
-        // and for placing them in correct stacks (if requested).
-        boolean allActivityWindowsVisible = true;
-        boolean tasksInCorrectStacks = true;
-        List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
-        for (int i = 0; i < waitForActivitiesVisible.length; i++) {
-            // Check if window is visible - it should be represented as one of the window states.
-            final String windowName =
-                    ActivityManagerTestBase.getWindowName(waitForActivitiesVisible[i]);
-            mWmState.getMatchingWindowState(windowName, matchingWindowStates);
-            boolean activityWindowVisible = !matchingWindowStates.isEmpty();
-            if (!activityWindowVisible) {
-                log("Activity window not visible: " + waitForActivitiesVisible[i]);
-                allActivityWindowsVisible = false;
-            } else if (stackIds != null) {
-                // Check if window is already in stack requested by test.
-                boolean windowInCorrectStack = false;
-                for (WindowManagerState.WindowState ws : matchingWindowStates) {
-                    if (ws.getStackId() == stackIds[i]) {
-                        windowInCorrectStack = true;
-                        break;
-                    }
-                }
-                if (!windowInCorrectStack) {
-                    log("Window in incorrect stack: " + waitForActivitiesVisible[i]);
-                    tasksInCorrectStacks = false;
-                }
-            }
-        }
-        return !allActivityWindowsVisible || !tasksInCorrectStacks;
-    }
-
-    ActivityManagerState getAmState() {
-        return mAmState;
-    }
-
-    WindowManagerState getWmState() {
-        return mWmState;
-    }
-
-    void assertSanity() throws Exception {
-        assertTrue("Must have stacks", mAmState.getStackCount() > 0);
-        assertEquals("There should be one and only one resumed activity in the system.",
-                1, mAmState.getResumedActivitiesCount());
-        assertNotNull("Must have focus activity.", mAmState.getFocusedActivity());
-
-        for (ActivityStack aStack : mAmState.getStacks()) {
-            final int stackId = aStack.mStackId;
-            for (ActivityTask aTask : aStack.getTasks()) {
-                assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId);
-            }
-        }
-
-        assertNotNull("Must have front window.", mWmState.getFrontWindow());
-        assertNotNull("Must have focused window.", mWmState.getFocusedWindow());
-        assertNotNull("Must have app.", mWmState.getFocusedApp());
-    }
-
-    void assertContainsStack(String msg, int stackId) throws Exception {
-        assertTrue(msg, mAmState.containsStack(stackId));
-        assertTrue(msg, mWmState.containsStack(stackId));
-    }
-
-    void assertDoesNotContainStack(String msg, int stackId) throws Exception {
-        assertFalse(msg, mAmState.containsStack(stackId));
-        assertFalse(msg, mWmState.containsStack(stackId));
-    }
-
-    void assertFrontStack(String msg, int stackId) throws Exception {
-        assertEquals(msg, stackId, mAmState.getFrontStackId());
-        assertEquals(msg, stackId, mWmState.getFrontStackId());
-    }
-
-    void assertFocusedStack(String msg, int stackId) throws Exception {
-        assertEquals(msg, stackId, mAmState.getFocusedStackId());
-    }
-
-    void assertNotFocusedStack(String msg, int stackId) throws Exception {
-        if (stackId == mAmState.getFocusedStackId()) {
-            failNotEquals(msg, stackId, mAmState.getFocusedStackId());
-        }
-    }
-
-    void assertFocusedActivity(String msg, String activityName) throws Exception {
-        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
-        assertEquals(msg, componentName, mAmState.getFocusedActivity());
-        assertEquals(msg, componentName, mWmState.getFocusedApp());
-    }
-
-    void assertNotFocusedActivity(String msg, String activityName) throws Exception {
-        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
-        if (mAmState.getFocusedActivity().equals(componentName)) {
-            failNotEquals(msg, mAmState.getFocusedActivity(), componentName);
-        }
-        if (mWmState.getFocusedApp().equals(componentName)) {
-            failNotEquals(msg, mWmState.getFocusedApp(), componentName);
-        }
-    }
-
-    void assertResumedActivity(String msg, String activityName) throws Exception {
-        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
-        assertEquals(msg, componentName, mAmState.getResumedActivity());
-    }
-
-    void assertNotResumedActivity(String msg, String activityName) throws Exception {
-        final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
-        if (mAmState.getResumedActivity().equals(componentName)) {
-            failNotEquals(msg, mAmState.getResumedActivity(), componentName);
-        }
-    }
-
-    void assertFocusedWindow(String msg, String windowName) {
-        assertEquals(msg, windowName, mWmState.getFocusedWindow());
-    }
-
-    void assertNotFocusedWindow(String msg, String windowName) {
-        if (mWmState.getFocusedWindow().equals(windowName)) {
-            failNotEquals(msg, mWmState.getFocusedWindow(), windowName);
-        }
-    }
-
-    void assertFrontWindow(String msg, String windowName) {
-        assertEquals(msg, windowName, mWmState.getFrontWindow());
-    }
-
-    void assertVisibility(String activityName, boolean visible) {
-        final String activityComponentName =
-                ActivityManagerTestBase.getActivityComponentName(activityName);
-        final String windowName =
-                ActivityManagerTestBase.getWindowName(activityName);
-
-        final boolean activityVisible = mAmState.isActivityVisible(activityComponentName);
-        final boolean windowVisible = mWmState.isWindowVisible(windowName);
-
-        if (visible) {
-            assertTrue("Activity=" + activityComponentName + " must be visible.", activityVisible);
-            assertTrue("Window=" + windowName + " must be visible.", windowVisible);
-        } else {
-            assertFalse("Activity=" + activityComponentName + " must NOT be visible.",
-                    activityVisible);
-            assertFalse("Window=" + windowName + " must NOT be visible.", windowVisible);
-        }
-    }
-
-    void assertHomeActivityVisible(boolean visible) {
-        final boolean activityVisible = mAmState.isHomeActivityVisible();
-
-        if (visible) {
-            assertTrue("Home activity must be visible.", activityVisible);
-        } else {
-            assertFalse("Home activity must NOT be visible.", activityVisible);
-        }
-    }
-
-    boolean taskListsInAmAndWmAreEqual() {
-        for (ActivityStack aStack : mAmState.getStacks()) {
-            final int stackId = aStack.mStackId;
-            final WindowStack wStack = mWmState.getStack(stackId);
-            if (wStack == null) {
-                log("Waiting for stack setup in WM, stackId=" + stackId);
-                return false;
-            }
-
-            for (ActivityTask aTask : aStack.getTasks()) {
-                if (wStack.getTask(aTask.mTaskId) == null) {
-                    log("Task is in AM but not in WM, waiting for it to settle, taskId="
-                            + aTask.mTaskId);
-                    return false;
-                }
-            }
-
-            for (WindowTask wTask : wStack.mTasks) {
-                if (aStack.getTask(wTask.mTaskId) == null) {
-                    log("Task is in WM but not in AM, waiting for it to settle, taskId="
-                            + wTask.mTaskId);
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    boolean stackBoundsInAMAndWMAreEqual() {
-        for (ActivityStack aStack : mAmState.getStacks()) {
-            final int stackId = aStack.mStackId;
-            final WindowStack wStack = mWmState.getStack(stackId);
-            if (aStack.isFullscreen() != wStack.isFullscreen()) {
-                log("Waiting for correct fullscreen state, stackId=" + stackId);
-                return false;
-            }
-
-            final Rectangle aStackBounds = aStack.getBounds();
-            final Rectangle wStackBounds = wStack.getBounds();
-
-            if (aStack.isFullscreen()) {
-                if (aStackBounds != null) {
-                    log("Waiting for correct stack state in AM, stackId=" + stackId);
-                    return false;
-                }
-            } else if (!Objects.equals(aStackBounds, wStackBounds)) {
-                // If stack is not fullscreen - comparing bounds. Not doing it always because
-                // for fullscreen stack bounds in WM can be either null or equal to display size.
-                log("Waiting for stack bound equality in AM and WM, stackId=" + stackId);
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /** Check task bounds when docked to top/left. */
-    void assertDockedTaskBounds(int taskSize, String activityName) {
-        // Task size can be affected by default minimal size.
-        int defaultMinimalTaskSize = defaultMinimalTaskSize(
-                mAmState.getStackById(ActivityManagerTestBase.DOCKED_STACK_ID).mDisplayId);
-        int targetSize = Math.max(taskSize, defaultMinimalTaskSize);
-
-        assertEquals(new Rectangle(0, 0, targetSize, targetSize),
-                mAmState.getTaskByActivityName(activityName).getBounds());
-    }
-
-    void assertValidBounds(boolean compareTaskAndStackBounds) {
-        for (ActivityStack aStack : mAmState.getStacks()) {
-            final int stackId = aStack.mStackId;
-            final WindowStack wStack = mWmState.getStack(stackId);
-            assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack);
-
-            assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId,
-                    aStack.isFullscreen(), wStack.isFullscreen());
-
-            final Rectangle aStackBounds = aStack.getBounds();
-            final Rectangle wStackBounds = wStack.getBounds();
-
-            if (aStack.isFullscreen()) {
-                assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds);
-            } else {
-                assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId,
-                        aStackBounds, wStackBounds);
-            }
-
-            for (ActivityTask aTask : aStack.getTasks()) {
-                final int taskId = aTask.mTaskId;
-                final WindowTask wTask = wStack.getTask(taskId);
-                assertNotNull(
-                        "taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask);
-
-                final boolean aTaskIsFullscreen = aTask.isFullscreen();
-                final boolean wTaskIsFullscreen = wTask.isFullscreen();
-                assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId
-                        + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
-
-                final Rectangle aTaskBounds = aTask.getBounds();
-                final Rectangle wTaskBounds = wTask.getBounds();
-
-                if (aTaskIsFullscreen) {
-                    assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
-                            aTaskBounds);
-                } else {
-                    assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
-                            + ", stackId=" + stackId, aTaskBounds, wTaskBounds);
-
-                    if (compareTaskAndStackBounds && stackId != FREEFORM_WORKSPACE_STACK_ID) {
-                        int aTaskMinWidth = aTask.getMinWidth();
-                        int aTaskMinHeight = aTask.getMinHeight();
-
-                        if (aTaskMinWidth == -1 || aTaskMinHeight == -1) {
-                            // Minimal dimension(s) not set for task - it should be using defaults.
-                            int defaultMinimalSize = defaultMinimalTaskSize(aStack.mDisplayId);
-
-                            if (aTaskMinWidth == -1) {
-                                aTaskMinWidth = defaultMinimalSize;
-                            }
-                            if (aTaskMinHeight == -1) {
-                                aTaskMinHeight = defaultMinimalSize;
-                            }
-                        }
-
-                        if (aStackBounds.getWidth() >= aTaskMinWidth
-                                && aStackBounds.getHeight() >= aTaskMinHeight
-                                || stackId == PINNED_STACK_ID) {
-                            // Bounds are not smaller then minimal possible, so stack and task
-                            // bounds must be equal.
-                            assertEquals("Task bounds must be equal to stack bounds taskId="
-                                    + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
-                        } else {
-                            // Minimal dimensions affect task size, so bounds of task and stack must
-                            // be different - will compare dimensions instead.
-                            int targetWidth = (int) Math.max(aTaskMinWidth,
-                                    aStackBounds.getWidth());
-                            assertEquals("Task width must be set according to minimal width"
-                                            + " taskId=" + taskId + ", stackId=" + stackId,
-                                    targetWidth, (int) wTaskBounds.getWidth());
-                            int targetHeight = (int) Math.max(aTaskMinHeight,
-                                    aStackBounds.getHeight());
-                            assertEquals("Task height must be set according to minimal height"
-                                            + " taskId=" + taskId + ", stackId=" + stackId,
-                                    targetHeight, (int) wTaskBounds.getHeight());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    static int dpToPx(float dp, int densityDpi){
-        return (int) (dp * densityDpi / DISPLAY_DENSITY_DEFAULT + 0.5f);
-    }
-
-    int defaultMinimalTaskSize(int displayId) {
-        return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
deleted file mode 100644
index 5aafe8e..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerActivityVisiblityTests.java
+++ /dev/null
@@ -1,180 +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.server.cts;
-
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.lang.Exception;
-import java.lang.String;
-
-public class ActivityManagerActivityVisiblityTests extends ActivityManagerTestBase {
-    private static final String TRANSLUCENT_ACTIVITY = "AlwaysFocusablePipActivity";
-    private static final String VISIBLE_BEHIND_ACTIVITY = "VisibleBehindActivity";
-    private static final String PIP_ON_PIP_ACTIVITY = "LaunchPipOnPipActivity";
-    private static final String TEST_ACTIVITY_NAME = "TestActivity";
-    private static final String TRANSLUCENT_ACTIVITY_NAME = "TranslucentActivity";
-    private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
-    private static final String TURN_SCREEN_ON_ACTIVITY_NAME = "TurnScreenOnActivity";
-    private static final String BROADCAST_RECEIVER_ACTIVITY = "BroadcastReceiverActivity";
-
-    public void testVisibleBehindHomeActivity() throws Exception {
-        executeShellCommand(getAmStartCmd(VISIBLE_BEHIND_ACTIVITY));
-        mAmWmState.waitForValidState(mDevice, true, new String[] {VISIBLE_BEHIND_ACTIVITY},
-                new int[] {FULLSCREEN_WORKSPACE_STACK_ID}, false /* compareTaskAndStackBounds */);
-
-        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
-        mAmWmState.waitForHomeActivityVisible(mDevice);
-
-        /* TODO: Find a proper way to wait until launcher activity
-         * becomes fully visible. It appears that both VisibleBehindActivity
-         * and home activity are visible at some point before the former
-         * disappears.*/
-        Thread.sleep(3000);
-        mAmWmState.computeState(mDevice, null);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
-        mAmWmState.assertVisibility(
-                VISIBLE_BEHIND_ACTIVITY, hasDeviceFeature("android.software.leanback"));
-    }
-
-    public void testVisibleBehindOtherActivity_NotOverHome() throws Exception {
-        executeShellCommand(getAmStartCmd(VISIBLE_BEHIND_ACTIVITY));
-        executeShellCommand(getAmStartCmd(TRANSLUCENT_ACTIVITY));
-
-        mAmWmState.computeState(mDevice,
-                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-    }
-
-    public void testVisibleBehindOtherActivity_OverHome() throws Exception {
-        executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
-        executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
-
-        mAmWmState.computeState(mDevice,
-                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-    }
-
-    public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
-        if (!supportsPip()) {
-            return;
-        }
-
-        executeShellCommand(getAmStartCmdOverHome(PIP_ON_PIP_ACTIVITY));
-        // NOTE: moving to pinned stack will trigger the pip-on-pip activity to launch the
-        // translucent activity.
-        executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
-
-        mAmWmState.computeState(mDevice, new String[] {PIP_ON_PIP_ACTIVITY, TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
-        mAmWmState.assertVisibility(PIP_ON_PIP_ACTIVITY, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-    }
-
-    /**
-     * Asserts that the home activity is visible when a translucent activity is launched in the
-     * fullscreen stack over the home activity.
-     */
-    public void testTranslucentActivityOnTopOfHome() throws Exception {
-        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
-        executeShellCommand(getAmStartCmd(TRANSLUCENT_ACTIVITY));
-
-        mAmWmState.computeState(mDevice, new String[]{TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertFrontStack(
-                "Fullscreen stack must be the front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-        mAmWmState.assertHomeActivityVisible(true);
-    }
-
-    /**
-     * Assert that the home activity is visible if a task that was launched from home is pinned
-     * and also assert the next task in the fullscreen stack isn't visible.
-     */
-    public void testHomeVisibleOnActivityTaskPinned() throws Exception {
-        if (!supportsPip()) {
-            return;
-        }
-
-        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
-        executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
-        executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
-        executeShellCommand(getAmStartCmd(TRANSLUCENT_ACTIVITY));
-        executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
-
-        mAmWmState.computeState(mDevice, new String[]{TRANSLUCENT_ACTIVITY});
-
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, false);
-        mAmWmState.assertHomeActivityVisible(true);
-    }
-
-    public void testTranslucentActivityOverDockedStack() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
-        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME});
-        launchActivityInStack(TRANSLUCENT_ACTIVITY_NAME, DOCKED_STACK_ID);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME,
-                TRANSLUCENT_ACTIVITY_NAME}, false /* compareTaskAndStackBounds */);
-        mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain fullscreen stack",
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY_NAME, true);
-    }
-
-    public void testTurnScreenOnActivity() throws Exception {
-        lockDevice();
-        executeShellCommand(getAmStartCmd(TURN_SCREEN_ON_ACTIVITY_NAME));
-        mAmWmState.computeState(mDevice, new String[] { TURN_SCREEN_ON_ACTIVITY_NAME });
-        mAmWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY_NAME, true);
-    }
-
-    public void testFinishActivityInNonFocusedStack() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        // Launch two activities in docked stack.
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        launchActivity(false /* toSide */, false /* randomData */, false /* multipleTaskFlag */,
-                BROADCAST_RECEIVER_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] { BROADCAST_RECEIVER_ACTIVITY });
-        mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, true);
-        // Launch something to fullscreen stack to make it focused.
-        launchActivityInStack(TEST_ACTIVITY_NAME, 1);
-        mAmWmState.computeState(mDevice, new String[] { TEST_ACTIVITY_NAME });
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
-        // Finish activity in non-focused (docked) stack.
-        executeShellCommand("am broadcast -a trigger_broadcast --ez finish true");
-        mAmWmState.computeState(mDevice, new String[] { LAUNCHING_ACTIVITY });
-        mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
-        mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, false);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
deleted file mode 100644
index 0083be4..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
+++ /dev/null
@@ -1,228 +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.server.cts;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
-public class ActivityManagerAmStartOptionsTests extends ActivityManagerTestBase {
-
-    private static final String TEST_ACTIVITY_NAME = "TestActivity";
-    private static final String ENTRYPOINT_ACTIVITY_NAME = "EntryPointAliasActivity";
-    private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity";
-
-    public void testDashD() throws Exception {
-        final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
-        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.app", 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.
-        for (int i = 0; i < 2; i++) {
-            clearLogcat();
-            executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME) + " -D");
-
-            // visibleOnly=false as the first window popping up will be the debugger window.
-            mAmWmState.computeState(mDevice, false, waitForActivitiesVisible);
-            verifier.verifyDashD();
-        }
-    }
-
-    public void testDashW_Direct() throws Exception {
-        testDashW(SINGLE_TASK_ACTIVITY_NAME, SINGLE_TASK_ACTIVITY_NAME);
-    }
-
-    public void testDashW_Indirect() throws Exception {
-        testDashW(ENTRYPOINT_ACTIVITY_NAME, SINGLE_TASK_ACTIVITY_NAME);
-    }
-
-    private void testDashW(final String entryActivity, final String actualActivity)
-            throws Exception {
-        AmStartLogcatVerifier verifier = new AmStartLogcatVerifier("android.server.app", actualActivity);
-
-        // Test cold start
-        startActivityAndVerifyResult(verifier, entryActivity, actualActivity, true);
-
-        // Test warm start
-        pressHomeButton();
-        startActivityAndVerifyResult(verifier, entryActivity, actualActivity, false);
-
-        // Test "hot" start (app already in front)
-        startActivityAndVerifyResult(verifier, entryActivity, actualActivity, false);
-    }
-
-    private static final Pattern sNotStartedWarningPattern = Pattern.compile(
-            "Warning: Activity not started(.*)");
-    private static final Pattern sStatusPattern = Pattern.compile(
-            "Status: (.*)");
-    private static final Pattern sActivityPattern = Pattern.compile(
-            "Activity: (.*)");
-    private static final String sStatusOk = "ok";
-
-    private void startActivityAndVerifyResult(
-            final AmStartLogcatVerifier verifier, final String entryActivity,
-            final String actualActivity, boolean shouldStart) throws Exception {
-        clearLogcat();
-
-        // Pass in different data only when cold starting. This is to make the intent
-        // different in subsequent warm/hot launches, so that the entrypoint alias
-        // activity is always started, but the actual activity is not started again
-        // because of the NEW_TASK and singleTask flags.
-        final String result = executeShellCommand(getAmStartCmd(entryActivity) + " -W"
-                + (shouldStart ? " -d about:blank" : ""));
-
-        // Verify shell command return value
-        verifyShellOutput(result, actualActivity, shouldStart);
-
-        // Verify adb logcat log
-        verifier.verifyDashW(shouldStart);
-    }
-
-    private void verifyShellOutput(
-            final String result, final String activity, boolean shouldStart) {
-        boolean warningFound = false;
-        String status = null;
-        String reportedActivity = null;
-        String componentActivityName = getActivityComponentName(activity);
-
-        for (String line : result.split("\\n")) {
-            Matcher matcher = sNotStartedWarningPattern.matcher(line);
-            if (matcher.matches()) {
-                warningFound = true;
-                continue;
-            }
-            matcher = sStatusPattern.matcher(line);
-            if (matcher.matches()) {
-                status = matcher.group(1);
-                continue;
-            }
-            matcher = sActivityPattern.matcher(line);
-            if (matcher.matches()) {
-                reportedActivity = matcher.group(1);
-                continue;
-            }
-        }
-
-        assertTrue("Status " + status + " is not ok", sStatusOk.equals(status));
-        assertTrue("Reported activity is " + reportedActivity + " not " + componentActivityName,
-                componentActivityName.equals(reportedActivity));
-
-        if (shouldStart && warningFound) {
-            fail("Should start new activity but brought something to front.");
-        } else if (!shouldStart && !warningFound){
-            fail("Should bring existing activity to front but started new activity.");
-        }
-    }
-
-    private static final Pattern sStartProcPattern =
-            Pattern.compile("(.+): Start proc (\\d+):(.*) for activity (.*)");
-    private static final Pattern sKillingPattern =
-            Pattern.compile("(.+): Killing (\\d+):(.*)");
-    private static final Pattern sWaitingForDebuggerPattern =
-            Pattern.compile("(.+): Application (.+) is waiting for the debugger (.*)");
-    private static final Pattern sDisplayTimePattern =
-            Pattern.compile("(.+): Displayed (.*): (\\+{0,1})([0-9]+)ms(.*)");
-
-    private class AmStartLogcatVerifier {
-        private String mPrevProcId;
-        private final String mPackageName;
-        private final String mActivityName;
-
-        AmStartLogcatVerifier(String packageName, String activityName) {
-            mPackageName = packageName;
-            mActivityName = activityName;
-        }
-
-        void verifyDashD() throws DeviceNotAvailableException {
-            boolean prevProcKilled = false;;
-            boolean waitingForDebugger = false;
-            String newProcId = null;
-            final String[] componentNames = new String[] {"ActivityManager", "ActivityThread"};
-
-            for (String line : getDeviceLogsForComponents(componentNames)) {
-                line = line.trim();
-
-                Matcher matcher = sStartProcPattern.matcher(line);
-                if (matcher.matches()) {
-                    final String activity = matcher.group(4);
-                    if (activity.contains(mActivityName)) {
-                        newProcId = matcher.group(2);
-                    }
-                    continue;
-                }
-
-                matcher = sKillingPattern.matcher(line);
-                if (matcher.matches()) {
-                    final String procId = matcher.group(2);
-                    if (procId.equals(mPrevProcId)) {
-                        prevProcKilled = true;
-                    }
-                    continue;
-                }
-
-                matcher = sWaitingForDebuggerPattern.matcher(line);
-                if (matcher.matches()) {
-                    final String packageName = matcher.group(2);
-                    if (packageName.equals(mPackageName)) {
-                        waitingForDebugger = true;
-                    }
-                    continue;
-                }
-            }
-
-            assertTrue("Didn't kill exisiting proc " + mPrevProcId + ".",
-                    mPrevProcId == null || prevProcKilled);
-            assertTrue("Didn't start new proc.", newProcId != null);
-            assertTrue("Didn't wait for debugger.", waitingForDebugger);
-
-            mPrevProcId = newProcId;
-        }
-
-        void verifyDashW(boolean shouldStart) throws DeviceNotAvailableException {
-            int displayCount = 0;
-            String activityName = null;
-
-            for (String line : getDeviceLogsForComponent("ActivityManager")) {
-                line = line.trim();
-
-                Matcher matcher = sDisplayTimePattern.matcher(line);
-                if (matcher.matches()) {
-                    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")) {
-                        continue;
-                    }
-                    if (!shouldStart) {
-                        fail("Shouldn't display anything but displayed " + activityName);
-                    }
-                    displayCount++;
-                }
-            }
-            final String expectedActivityName = getActivityComponentName(mActivityName);
-            if (shouldStart) {
-                if (displayCount != 1) {
-                    fail("Should display exactly one activity but displayed " + displayCount);
-                } else if (!expectedActivityName.equals(activityName)) {
-                    fail("Should display " + expectedActivityName +
-                            " but displayed " + activityName);
-                }
-            }
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
deleted file mode 100644
index 9ef7093..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ /dev/null
@@ -1,352 +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.server.cts;
-
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.awt.Rectangle;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ActivityManagerAppConfigurationTests extends ActivityManagerTestBase {
-    private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity";
-    private static final String TEST_ACTIVITY_NAME = "TestActivity";
-
-    /**
-     * Tests that the WindowManager#getDefaultDisplay() and the Configuration of the Activity
-     * has an updated size when the Activity is resized from fullscreen to docked state.
-     *
-     * The Activity handles configuration changes, so it will not be restarted between resizes.
-     * On Configuration changes, the Activity logs the Display size and Configuration width
-     * and heights. The values reported in fullscreen should be larger than those reported in
-     * docked state.
-     */
-    public void testConfigurationUpdatesWhenResizedFromFullscreen() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-
-        moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                DOCKED_STACK_ID);
-
-        assertSizesAreSane(fullscreenSizes, dockedSizes);
-    }
-
-    /**
-     * Same as {@link #testConfigurationUpdatesWhenResizedFromFullscreen()} but resizing
-     * from docked state to fullscreen (reverse).
-     */
-    public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                DOCKED_STACK_ID);
-
-        moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-
-        assertSizesAreSane(fullscreenSizes, dockedSizes);
-    }
-
-    /**
-     * Tests whether the Display sizes change when rotating the device.
-     */
-    public void testConfigurationUpdatesWhenRotatingWhileFullscreen() throws Exception {
-        if (!supportsScreenRotation()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no rotation support");
-            return;
-        }
-
-        setDeviceRotation(0);
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-
-        rotateAndCheckSizes(initialSizes, FULLSCREEN_WORKSPACE_STACK_ID);
-    }
-
-    /**
-     * Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity
-     * is in the docked stack.
-     */
-    public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
-        if (!supportsScreenRotation()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no rotation support");
-            return;
-        }
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        setDeviceRotation(0);
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        // Launch our own activity to side in case Recents (or other activity to side) doesn't
-        // support rotation.
-        launchActivityToSide(false /* randomData */, false /* multipleTask */, TEST_ACTIVITY_NAME);
-        // Launch target activity in docked stack.
-        launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask */,
-                RESIZEABLE_ACTIVITY_NAME);
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                DOCKED_STACK_ID);
-
-        rotateAndCheckSizes(initialSizes, DOCKED_STACK_ID);
-    }
-
-    /**
-     * Same as {@link #testConfigurationUpdatesWhenRotatingWhileDocked()} but when the Activity
-     * is launched to side from docked stack.
-     */
-    public void testConfigurationUpdatesWhenRotatingToSideFromDocked() throws Exception {
-        if (!supportsScreenRotation()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no rotation support");
-            return;
-        }
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        setDeviceRotation(0);
-
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        launchActivityToSide(false /* randomData */, false /* multipleTaskFlag */,
-                RESIZEABLE_ACTIVITY_NAME);
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-
-        rotateAndCheckSizes(initialSizes, FULLSCREEN_WORKSPACE_STACK_ID);
-    }
-
-    private void rotateAndCheckSizes(ReportedSizes prevSizes, int stackId) throws Exception {
-        for (int rotation = 3; rotation >= 0; --rotation) {
-            clearLogcat();
-            setDeviceRotation(rotation);
-            final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
-                    stackId);
-            assertSizesRotate(prevSizes, rotatedSizes);
-            prevSizes = rotatedSizes;
-        }
-    }
-
-    /**
-     * Tests when activity moved from fullscreen stack to docked and back. Activity will be
-     * relaunched twice and it should have same config as initial one.
-     */
-    public void testSameConfigurationFullSplitFullRelaunch() throws Exception {
-        moveActivityFullSplitFull(TEST_ACTIVITY_NAME);
-    }
-
-    /**
-     * Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch.
-     */
-    public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
-        moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
-    }
-
-    /**
-     * Launches activity in fullscreen stack, moves to docked stack and back to fullscreen stack.
-     * Last operation is done in a way which simulates split-screen divider movement maximizing
-     * docked stack size and then moving task to fullscreen stack - the same way it is done when
-     * user long-presses overview/recents button to exit split-screen.
-     * Asserts that initial and final reported sizes in fullscreen stack are the same.
-     */
-    private void moveActivityFullSplitFull(String activityName) throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        // Launch to fullscreen stack and record size.
-        launchActivityInStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        final Rectangle displayRect = getDisplayRect(activityName);
-
-        // Move to docked stack.
-        moveActivityToStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(activityName, DOCKED_STACK_ID);
-        assertSizesAreSane(initialFullscreenSizes, dockedSizes);
-        // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
-        // will come up.
-        launchActivityInStack(activityName, DOCKED_STACK_ID);
-        mAmWmState.computeState(mDevice, new String[] { activityName },
-                false /* compareTaskAndStackBounds */);
-
-        // Resize docked stack to fullscreen size. This will trigger activity relaunch with
-        // non-empty override configuration corresponding to fullscreen size.
-        runCommandAndPrintOutput("am stack resize " + DOCKED_STACK_ID + " 0 0 "
-                + displayRect.width + " " + displayRect.height);
-        // Move activity back to fullscreen stack.
-        moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-
-        // After activity configuration was changed twice it must report same size as original one.
-        assertSizesAreSame(initialFullscreenSizes, finalFullscreenSizes);
-    }
-
-    /**
-     * Tests when activity moved from docked stack to fullscreen and back. Activity will be
-     * relaunched twice and it should have same config as initial one.
-     */
-    public void testSameConfigurationSplitFullSplitRelaunch() throws Exception {
-        moveActivitySplitFullSplit(TEST_ACTIVITY_NAME);
-    }
-
-    /**
-     * Same as {@link #testSameConfigurationSplitFullSplitRelaunch} but without relaunch.
-     */
-    public void testSameConfigurationSplitFullSplitNoRelaunch() throws Exception {
-        moveActivitySplitFullSplit(RESIZEABLE_ACTIVITY_NAME);
-    }
-
-    /**
-     * Launches activity in docked stack, moves to fullscreen stack and back to docked stack.
-     * Asserts that initial and final reported sizes in docked stack are the same.
-     */
-    private void moveActivitySplitFullSplit(String activityName) throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        // Launch to docked stack and record size.
-        launchActivityInStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName,
-                DOCKED_STACK_ID);
-        // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
-        // will come up.
-        launchActivityInStack(activityName, DOCKED_STACK_ID);
-        mAmWmState.computeState(mDevice, new String[] { activityName },
-                false /* compareTaskAndStackBounds */);
-
-        // Move to fullscreen stack.
-        moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        assertSizesAreSane(fullscreenSizes, initialDockedSizes);
-
-        // Move activity back to docked stack.
-        moveActivityToStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName,
-                DOCKED_STACK_ID);
-
-        // After activity configuration was changed twice it must report same size as original one.
-        assertSizesAreSame(initialDockedSizes, finalDockedSizes);
-    }
-
-    /**
-     * Asserts that after rotation, the aspect ratios of display size, metrics, and configuration
-     * have flipped.
-     */
-    private static void assertSizesRotate(ReportedSizes rotationA, ReportedSizes rotationB)
-            throws Exception {
-        assertEquals(rotationA.displayWidth, rotationA.metricsWidth);
-        assertEquals(rotationA.displayHeight, rotationA.metricsHeight);
-        assertEquals(rotationB.displayWidth, rotationB.metricsWidth);
-        assertEquals(rotationB.displayHeight, rotationB.metricsHeight);
-
-        final boolean beforePortrait = rotationA.displayWidth < rotationA.displayHeight;
-        final boolean afterPortrait = rotationB.displayWidth < rotationB.displayHeight;
-        assertFalse(beforePortrait == afterPortrait);
-
-        final boolean beforeConfigPortrait = rotationA.widthDp < rotationA.heightDp;
-        final boolean afterConfigPortrait = rotationB.widthDp < rotationB.heightDp;
-        assertEquals(beforePortrait, beforeConfigPortrait);
-        assertEquals(afterPortrait, afterConfigPortrait);
-
-        assertEquals(rotationA.smallestWidthDp, rotationB.smallestWidthDp);
-    }
-
-    /**
-     * Throws an AssertionError if fullscreenSizes has widths/heights (depending on aspect ratio)
-     * that are smaller than the dockedSizes.
-     */
-    private static void assertSizesAreSane(ReportedSizes fullscreenSizes, ReportedSizes dockedSizes)
-            throws Exception {
-        final boolean portrait = fullscreenSizes.displayWidth < fullscreenSizes.displayHeight;
-        if (portrait) {
-            assertTrue(dockedSizes.displayHeight < fullscreenSizes.displayHeight);
-            assertTrue(dockedSizes.heightDp < fullscreenSizes.heightDp);
-            assertTrue(dockedSizes.metricsHeight < fullscreenSizes.metricsHeight);
-        } else {
-            assertTrue(dockedSizes.displayWidth < fullscreenSizes.displayWidth);
-            assertTrue(dockedSizes.widthDp < fullscreenSizes.widthDp);
-            assertTrue(dockedSizes.metricsWidth < fullscreenSizes.metricsWidth);
-        }
-    }
-
-    /**
-     * Throws an AssertionError if sizes are different.
-     */
-    private static void assertSizesAreSame(ReportedSizes firstSize, ReportedSizes secondSize)
-            throws Exception {
-        assertEquals(firstSize.widthDp, secondSize.widthDp);
-        assertEquals(firstSize.heightDp, secondSize.heightDp);
-        assertEquals(firstSize.displayWidth, secondSize.displayWidth);
-        assertEquals(firstSize.displayHeight, secondSize.displayHeight);
-        assertEquals(firstSize.metricsWidth, secondSize.metricsWidth);
-        assertEquals(firstSize.metricsHeight, secondSize.metricsHeight);
-        assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp);
-    }
-
-    private ReportedSizes getActivityDisplaySize(String activityName, int stackId)
-            throws Exception {
-        mAmWmState.computeState(mDevice, new String[] { activityName },
-                false /* compareTaskAndStackBounds */);
-        mAmWmState.assertContainsStack("Must contain stack " + stackId, stackId);
-        final ReportedSizes details = getLastReportedSizesForActivity(activityName);
-        assertNotNull(details);
-        return details;
-    }
-
-    private Rectangle getDisplayRect(String activityName)
-            throws Exception {
-        final String windowName = getWindowName(activityName);
-
-        mAmWmState.computeState(mDevice, true /* visibleOnly */, new String[] {activityName});
-
-        mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
-
-        final List<WindowManagerState.WindowState> tempWindowList = new ArrayList<>();
-        mAmWmState.getWmState().getMatchingWindowState(windowName, tempWindowList);
-
-        assertEquals("Should have exactly one window state for the activity.", 1,
-                tempWindowList.size());
-
-        WindowManagerState.WindowState windowState = tempWindowList.get(0);
-        assertNotNull("Should have a valid window", windowState);
-
-        WindowManagerState.Display display = mAmWmState.getWmState()
-                .getDisplay(windowState.getDisplayId());
-        assertNotNull("Should be on a display", display);
-
-        return display.getDisplayRect();
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
deleted file mode 100644
index 130e84e..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
+++ /dev/null
@@ -1,106 +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.server.cts;
-
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
-public class ActivityManagerConfigChangeTests extends ActivityManagerTestBase {
-
-    private static final String TEST_ACTIVITY_NAME = "TestActivity";
-    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
-
-    public void testRotation90Relaunch() throws Exception{
-        if (!supportsScreenRotation()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no rotation support");
-            return;
-        }
-
-        // Should relaunch on every rotation and receive no onConfigurationChanged()
-        testRotation(TEST_ACTIVITY_NAME, 1, 1, 0);
-    }
-
-    public void testRotation90NoRelaunch() throws Exception {
-        if (!supportsScreenRotation()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no rotation support");
-            return;
-        }
-
-        // Should receive onConfigurationChanged() on every rotation and no relaunch
-        testRotation(NO_RELAUNCH_ACTIVITY_NAME, 1, 0, 1);
-    }
-
-    public void testRotation180Relaunch() throws Exception {
-        // Should receive nothing
-        testRotation(TEST_ACTIVITY_NAME, 2, 0, 0);
-    }
-
-    public void testRotation180NoRelaunch() throws Exception {
-        // Should receive nothing
-        testRotation(NO_RELAUNCH_ACTIVITY_NAME, 2, 0, 0);
-    }
-
-    public void testChangeFontScaleRelaunch() throws Exception {
-        // Should relaunch and receive no onConfigurationChanged()
-        testChangeFontScale(TEST_ACTIVITY_NAME, true);
-    }
-
-    public void testChangeFontScaleNoRelaunch() throws Exception {
-        // Should receive onConfigurationChanged() and no relaunch
-        testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false);
-    }
-
-    private void testRotation(
-            String activityName, int rotationStep, int numRelaunch, int numConfigChange)
-                    throws Exception {
-        executeShellCommand(getAmStartCmd(activityName));
-
-        final String[] waitForActivitiesVisible = new String[] {activityName};
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-
-        setDeviceRotation(4 - rotationStep);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-
-        for (int rotation = 0; rotation < 4; rotation += rotationStep) {
-            clearLogcat();
-            setDeviceRotation(rotation);
-            mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-            assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange);
-        }
-    }
-
-    private void testChangeFontScale(
-            String activityName, boolean relaunch) throws Exception {
-        executeShellCommand(getAmStartCmd(activityName));
-        final String[] waitForActivitiesVisible = new String[] {activityName};
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-
-        setFontScale(1.0f);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-
-        for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
-            clearLogcat();
-            setFontScale(fontScale);
-            mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-            assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1);
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
deleted file mode 100644
index ec0b7b0..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ /dev/null
@@ -1,405 +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 android.server.cts;
-
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.awt.Rectangle;
-
-public class ActivityManagerDockedStackTests extends ActivityManagerTestBase {
-
-    private static final String TEST_ACTIVITY_NAME = "TestActivity";
-    private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity";
-    private static final String DOCKED_ACTIVITY_NAME = "DockedActivity";
-    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
-    private static final String SINGLE_INSTANCE_ACTIVITY_NAME = "SingleInstanceActivity";
-    private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity";
-
-    private static final int TASK_SIZE = 600;
-    private static final int STACK_SIZE = 300;
-
-    public void testStackList() throws Exception {
-        executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
-    }
-
-    public void testDockActivity() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(TEST_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
-    }
-
-    public void testNonResizeableNotDocked() throws Exception {
-        launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME});
-
-        mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
-        mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID);
-        mAmWmState.assertFrontStack(
-                "Fullscreen stack must be front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-    }
-
-    public void testLaunchToSide() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
-    }
-
-    public void testLaunchToSideAndBringToFront() throws Exception {
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
-        final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-
-        // Launch activity to side.
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, waitForFirstVisible);
-        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
-                TEST_ACTIVITY_NAME);
-
-        // Launch another activity to side to cover first one.
-        launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.computeState(mDevice, waitForSecondVisible);
-        int taskNumberCovered = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertEquals("Fullscreen stack must have one task added.",
-                taskNumberInitial + 1, taskNumberCovered);
-        mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
-                NO_RELAUNCH_ACTIVITY_NAME);
-
-        // Launch activity that was first launched to side. It should be brought to front.
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, waitForFirstVisible);
-        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertEquals("Task number in fullscreen stack must remain the same.",
-                taskNumberCovered, taskNumberFinal);
-        mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
-                TEST_ACTIVITY_NAME);
-    }
-
-    public void testLaunchToSideMultiple() throws Exception {
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-        final String[] waitForActivitiesVisible =
-            new String[] {TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY};
-
-        // Launch activity to side.
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
-
-        // Try to launch to side same activity again.
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal);
-        mAmWmState.assertFocusedActivity("Launched to side activity must remain in front.",
-                TEST_ACTIVITY_NAME);
-        mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
-    }
-
-    public void testLaunchToSideSingleInstance() throws Exception {
-        launchTargetToSide(SINGLE_INSTANCE_ACTIVITY_NAME, false);
-    }
-
-    public void testLaunchToSideSingleTask() throws Exception {
-        launchTargetToSide(SINGLE_TASK_ACTIVITY_NAME, false);
-    }
-
-    public void testLaunchToSideMultipleWithDifferentIntent() throws Exception {
-        launchTargetToSide(TEST_ACTIVITY_NAME, true);
-    }
-
-    private void launchTargetToSide(String targetActivityName,
-                                    boolean taskCountMustIncrement) throws Exception {
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-
-        final String[] waitForActivitiesVisible =
-            new String[] {targetActivityName, LAUNCHING_ACTIVITY};
-
-        // Launch activity to side with data.
-        launchActivityToSide(true, false, targetActivityName);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
-
-        // Try to launch to side same activity again with different data.
-        launchActivityToSide(true, false, targetActivityName);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberSecondLaunch = mAmWmState.getAmState()
-                .getStackById(FULLSCREEN_WORKSPACE_STACK_ID).getTasks().size();
-        if (taskCountMustIncrement) {
-            mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1,
-                    taskNumberSecondLaunch);
-        } else {
-            mAmWmState.assertEquals("Task number must not change.", taskNumberInitial,
-                    taskNumberSecondLaunch);
-        }
-        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
-                targetActivityName);
-        mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
-
-        // Try to launch to side same activity again with no data.
-        launchActivityToSide(false, false, targetActivityName);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        if (taskCountMustIncrement) {
-            mAmWmState.assertEquals("Task number must be incremented.", taskNumberSecondLaunch + 1,
-                    taskNumberFinal);
-        } else {
-            mAmWmState.assertEquals("Task number must not change.", taskNumberSecondLaunch,
-                    taskNumberFinal);
-        }
-        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
-                targetActivityName);
-        mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID));
-    }
-
-    public void testLaunchToSideMultipleWithFlag() throws Exception {
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-        final String[] waitForActivitiesVisible =
-            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
-
-        // Launch activity to side.
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
-
-        // Try to launch to side same activity again, but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK.
-        launchActivityToSide(false, true);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
-                .getTasks().size();
-        mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1,
-                taskNumberFinal);
-        mAmWmState.assertFocusedActivity("Launched to side activity must be in front.",
-                TEST_ACTIVITY_NAME);
-        mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.",
-                mAmWmState.getAmState()
-                        .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID));
-    }
-
-    public void testRotationWhenDocked() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
-
-        // Rotate device single steps (90°) 0-1-2-3.
-        // Each time we compute the state we implicitly assert valid bounds.
-        String[] waitForActivitiesVisible =
-            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
-        setDeviceRotation(0);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(1);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(2);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(3);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        // Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for double
-        // step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side.
-        setDeviceRotation(1);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(3);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(0);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(2);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-        setDeviceRotation(0);
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-    }
-
-    public void testRotationWhenDockedWhileLocked() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
-        launchActivityToSide();
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        mAmWmState.assertSanity();
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
-
-        String[] waitForActivitiesVisible =
-            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
-        lockDevice();
-        setDeviceRotation(0);
-        unlockDevice();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-
-        lockDevice();
-        setDeviceRotation(1);
-        unlockDevice();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-
-        lockDevice();
-        setDeviceRotation(2);
-        unlockDevice();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-
-        lockDevice();
-        setDeviceRotation(3);
-        unlockDevice();
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-    }
-
-    public void testResizeDockedStack() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-
-        launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
-        launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
-        resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
-                false /* compareTaskAndStackBounds */);
-        mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
-        mAmWmState.assertContainsStack("Must contain fullscreen stack",
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        assertEquals(new Rectangle(0, 0, STACK_SIZE, STACK_SIZE),
-                mAmWmState.getAmState().getStackById(DOCKED_STACK_ID).getBounds());
-        mAmWmState.assertDockedTaskBounds(TASK_SIZE, DOCKED_ACTIVITY_NAME);
-        mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true);
-    }
-
-    public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
-            return;
-        }
-        final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
-        executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
-        mAmWmState.computeState(mDevice, waitTestActivityName);
-        final Rectangle fullScreenBounds =
-                mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds();
-
-        moveActivityToDockStack(TEST_ACTIVITY_NAME);
-        mAmWmState.computeState(mDevice, waitTestActivityName);
-        launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-
-        mAmWmState.computeState(mDevice,
-                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-        final Rectangle initialDockBounds =
-                mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds();
-
-        clearLogcat();
-
-        Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
-        resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
-        mAmWmState.computeState(mDevice,
-                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-
-        // We resize twice to make sure we cross an orientation change threshold for both
-        // activities.
-        newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false);
-        resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
-        mAmWmState.computeState(mDevice,
-                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-        assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
-        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
-    }
-
-    private Rectangle computeNewDockBounds(
-            Rectangle fullscreenBounds, Rectangle dockBounds, boolean reduceSize) {
-        final boolean inLandscape = fullscreenBounds.width > dockBounds.width;
-        // We are either increasing size or reducing it.
-        final float sizeChangeFactor = reduceSize ? 0.5f : 1.5f;
-        final Rectangle newBounds = new Rectangle(dockBounds);
-        if (inLandscape) {
-            // In landscape we change the width.
-            newBounds.width *= sizeChangeFactor;
-        } else {
-            // In portrait we change the height
-            newBounds.height *= sizeChangeFactor;
-        }
-
-        return newBounds;
-    }
-
-    private void launchActivityToSide() throws Exception {
-        launchActivityToSide(false, false);
-    }
-
-    private void launchActivityToSide(boolean randomData, boolean multipleTaskFlag)
-            throws Exception {
-        launchActivityToSide(randomData, multipleTaskFlag, null);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
deleted file mode 100644
index 3f755fe..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
+++ /dev/null
@@ -1,97 +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.server.cts;
-
-import java.awt.Rectangle;
-import java.util.ArrayList;
-
-public class ActivityManagerFreeformStackTests extends ActivityManagerTestBase {
-
-    private static final String TEST_ACTIVITY = "TestActivity";
-    private static final int TEST_TASK_OFFSET = 20;
-    private static final int TEST_TASK_OFFSET_2 = 100;
-    private static final int TEST_TASK_SIZE_1 = 900;
-    private static final int TEST_TASK_SIZE_2 = TEST_TASK_SIZE_1 * 2;
-    // NOTE: Launching the FreeformActivity will automatically launch the TestActivity
-    // with bounds (0, 0, 900, 900)
-    private static final String FREEFORM_ACTIVITY = "FreeformActivity";
-    private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
-    private static final String NO_RELAUNCH_ACTIVITY = "NoRelaunchActivity";
-
-    public void testFreeformWindowManagementSupport() throws Exception {
-
-        launchActivityInStack(FREEFORM_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
-
-        mAmWmState.computeState(mDevice, new String[] {FREEFORM_ACTIVITY, TEST_ACTIVITY});
-
-        if (!supportsFreeform()) {
-            mAmWmState.assertDoesNotContainStack(
-                    "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
-            return;
-        }
-
-        mAmWmState.assertFrontStack(
-                "Freeform stack must be the front stack.", FREEFORM_WORKSPACE_STACK_ID);
-        mAmWmState.assertVisibility(FREEFORM_ACTIVITY, true);
-        mAmWmState.assertVisibility(TEST_ACTIVITY, true);
-        mAmWmState.assertFocusedActivity(
-                TEST_ACTIVITY + " must be focused Activity", TEST_ACTIVITY);
-        assertEquals(new Rectangle(0, 0, TEST_TASK_SIZE_1, TEST_TASK_SIZE_1),
-                mAmWmState.getAmState().getTaskByActivityName(TEST_ACTIVITY).getBounds());
-    }
-
-    public void testNonResizeableActivityNotLaunchedToFreeform() throws Exception {
-        launchActivityInStack(NON_RESIZEABLE_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
-
-        mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY});
-
-        mAmWmState.assertFrontStack(
-                "Fullscreen stack must be the front stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertDoesNotContainStack(
-                "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
-    }
-
-    public void testActivityLifeCycleOnResizeFreeformTask() throws Exception {
-        launchActivityInStack(TEST_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
-        launchActivityInStack(NO_RELAUNCH_ACTIVITY, FREEFORM_WORKSPACE_STACK_ID);
-
-        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
-
-        if (!supportsFreeform()) {
-            mAmWmState.assertDoesNotContainStack(
-                    "Must not contain freeform stack.", FREEFORM_WORKSPACE_STACK_ID);
-            return;
-        }
-
-        resizeActivityTask(TEST_ACTIVITY,
-                TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_1, TEST_TASK_SIZE_2);
-        resizeActivityTask(NO_RELAUNCH_ACTIVITY,
-                TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_1, TEST_TASK_SIZE_2);
-
-        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
-
-        clearLogcat();
-        resizeActivityTask(TEST_ACTIVITY,
-                TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
-        resizeActivityTask(NO_RELAUNCH_ACTIVITY,
-                TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
-        mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
-
-        assertActivityLifecycle(TEST_ACTIVITY, true);
-        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
deleted file mode 100644
index 70b0518..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
+++ /dev/null
@@ -1,191 +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.server.cts;
-
-import java.lang.Exception;
-import java.lang.String;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import junit.framework.Assert;
-
-import java.awt.Rectangle;
-import android.server.cts.WindowManagerState.WindowState;
-import android.server.cts.WindowManagerState.Display;
-
-import static android.server.cts.ActivityAndWindowManagersState.dpToPx;
-import static com.android.ddmlib.Log.LogLevel.INFO;
-
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-public class ActivityManagerManifestLayoutTests extends ActivityManagerTestBase {
-
-    // Test parameters
-    private static final int DEFAULT_WIDTH_DP = 240;
-    private static final int DEFAULT_HEIGHT_DP = 160;
-    private static final float DEFAULT_WIDTH_FRACTION = 0.25f;
-    private static final float DEFAULT_HEIGHT_FRACTION = 0.35f;
-    private static final int MIN_WIDTH_DP = 100;
-    private static final int MIN_HEIGHT_DP = 80;
-
-    private static final int GRAVITY_VER_CENTER = 0x01;
-    private static final int GRAVITY_VER_TOP    = 0x02;
-    private static final int GRAVITY_VER_BOTTOM = 0x04;
-    private static final int GRAVITY_HOR_CENTER = 0x10;
-    private static final int GRAVITY_HOR_LEFT   = 0x20;
-    private static final int GRAVITY_HOR_RIGHT  = 0x40;
-
-    private List<WindowState> mTempWindowList = new ArrayList();
-    private Display mDisplay;
-    private WindowState mWindowState;
-
-    public void testGravityAndDefaultSizeTopLeft() throws Exception {
-        testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_LEFT, false /*fraction*/);
-    }
-
-    public void testGravityAndDefaultSizeTopRight() throws Exception {
-        testLayout(GRAVITY_VER_TOP, GRAVITY_HOR_RIGHT, true /*fraction*/);
-    }
-
-    public void testGravityAndDefaultSizeBottomLeft() throws Exception {
-        testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_LEFT, true /*fraction*/);
-    }
-
-    public void testGravityAndDefaultSizeBottomRight() throws Exception {
-        testLayout(GRAVITY_VER_BOTTOM, GRAVITY_HOR_RIGHT, false /*fraction*/);
-    }
-
-    public void testMinimalSizeFreeform() throws Exception {
-        if (!supportsFreeform()) {
-            CLog.logAndDisplay(INFO, "Skipping test: no freeform support");
-            return;
-        }
-        testMinimalSize(FREEFORM_WORKSPACE_STACK_ID);
-    }
-
-    public void testMinimalSizeDocked() throws Exception {
-        if (!supportsMultiWindowMode()) {
-            CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
-            return;
-        }
-        testMinimalSize(DOCKED_STACK_ID);
-    }
-
-    private void testMinimalSize(int stackId) throws Exception {
-        final String activityName = "BottomRightLayoutActivity";
-
-        // Issue command to resize to <0,0,1,1>. We expect the size to be floored at
-        // MIN_WIDTH_DPxMIN_HEIGHT_DP.
-        if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
-            launchActivityInStack(activityName, stackId);
-            resizeActivityTask(activityName, 0, 0, 1, 1);
-        } else { // stackId == DOCKED_STACK_ID
-            launchActivityInDockStack(activityName);
-            resizeDockedStack(1, 1, 1, 1);
-        }
-        getDisplayAndWindowState(activityName, false);
-
-        final int minWidth = dpToPx(MIN_WIDTH_DP, mDisplay.getDpi());
-        final int minHeight = dpToPx(MIN_HEIGHT_DP, mDisplay.getDpi());
-        final Rectangle containingRect = mWindowState.getContainingFrame();
-
-        Assert.assertEquals("Min width is incorrect", minWidth, containingRect.width);
-        Assert.assertEquals("Min height is incorrect", minHeight, containingRect.height);
-    }
-
-    private void testLayout(
-            int vGravity, int hGravity, boolean fraction) throws Exception {
-        if (!supportsFreeform()) {
-            CLog.logAndDisplay(INFO, "Skipping test: no freeform support");
-            return;
-        }
-
-        final String activityName = (vGravity == GRAVITY_VER_TOP ? "Top" : "Bottom")
-                + (hGravity == GRAVITY_HOR_LEFT ? "Left" : "Right") + "LayoutActivity";
-
-        // Launch in freeform stack
-        launchActivityInStack(activityName, FREEFORM_WORKSPACE_STACK_ID);
-
-        getDisplayAndWindowState(activityName, true);
-
-        final Rectangle containingRect = mWindowState.getContainingFrame();
-        final Rectangle appRect = mDisplay.getAppRect();
-        final int expectedWidthPx, expectedHeightPx;
-        // Evaluate the expected window size in px. If we're using fraction dimensions,
-        // calculate the size based on the app rect size. Otherwise, convert the expected
-        // size in dp to px.
-        if (fraction) {
-            expectedWidthPx = (int) (appRect.width * DEFAULT_WIDTH_FRACTION);
-            expectedHeightPx = (int) (appRect.height * DEFAULT_HEIGHT_FRACTION);
-        } else {
-            final int densityDpi = mDisplay.getDpi();
-            expectedWidthPx = dpToPx(DEFAULT_WIDTH_DP, densityDpi);
-            expectedHeightPx = dpToPx(DEFAULT_HEIGHT_DP, densityDpi);
-        }
-
-        verifyFrameSizeAndPosition(
-                vGravity, hGravity, expectedWidthPx, expectedHeightPx, containingRect, appRect);
-    }
-
-    private void getDisplayAndWindowState(String activityName, boolean checkFocus)
-            throws Exception {
-        final String windowName = getWindowName(activityName);
-
-        mAmWmState.computeState(mDevice, true /* visibleOnly */, new String[] {activityName});
-
-        if (checkFocus) {
-            mAmWmState.assertFocusedWindow("Test window must be the front window.", windowName);
-        } else {
-            mAmWmState.assertVisibility(activityName, true);
-        }
-
-        mAmWmState.getWmState().getMatchingWindowState(windowName, mTempWindowList);
-
-        Assert.assertEquals("Should have exactly one window state for the activity.",
-                1, mTempWindowList.size());
-
-        mWindowState = mTempWindowList.get(0);
-        Assert.assertNotNull("Should have a valid window", mWindowState);
-
-        mDisplay = mAmWmState.getWmState().getDisplay(mWindowState.getDisplayId());
-        Assert.assertNotNull("Should be on a display", mDisplay);
-    }
-
-    private void verifyFrameSizeAndPosition(
-            int vGravity, int hGravity, int expectedWidthPx, int expectedHeightPx,
-            Rectangle containingFrame, Rectangle parentFrame) {
-        Assert.assertEquals("Width is incorrect", expectedWidthPx, containingFrame.width);
-        Assert.assertEquals("Height is incorrect", expectedHeightPx, containingFrame.height);
-
-        if (vGravity == GRAVITY_VER_TOP) {
-            Assert.assertEquals("Should be on the top", parentFrame.y, containingFrame.y);
-        } else if (vGravity == GRAVITY_VER_BOTTOM) {
-            Assert.assertEquals("Should be on the bottom",
-                    parentFrame.y + parentFrame.height, containingFrame.y + containingFrame.height);
-        }
-
-        if (hGravity == GRAVITY_HOR_LEFT) {
-            Assert.assertEquals("Should be on the left", parentFrame.x, containingFrame.x);
-        } else if (hGravity == GRAVITY_HOR_RIGHT){
-            Assert.assertEquals("Should be on the right",
-                    parentFrame.x + parentFrame.width, containingFrame.x + containingFrame.width);
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
deleted file mode 100644
index 7a691ec..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ /dev/null
@@ -1,88 +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.server.cts;
-
-import java.lang.Exception;
-import java.lang.String;
-
-public class ActivityManagerPinnedStackTests extends ActivityManagerTestBase {
-    private static final String PIP_ACTIVITY = "PipActivity";
-    private static final String AUTO_ENTER_PIP_ACTIVITY = "AutoEnterPipActivity";
-    private static final String ALWAYS_FOCUSABLE_PIP_ACTIVITY = "AlwaysFocusablePipActivity";
-    private static final String LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY =
-            "LaunchIntoPinnedStackPipActivity";
-
-    public void testEnterPictureInPictureMode() throws Exception {
-        pinnedStackTester(AUTO_ENTER_PIP_ACTIVITY, AUTO_ENTER_PIP_ACTIVITY, false, false);
-    }
-
-    public void testMoveTopActivityToPinnedStack() throws Exception {
-        pinnedStackTester(PIP_ACTIVITY, PIP_ACTIVITY, true, false);
-    }
-
-    public void testAlwaysFocusablePipActivity() throws Exception {
-        pinnedStackTester(ALWAYS_FOCUSABLE_PIP_ACTIVITY, ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
-    }
-
-    public void testLaunchIntoPinnedStack() throws Exception {
-        pinnedStackTester(
-                LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY, ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
-    }
-
-    private void pinnedStackTester(String startActivity, String topActivityName,
-            boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
-
-        executeShellCommand(getAmStartCmd(startActivity));
-        if (moveTopToPinnedStack) {
-            executeShellCommand(AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND);
-        }
-
-        mAmWmState.waitForValidState(mDevice, true, new String[] {topActivityName},
-                new int[] {PINNED_STACK_ID}, false /* compareTaskAndStackBounds */);
-        mAmWmState.computeState(mDevice, null);
-
-        if (supportsPip()) {
-            final String windowName = getWindowName(topActivityName);
-            mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
-            mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
-            mAmWmState.assertVisibility(topActivityName, true);
-
-            if (isFocusable) {
-                mAmWmState.assertFocusedStack(
-                        "Pinned stack must be the focused stack.", PINNED_STACK_ID);
-                mAmWmState.assertFocusedActivity(
-                        "Pinned activity must be focused activity.", topActivityName);
-                mAmWmState.assertFocusedWindow(
-                        "Pinned window must be focused window.", windowName);
-                // Not checking for resumed state here because PiP overlay can be launched on top
-                // in different task by SystemUI.
-            } else {
-                mAmWmState.assertNotFocusedStack(
-                        "Pinned stack can't be the focused stack.", PINNED_STACK_ID);
-                mAmWmState.assertNotFocusedActivity(
-                        "Pinned activity can't be the focused activity.", topActivityName);
-                mAmWmState.assertNotResumedActivity(
-                        "Pinned activity can't be the resumed activity.", topActivityName);
-                mAmWmState.assertNotFocusedWindow(
-                        "Pinned window can't be focused window.", windowName);
-            }
-        } else {
-            mAmWmState.assertDoesNotContainStack(
-                    "Must not contain pinned stack.", PINNED_STACK_ID);
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
deleted file mode 100644
index 3d68334..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
+++ /dev/null
@@ -1,97 +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.server.cts;
-
-import java.lang.Exception;
-import java.lang.String;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import junit.framework.Assert;
-
-import static com.android.ddmlib.Log.LogLevel.INFO;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-public class ActivityManagerReplaceWindowTests extends ActivityManagerTestBase {
-
-    private static final String SLOW_CREATE_ACTIVITY_NAME = "SlowCreateActivity";
-    private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity";
-
-    private static final String AM_MOVE_TASK = "am stack movetask ";
-
-    private List<String> mTempWindowTokens = new ArrayList();
-
-    public void testReplaceWindow_Dock_Relaunch() throws Exception {
-        testReplaceWindow_Dock(true);
-    }
-
-    public void testReplaceWindow_Dock_NoRelaunch() throws Exception {
-        testReplaceWindow_Dock(false);
-    }
-
-    private void testReplaceWindow_Dock(boolean relaunch) throws Exception {
-        final String activityName =
-                relaunch ? SLOW_CREATE_ACTIVITY_NAME : NO_RELAUNCH_ACTIVITY_NAME;
-        final String windowName = getWindowName(activityName);
-        final String amStartCmd = getAmStartCmd(activityName);
-
-        executeShellCommand(amStartCmd);
-
-        // Sleep 2 seconds, then check if the window is started properly.
-        // SlowCreateActivity will do a sleep inside its onCreate() to simulate a
-        // slow-starting app. So instead of relying on WindowManagerState's
-        // retrying mechanism, we do an explicit sleep to avoid excess spews
-        // from WindowManagerState.
-        if (SLOW_CREATE_ACTIVITY_NAME.equals(activityName)) {
-            Thread.sleep(2000);
-        }
-
-        CLog.logAndDisplay(INFO, "==========Before Docking========");
-        final String oldToken = getWindowToken(windowName, activityName, true);
-
-        // Move to docked stack
-        final int taskId = getActivityTaskId(activityName);
-        final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
-        executeShellCommand(cmd);
-
-        // Sleep 5 seconds, then check if the window is replaced properly.
-        Thread.sleep(5000);
-
-        CLog.logAndDisplay(INFO, "==========After Docking========");
-        final String newToken = getWindowToken(windowName, activityName, false);
-
-        // For both relaunch and not relaunch case, we'd like the window to be kept.
-        Assert.assertEquals("Window replaced while docking.", oldToken, newToken);
-    }
-
-    private String getWindowToken(String windowName, String activityName, boolean visibleOnly)
-            throws Exception {
-        mAmWmState.computeState(mDevice, visibleOnly, new String[] {activityName});
-
-        mAmWmState.assertVisibility(activityName, true);
-
-        mAmWmState.getWmState().getMatchingWindowTokens(windowName, mTempWindowTokens);
-
-        Assert.assertEquals("Should have exactly one window for the activity.",
-                1, mTempWindowTokens.size());
-
-        return mTempWindowTokens.get(0);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
deleted file mode 100644
index d392e00..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
+++ /dev/null
@@ -1,632 +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.server.cts;
-
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
-import java.awt.Rectangle;
-import java.lang.Integer;
-import java.lang.String;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
-import static android.server.cts.ActivityManagerTestBase.HOME_STACK_ID;
-import static android.server.cts.StateLogger.log;
-import static android.server.cts.StateLogger.logE;
-
-class ActivityManagerState {
-    private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity activities";
-
-    // Copied from ActivityRecord.java
-    private static final int APPLICATION_ACTIVITY_TYPE = 0;
-    private static final int HOME_ACTIVITY_TYPE = 1;
-    private static final int RECENTS_ACTIVITY_TYPE = 2;
-
-    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 mFocusedStackPattern =
-            Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)");
-
-    private final Pattern[] mExtractStackExitPatterns =
-            { mStackIdPattern, mFocusedActivityPattern, 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 final List<String> mResumedActivities = new ArrayList();
-    private final LinkedList<String> mSysDump = new LinkedList();
-
-    void computeState(ITestDevice device) throws DeviceNotAvailableException {
-        // It is possible the system is in the middle of transition to the right state when we get
-        // the dump. We try a few times to get the information we need before giving up.
-        int retriesLeft = 3;
-        boolean retry = false;
-        String dump = null;
-
-        log("==============================");
-        log("     ActivityManagerState     ");
-        log("==============================");
-
-        do {
-            if (retry) {
-                log("***Incomplete AM state. Retrying...");
-                // Wait half a second between retries for activity manager to finish transitioning.
-                try {
-                    Thread.sleep(500);
-                } catch (InterruptedException e) {
-                    log(e.toString());
-                    // Well I guess we are not waiting...
-                }
-            }
-
-            final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-            device.executeShellCommand(DUMPSYS_ACTIVITY_ACTIVITIES, outputReceiver);
-            dump = outputReceiver.getOutput();
-            parseSysDump(dump);
-
-            retry = mStacks.isEmpty() || mFocusedStackId == -1 || mFocusedActivityRecord == null
-                    || mResumedActivities.isEmpty();
-        } while (retry && retriesLeft-- > 0);
-
-        if (retry) {
-            log(dump);
-        }
-
-        if (mStacks.isEmpty()) {
-            logE("No stacks found...");
-        }
-        if (mFocusedStackId == -1) {
-            logE("No focused stack found...");
-        }
-        if (mFocusedActivityRecord == null) {
-            logE("No focused activity found...");
-        }
-        if (mResumedActivities.isEmpty()) {
-            logE("No resumed activities found...");
-        }
-    }
-
-    private void parseSysDump(String sysDump) {
-        reset();
-
-        Collections.addAll(mSysDump, sysDump.split("\\n"));
-
-        int currentDisplayId = 0;
-        while (!mSysDump.isEmpty()) {
-            final ActivityStack stack = ActivityStack.create(mSysDump, mStackIdPattern,
-                    mExtractStackExitPatterns, currentDisplayId);
-
-            if (stack != null) {
-                mStacks.add(stack);
-                if (stack.mResumedActivity != null) {
-                    mResumedActivities.add(stack.mResumedActivity);
-                }
-                continue;
-            }
-
-            final String line = mSysDump.pop().trim();
-
-            Matcher matcher = mFocusedStackPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String stackId = matcher.group(2);
-                log(stackId);
-                mFocusedStackId = Integer.parseInt(stackId);
-                continue;
-            }
-
-            matcher = mFocusedActivityPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                mFocusedActivityRecord = matcher.group(3);
-                log(mFocusedActivityRecord);
-                continue;
-            }
-
-            matcher = mDisplayIdPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String displayId = matcher.group(2);
-                log(displayId);
-                currentDisplayId = Integer.parseInt(displayId);
-            }
-        }
-    }
-
-    private void reset() {
-        mStacks.clear();
-        mFocusedStackId = -1;
-        mFocusedActivityRecord = null;
-        mResumedActivities.clear();
-        mSysDump.clear();
-    }
-
-    int getFrontStackId() {
-        return mStacks.get(0).mStackId;
-    }
-
-    int getFocusedStackId() {
-        return mFocusedStackId;
-    }
-
-    String getFocusedActivity() {
-        return mFocusedActivityRecord;
-    }
-
-    String getResumedActivity() {
-        return mResumedActivities.get(0);
-    }
-
-    int getResumedActivitiesCount() {
-        return mResumedActivities.size();
-    }
-
-    boolean containsStack(int stackId) {
-        return getStackById(stackId) != null;
-    }
-
-    ActivityStack getStackById(int stackId) {
-        for (ActivityStack stack : mStacks) {
-            if (stackId == stack.mStackId) {
-                return stack;
-            }
-        }
-        return null;
-    }
-
-    List<ActivityStack> getStacks() {
-        return new ArrayList(mStacks);
-    }
-
-    int getStackCount() {
-        return mStacks.size();
-    }
-
-    boolean isActivityVisible(String activityName) {
-        for (ActivityStack stack : mStacks) {
-            for (ActivityTask task : stack.mTasks) {
-               for (Activity activity : task.mActivities) {
-                   if (activity.name.equals(activityName)) {
-                       return activity.visible;
-                   }
-               }
-            }
-        }
-        return false;
-    }
-
-    boolean isHomeActivityVisible() {
-        final Activity homeActivity = getHomeActivity();
-        return homeActivity != null && homeActivity.visible;
-    }
-
-    private Activity getHomeActivity() {
-        for (ActivityStack stack : mStacks) {
-            if (stack.mStackId != HOME_STACK_ID) {
-                continue;
-            }
-
-            for (ActivityTask task : stack.mTasks) {
-                if (task.mTaskType != HOME_ACTIVITY_TYPE) {
-                    continue;
-                }
-                return task.mActivities.get(task.mActivities.size() - 1);
-            }
-
-            return null;
-        }
-        return null;
-    }
-
-    ActivityTask getTaskByActivityName(String activityName) {
-        return getTaskByActivityName(activityName, -1);
-    }
-
-    ActivityTask getTaskByActivityName(String activityName, int stackId) {
-        String fullName = ActivityManagerTestBase.getActivityComponentName(activityName);
-        for (ActivityStack stack : mStacks) {
-            if (stackId == -1 || stackId == stack.mStackId) {
-                for (ActivityTask task : stack.mTasks) {
-                    for (Activity activity : task.mActivities) {
-                        if (activity.name.equals(fullName)) {
-                            return task;
-                        }
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    static class ActivityStack extends ActivityContainer {
-
-        private static final Pattern TASK_ID_PATTERN = Pattern.compile("Task id #(\\d+)");
-        private static final Pattern RESUMED_ACTIVITY_PATTERN = Pattern.compile(
-                "mResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
-
-        int mDisplayId;
-        int mStackId;
-        String mResumedActivity;
-        ArrayList<ActivityTask> mTasks = new ArrayList();
-
-        private ActivityStack() {
-        }
-
-        static ActivityStack create(LinkedList<String> dump, Pattern stackIdPattern,
-                                    Pattern[] exitPatterns, int displayId) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = stackIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a stack.
-                return null;
-            }
-            // For the stack Id line we just read.
-            dump.pop();
-
-            final ActivityStack stack = new ActivityStack();
-            stack.mDisplayId = displayId;
-            log(line);
-            final String stackId = matcher.group(1);
-            log(stackId);
-            stack.mStackId = Integer.parseInt(stackId);
-            stack.extract(dump, exitPatterns);
-            return stack;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
-            final List<Pattern> taskExitPatterns = new ArrayList();
-            Collections.addAll(taskExitPatterns, exitPatterns);
-            taskExitPatterns.add(TASK_ID_PATTERN);
-            taskExitPatterns.add(RESUMED_ACTIVITY_PATTERN);
-            final Pattern[] taskExitPatternsArray =
-                    taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
-
-            while (!doneExtracting(dump, exitPatterns)) {
-                final ActivityTask task =
-                        ActivityTask.create(dump, TASK_ID_PATTERN, taskExitPatternsArray);
-
-                if (task != null) {
-                    mTasks.add(task);
-                    continue;
-                }
-
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-
-                Matcher matcher = RESUMED_ACTIVITY_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    mResumedActivity = matcher.group(3);
-                    log(mResumedActivity);
-                    continue;
-                }
-            }
-        }
-
-        List<ActivityTask> getTasks() {
-            return new ArrayList(mTasks);
-        }
-
-        ActivityTask getTask(int taskId) {
-            for (ActivityTask task : mTasks) {
-                if (taskId == task.mTaskId) {
-                    return task;
-                }
-            }
-            return null;
-        }
-    }
-
-    static class ActivityTask extends ActivityContainer {
-        private static final Pattern TASK_RECORD_PATTERN = Pattern.compile("\\* TaskRecord\\"
-                + "{(\\S+) #(\\d+) (\\S+)=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}");
-
-        private static final Pattern LAST_NON_FULLSCREEN_BOUNDS_PATTERN = Pattern.compile(
-                "mLastNonFullscreenBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)");
-
-        private static final Pattern ORIG_ACTIVITY_PATTERN = Pattern.compile("origActivity=(\\S+)");
-        private static final Pattern REAL_ACTIVITY_PATTERN = Pattern.compile("realActivity=(\\S+)");
-
-        private static final Pattern ACTIVITY_NAME_PATTERN = Pattern.compile(
-                "\\* Hist #(\\d+)\\: ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}");
-
-        private static final Pattern TASK_TYPE_PATTERN = Pattern.compile("autoRemoveRecents=(\\S+) "
-                + "isPersistable=(\\S+) numFullscreen=(\\d+) taskType=(\\d+) "
-                + "mTaskToReturnTo=(\\d+)");
-
-        int mTaskId;
-        int mStackId;
-        Rectangle mLastNonFullscreenBounds;
-        String mRealActivity;
-        String mOrigActivity;
-        ArrayList<Activity> mActivities = new ArrayList();
-        int mTaskType = -1;
-        int mReturnToType = -1;
-
-        private ActivityTask() {
-        }
-
-        static ActivityTask create(
-                LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = taskIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a task.
-                return null;
-            }
-            // For the task Id line we just read.
-            dump.pop();
-
-            final ActivityTask task = new ActivityTask();
-            log(line);
-            final String taskId = matcher.group(1);
-            log(taskId);
-            task.mTaskId = Integer.parseInt(taskId);
-            task.extract(dump, exitPatterns);
-            return task;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            final List<Pattern> activityExitPatterns = new ArrayList();
-            Collections.addAll(activityExitPatterns, exitPatterns);
-            activityExitPatterns.add(ACTIVITY_NAME_PATTERN);
-            final Pattern[] activityExitPatternsArray =
-                    activityExitPatterns.toArray(new Pattern[activityExitPatterns.size()]);
-
-            while (!doneExtracting(dump, exitPatterns)) {
-                final Activity activity =
-                        Activity.create(dump, ACTIVITY_NAME_PATTERN, activityExitPatternsArray);
-
-                if (activity != null) {
-                    mActivities.add(activity);
-                    continue;
-                }
-
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-
-                if (extractMinimalSize(line)) {
-                    continue;
-                }
-
-                Matcher matcher = TASK_RECORD_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    final String stackId = matcher.group(6);
-                    mStackId = Integer.valueOf(stackId);
-                    log(stackId);
-                    continue;
-                }
-
-                matcher = LAST_NON_FULLSCREEN_BOUNDS_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    mLastNonFullscreenBounds = extractBounds(matcher);
-                }
-
-                matcher = REAL_ACTIVITY_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    if (mRealActivity == null) {
-                        log(line);
-                        mRealActivity = matcher.group(1);
-                        log(mRealActivity);
-                    }
-                    continue;
-                }
-
-                matcher = ORIG_ACTIVITY_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    if (mOrigActivity == null) {
-                        log(line);
-                        mOrigActivity = matcher.group(1);
-                        log(mOrigActivity);
-                    }
-                    continue;
-                }
-
-                matcher = TASK_TYPE_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    mTaskType = Integer.valueOf(matcher.group(4));
-                    mReturnToType = Integer.valueOf(matcher.group(5));
-                    continue;
-                }
-            }
-        }
-    }
-
-    static class Activity {
-        private static final Pattern VISIBILITY_PATTERN = Pattern.compile("keysPaused=(\\S+) "
-                + "inHistory=(\\S+) visible=(\\S+) sleeping=(\\S+) idle=(\\S+) "
-                + "mStartingWindowState=(\\S+)");
-        private static final Pattern FRONT_OF_TASK_PATTERN = Pattern.compile("frontOfTask=(\\S+) "
-                + "task=TaskRecord\\{(\\S+) #(\\d+) A=(\\S+) U=(\\d+) StackId=(\\d+) sz=(\\d+)\\}");
-
-        String name;
-        boolean visible;
-        boolean frontOfTask;
-
-        private Activity() {
-        }
-
-        static Activity create(
-                LinkedList<String> dump, Pattern activityNamePattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = activityNamePattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not an activity.
-                return null;
-            }
-            // For the activity name line we just read.
-            dump.pop();
-
-            final Activity activity = new Activity();
-            log(line);
-            activity.name = matcher.group(4);
-            log(activity.name);
-            activity.extract(dump, exitPatterns);
-            return activity;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                Matcher matcher = VISIBILITY_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    final String visibleString = matcher.group(3);
-                    visible = Boolean.valueOf(visibleString);
-                    log(visibleString);
-                    continue;
-                }
-
-                matcher = FRONT_OF_TASK_PATTERN.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    final String frontOfTaskString = matcher.group(1);
-                    frontOfTask = Boolean.valueOf(frontOfTaskString);
-                    log(frontOfTaskString);
-                    continue;
-                }
-            }
-        }
-    }
-
-    static abstract class ActivityContainer {
-        protected static final Pattern FULLSCREEN_PATTERN = Pattern.compile("mFullscreen=(\\S+)");
-        protected static final Pattern BOUNDS_PATTERN =
-                Pattern.compile("mBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)");
-        protected static final Pattern MIN_WIDTH_PATTERN =
-                Pattern.compile("mMinWidth=(\\d+)");
-        protected static final Pattern MIN_HEIGHT_PATTERN =
-                Pattern.compile("mMinHeight=(\\d+)");
-
-        protected boolean mFullscreen;
-        protected Rectangle mBounds;
-        protected int mMinWidth = -1;
-        protected int mMinHeight = -1;
-
-        boolean extractFullscreen(String line) {
-            final Matcher matcher = FULLSCREEN_PATTERN.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            final String fullscreen = matcher.group(1);
-            log(fullscreen);
-            mFullscreen = Boolean.valueOf(fullscreen);
-            return true;
-        }
-
-        boolean extractBounds(String line) {
-            final Matcher matcher = BOUNDS_PATTERN.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            mBounds = extractBounds(matcher);
-            return true;
-        }
-
-        static Rectangle extractBounds(Matcher matcher) {
-            final int left = Integer.valueOf(matcher.group(1));
-            final int top = Integer.valueOf(matcher.group(2));
-            final int right = Integer.valueOf(matcher.group(3));
-            final int bottom = Integer.valueOf(matcher.group(4));
-            final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
-
-            log(rect.toString());
-            return rect;
-        }
-
-        boolean extractMinimalSize(String line) {
-            final Matcher minWidthMatcher = MIN_WIDTH_PATTERN.matcher(line);
-            final Matcher minHeightMatcher = MIN_HEIGHT_PATTERN.matcher(line);
-
-            if (minWidthMatcher.matches()) {
-                log(line);
-                mMinWidth = Integer.valueOf(minWidthMatcher.group(1));
-            } else if (minHeightMatcher.matches()) {
-                log(line);
-                mMinHeight = Integer.valueOf(minHeightMatcher.group(1));
-            } else {
-                return false;
-            }
-            return true;
-        }
-
-        Rectangle getBounds() {
-            return mBounds;
-        }
-
-        boolean isFullscreen() {
-            return mFullscreen;
-        }
-
-        int getMinWidth() {
-            return mMinWidth;
-        }
-
-        int getMinHeight() {
-            return mMinHeight;
-        }
-    }
-
-    static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
-        if (dump.isEmpty()) {
-            return true;
-        }
-        final String line = dump.peek().trim();
-
-        for (Pattern pattern : exitPatterns) {
-            if (pattern.matcher(line).matches()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
deleted file mode 100644
index 735a303..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTestBase.java
+++ /dev/null
@@ -1,553 +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.server.cts;
-
-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 java.lang.Exception;
-import java.lang.Integer;
-import java.lang.String;
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static android.server.cts.StateLogger.log;
-
-public abstract class ActivityManagerTestBase extends DeviceTestCase {
-    private static final boolean PRETEND_DEVICE_SUPPORTS_PIP = false;
-    private static final boolean PRETEND_DEVICE_SUPPORTS_FREEFORM = false;
-    private static final boolean PRETEND_DEVICE_SUPPORTS_DOCKING = false;
-    private static final boolean PRETEND_DEVICE_SUPPORTS_ROTATION = false;
-
-    // Constants copied from ActivityManager.StackId. If they are changed there, these must be
-    // updated.
-    /** First static stack ID. */
-    public static final int FIRST_STATIC_STACK_ID = 0;
-
-    /** Home activity stack ID. */
-    public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
-
-    /** ID of stack where fullscreen activities are normally launched into. */
-    public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
-
-    /** ID of stack where freeform/resized activities are normally launched into. */
-    public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
-
-    /** ID of stack that occupies a dedicated region of the screen. */
-    public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
-
-    /** ID of stack that always on top (always visible) when it exist. */
-    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
-
-    private static final String TASK_ID_PREFIX = "taskId";
-
-    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_REMOVE_STACK = "am stack remove ";
-
-    protected static final String AM_START_HOME_ACTIVITY_COMMAND =
-            "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
-
-    protected static final String AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND =
-            "am stack move-top-activity-to-pinned-stack 1 0 0 500 500";
-
-    protected static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
-
-    private static final String AM_RESIZE_DOCKED_STACK = "am stack resize-docked-stack ";
-
-    private static final String AM_MOVE_TASK = "am stack movetask ";
-
-    private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
-
-    /** A reference to the device under test. */
-    protected ITestDevice mDevice;
-
-    private HashSet<String> mAvailableFeatures;
-
-    protected static String getAmStartCmd(final String activityName) {
-        return "am start -n " + getActivityComponentName(activityName);
-    }
-
-    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;
-    }
-
-    static String getWindowName(final String activityName) {
-        return "android.server.app/android.server.app." + activityName;
-    }
-
-    protected ActivityAndWindowManagersState mAmWmState = new ActivityAndWindowManagersState();
-
-    private int mInitialAccelerometerRotation;
-    private int mUserRotation;
-    private float mFontScale;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        // Get the device, this gives a handle to run commands and install APKs.
-        mDevice = getDevice();
-        unlockDevice();
-        // Remove special stacks.
-        executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
-        executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
-        executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
-        // Store rotation settings.
-        mInitialAccelerometerRotation = getAccelerometerRotation();
-        mUserRotation = getUserRotation();
-        mFontScale = getFontScale();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        try {
-            unlockDevice();
-            executeShellCommand(AM_FORCE_STOP_TEST_PACKAGE);
-            // Restore rotation settings to the state they were before test.
-            setAccelerometerRotation(mInitialAccelerometerRotation);
-            setUserRotation(mUserRotation);
-            setFontScale(mFontScale);
-            // Remove special stacks.
-            executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
-            executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
-            executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
-        } catch (DeviceNotAvailableException e) {
-        }
-    }
-
-    protected String executeShellCommand(String command) throws DeviceNotAvailableException {
-        log("adb shell " + command);
-        return mDevice.executeShellCommand(command);
-    }
-
-    protected void executeShellCommand(String command, CollectingOutputReceiver outputReceiver)
-            throws DeviceNotAvailableException {
-        log("adb shell " + command);
-        mDevice.executeShellCommand(command, outputReceiver);
-    }
-
-    /**
-     * Launch specific target activity. It uses existing instance of {@link #LAUNCHING_ACTIVITY}, so
-     * that one should be started first.
-     * @param toSide Launch to side in split-screen.
-     * @param randomData Make intent URI random by generating random data.
-     * @param multipleTask Allow multiple task launch.
-     * @param targetActivityName Target activity to be launched. Only class name should be provided,
-     *                           package name of {@link #LAUNCHING_ACTIVITY} will be added
-     *                           automatically.
-     * @throws Exception
-     */
-    protected void launchActivity(boolean toSide, boolean randomData, boolean multipleTask,
-            String targetActivityName) throws Exception {
-        StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(LAUNCHING_ACTIVITY));
-        commandBuilder.append(" -f 0x20000000");
-        if (toSide) {
-            commandBuilder.append(" --ez launch_to_the_side true");
-        }
-        if (randomData) {
-            commandBuilder.append(" --ez random_data true");
-        }
-        if (multipleTask) {
-            commandBuilder.append(" --ez multiple_task true");
-        }
-        if (targetActivityName != null) {
-            commandBuilder.append(" --es target_activity ").append(targetActivityName);
-        }
-        executeShellCommand(commandBuilder.toString());
-    }
-
-    protected void launchActivityInStack(String activityName, int stackId) throws Exception {
-        executeShellCommand(getAmStartCmd(activityName) + " --stack " + stackId);
-    }
-
-    protected void launchActivityInDockStack(String activityName) throws Exception {
-        executeShellCommand(getAmStartCmd(activityName));
-        moveActivityToDockStack(activityName);
-    }
-
-    protected void launchActivityToSide(boolean randomData, boolean multipleTaskFlag,
-            String targetActivity) throws Exception {
-        launchActivity(true /* toSide */, randomData, multipleTaskFlag, targetActivity);
-    }
-
-    protected void moveActivityToDockStack(String activityName) throws Exception {
-        moveActivityToStack(activityName, DOCKED_STACK_ID);
-    }
-
-    protected void moveActivityToStack(String activityName, int stackId) throws Exception {
-        final int taskId = getActivityTaskId(activityName);
-        final String cmd = AM_MOVE_TASK + taskId + " " + stackId + " true";
-        executeShellCommand(cmd);
-    }
-
-    protected void resizeActivityTask(String activityName, int left, int top, int right, int bottom)
-            throws Exception {
-        final int taskId = getActivityTaskId(activityName);
-        final String cmd = "am task resize "
-                + taskId + " " + left + " " + top + " " + right + " " + bottom;
-        executeShellCommand(cmd);
-    }
-
-    protected void resizeDockedStack(
-            int stackWidth, int stackHeight, int taskWidth, int taskHeight)
-                    throws DeviceNotAvailableException {
-        executeShellCommand(AM_RESIZE_DOCKED_STACK
-                + "0 0 " + stackWidth + " " + stackHeight
-                + " 0 0 " + taskWidth + " " + taskHeight);
-    }
-
-    protected void pressHomeButton() throws DeviceNotAvailableException {
-        executeShellCommand(INPUT_KEYEVENT_HOME);
-    }
-
-    // Utility method for debugging, not used directly here, but useful, so kept around.
-    protected void printStacksAndTasks() throws DeviceNotAvailableException {
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        executeShellCommand(AM_STACK_LIST, outputReceiver);
-        String output = outputReceiver.getOutput();
-        for (String line : output.split("\\n")) {
-            CLog.logAndDisplay(LogLevel.INFO, line);
-        }
-    }
-
-    protected int getActivityTaskId(String name) throws DeviceNotAvailableException {
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        executeShellCommand(AM_STACK_LIST, outputReceiver);
-        final String output = outputReceiver.getOutput();
-        final Pattern activityPattern = Pattern.compile("(.*) " + getWindowName(name) + " (.*)");
-        for (String line : output.split("\\n")) {
-            Matcher matcher = activityPattern.matcher(line);
-            if (matcher.matches()) {
-                for (String word : line.split("\\s+")) {
-                    if (word.startsWith(TASK_ID_PREFIX)) {
-                        final String withColon = word.split("=")[1];
-                        return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
-                    }
-                }
-            }
-        }
-        return -1;
-    }
-
-    protected boolean supportsPip() throws DeviceNotAvailableException {
-        return hasDeviceFeature("android.software.picture_in_picture")
-                || PRETEND_DEVICE_SUPPORTS_PIP;
-    }
-
-    protected boolean supportsFreeform() throws DeviceNotAvailableException {
-        return hasDeviceFeature("android.software.freeform_window_management")
-                || PRETEND_DEVICE_SUPPORTS_FREEFORM;
-    }
-
-    protected boolean supportsMultiWindowMode() throws DeviceNotAvailableException {
-        return !hasDeviceFeature("android.hardware.type.watch")
-                || PRETEND_DEVICE_SUPPORTS_DOCKING;
-    }
-
-    protected boolean supportsScreenRotation() throws DeviceNotAvailableException {
-        return !hasDeviceFeature("android.hardware.type.watch")
-                || PRETEND_DEVICE_SUPPORTS_ROTATION;
-    }
-
-    protected boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
-        if (mAvailableFeatures == null) {
-            // TODO: Move this logic to ITestDevice.
-            final String output = runCommandAndPrintOutput("pm list features");
-
-            // Extract the id of the new user.
-            mAvailableFeatures = new HashSet<>();
-            for (String feature: output.split("\\s+")) {
-                // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
-                String[] tokens = feature.split(":");
-                assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
-                        tokens.length > 1);
-                assertEquals(feature, "feature", tokens[0]);
-                mAvailableFeatures.add(tokens[1]);
-            }
-        }
-        boolean result = mAvailableFeatures.contains(requiredFeature);
-        if (!result) {
-            CLog.logAndDisplay(LogLevel.INFO, "Device doesn't support " + requiredFeature);
-        }
-        return result;
-    }
-
-    private boolean isDisplayOn() throws DeviceNotAvailableException {
-        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        mDevice.executeShellCommand("dumpsys power", outputReceiver);
-
-        for (String line : outputReceiver.getOutput().split("\\n")) {
-            line = line.trim();
-
-            final Matcher matcher = sDisplayStatePattern.matcher(line);
-            if (matcher.matches()) {
-                final String state = matcher.group(1);
-                log("power state=" + state);
-                return "ON".equals(state);
-            }
-        }
-        log("power state :(");
-        return false;
-    }
-
-    protected void lockDevice() throws DeviceNotAvailableException {
-        int retriesLeft = 5;
-        runCommandAndPrintOutput("input keyevent 26");
-        do {
-            if (isDisplayOn()) {
-                log("***Waiting for display to turn off...");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                    log(e.toString());
-                    // Well I guess we are not waiting...
-                }
-            } else {
-                break;
-            }
-        } while (retriesLeft-- > 0);
-    }
-
-    protected void unlockDevice() throws DeviceNotAvailableException {
-        if (!isDisplayOn()) {
-            runCommandAndPrintOutput("input keyevent 224");
-            runCommandAndPrintOutput("input keyevent 82");
-        }
-    }
-
-    protected void setDeviceRotation(int rotation) throws DeviceNotAvailableException {
-        setAccelerometerRotation(0);
-        setUserRotation(rotation);
-    }
-
-    private int getAccelerometerRotation() throws DeviceNotAvailableException {
-        final String rotation =
-                runCommandAndPrintOutput("settings get system accelerometer_rotation");
-        return Integer.parseInt(rotation.trim());
-    }
-
-    private void setAccelerometerRotation(int rotation) throws DeviceNotAvailableException {
-        runCommandAndPrintOutput(
-                "settings put system accelerometer_rotation " + rotation);
-    }
-
-    private int getUserRotation() throws DeviceNotAvailableException {
-        final String rotation =
-                runCommandAndPrintOutput("settings get system user_rotation").trim();
-        if ("null".equals(rotation)) {
-            return -1;
-        }
-        return Integer.parseInt(rotation);
-    }
-
-    private void setUserRotation(int rotation) throws DeviceNotAvailableException {
-        if (rotation == -1) {
-            runCommandAndPrintOutput(
-                    "settings delete system user_rotation");
-        } else {
-            runCommandAndPrintOutput(
-                    "settings put system user_rotation " + rotation);
-        }
-    }
-
-    protected void setFontScale(float fontScale) throws DeviceNotAvailableException {
-        if (fontScale == 0.0f) {
-            runCommandAndPrintOutput(
-                    "settings delete system font_scale");
-        } else {
-            runCommandAndPrintOutput(
-                    "settings put system font_scale " + fontScale);
-        }
-    }
-
-    protected float getFontScale() throws DeviceNotAvailableException {
-        try {
-            final String fontScale =
-                    runCommandAndPrintOutput("settings get system font_scale").trim();
-            return Float.parseFloat(fontScale);
-        } catch (NumberFormatException e) {
-            // If we don't have a valid font scale key, return 0.0f now so
-            // that we delete the key in tearDown().
-            return 0.0f;
-        }
-    }
-
-    protected String runCommandAndPrintOutput(String command) throws DeviceNotAvailableException {
-        final String output = executeShellCommand(command);
-        log(output);
-        return output;
-    }
-
-    protected void clearLogcat() throws DeviceNotAvailableException {
-        mDevice.executeAdbCommand("logcat", "-c");
-    }
-
-    protected void assertActivityLifecycle(String activityName, boolean relaunched)
-            throws DeviceNotAvailableException {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
-
-        if (relaunched) {
-            if (lifecycleCounts.mDestroyCount < 1) {
-                fail(activityName + " must have been destroyed. mDestroyCount="
-                        + lifecycleCounts.mDestroyCount);
-            }
-            if (lifecycleCounts.mCreateCount < 1) {
-                fail(activityName + " must have been (re)created. mCreateCount="
-                        + lifecycleCounts.mCreateCount);
-            }
-        } else {
-            if (lifecycleCounts.mDestroyCount > 0) {
-                fail(activityName + " must *NOT* have been destroyed. mDestroyCount="
-                        + lifecycleCounts.mDestroyCount);
-            }
-            if (lifecycleCounts.mCreateCount > 0) {
-                fail(activityName + " must *NOT* have been (re)created. mCreateCount="
-                        + lifecycleCounts.mCreateCount);
-            }
-            if (lifecycleCounts.mConfigurationChangedCount < 1) {
-                fail(activityName + " must have received configuration changed. "
-                        + "mConfigurationChangedCount="
-                        + lifecycleCounts.mConfigurationChangedCount);
-            }
-        }
-    }
-
-    protected void assertRelaunchOrConfigChanged(
-            String activityName, int numRelaunch, int numConfigChange)
-            throws DeviceNotAvailableException {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
-
-        if (lifecycleCounts.mDestroyCount != numRelaunch) {
-            fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
-                    + " time(s), expecting " + numRelaunch);
-        } else if (lifecycleCounts.mCreateCount != numRelaunch) {
-            fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
-                    + " time(s), expecting " + numRelaunch);
-        } else if (lifecycleCounts.mConfigurationChangedCount != numConfigChange) {
-            fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
-                    + " onConfigurationChanged() calls, expecting " + numConfigChange);
-        }
-    }
-
-    protected String[] getDeviceLogsForComponent(String componentName)
-            throws DeviceNotAvailableException {
-        return mDevice.executeAdbCommand(
-                "logcat", "-v", "brief", "-d", componentName + ":I", "*:S").split("\\n");
-    }
-
-    protected String[] getDeviceLogsForComponents(final String[] componentNames)
-            throws DeviceNotAvailableException {
-        String filters = "";
-        for (int i = 0; i < componentNames.length; i++) {
-            filters += componentNames[i] + ":I ";
-        }
-        return mDevice.executeAdbCommand(
-                "logcat", "-v", "brief", "-d", filters, "*:S").split("\\n");
-    }
-
-    private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
-    private static final Pattern sConfigurationChangedPattern =
-            Pattern.compile("(.+): onConfigurationChanged");
-    private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
-    private static final Pattern sNewConfigPattern = Pattern.compile(
-            "(.+): config size=\\((\\d+),(\\d+)\\) displaySize=\\((\\d+),(\\d+)\\)" +
-            " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+)");
-    private static final Pattern sDisplayStatePattern =
-            Pattern.compile("Display Power: state=(.+)");
-
-    protected class ReportedSizes {
-        int widthDp;
-        int heightDp;
-        int displayWidth;
-        int displayHeight;
-        int metricsWidth;
-        int metricsHeight;
-        int smallestWidthDp;
-
-        @Override
-        public String toString() {
-            return "ReportedSizes: {widthDp=" + widthDp + " heightDp=" + heightDp +
-                    " displayWidth=" + displayWidth + " displayHeight=" + displayHeight +
-                    " metricsWidth=" + metricsWidth + " metricsHeight=" + metricsHeight +
-                    " smallestWidthDp=" + smallestWidthDp + "}";
-        }
-    }
-
-    protected ReportedSizes getLastReportedSizesForActivity(String activityName)
-            throws DeviceNotAvailableException {
-        final String[] lines = getDeviceLogsForComponent(activityName);
-        for (int i = lines.length - 1; i >= 0; i--) {
-            final String line = lines[i].trim();
-            final Matcher matcher = sNewConfigPattern.matcher(line);
-            if (matcher.matches()) {
-                ReportedSizes details = new ReportedSizes();
-                details.widthDp = Integer.parseInt(matcher.group(2));
-                details.heightDp = Integer.parseInt(matcher.group(3));
-                details.displayWidth = Integer.parseInt(matcher.group(4));
-                details.displayHeight = Integer.parseInt(matcher.group(5));
-                details.metricsWidth = Integer.parseInt(matcher.group(6));
-                details.metricsHeight = Integer.parseInt(matcher.group(7));
-                details.smallestWidthDp = Integer.parseInt(matcher.group(8));
-                return details;
-            }
-        }
-        return null;
-    }
-
-    private class ActivityLifecycleCounts {
-        int mCreateCount;
-        int mConfigurationChangedCount;
-        int mDestroyCount;
-
-        public ActivityLifecycleCounts(String activityName) throws DeviceNotAvailableException {
-            for (String line : getDeviceLogsForComponent(activityName)) {
-                line = line.trim();
-
-                Matcher matcher = sCreatePattern.matcher(line);
-                if (matcher.matches()) {
-                    mCreateCount++;
-                    continue;
-                }
-
-                matcher = sConfigurationChangedPattern.matcher(line);
-                if (matcher.matches()) {
-                    mConfigurationChangedCount++;
-                    continue;
-                }
-
-                matcher = sDestroyPattern.matcher(line);
-                if (matcher.matches()) {
-                    mDestroyCount++;
-                    continue;
-                }
-            }
-        }
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java b/hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java
deleted file mode 100644
index 4dbb704..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/DisplaySizeTest.java
+++ /dev/null
@@ -1,171 +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.server.cts;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-
-/**
- * Ensure that compatibility dialog is shown when launching an application with
- * an unsupported smallest width.
- */
-public class DisplaySizeTest extends DeviceTestCase {
-    private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density";
-    private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density";
-
-    private static final String AM_START_COMMAND = "am start -n %s/%s.%s";
-    private static final String AM_FORCE_STOP = "am force-stop %s";
-
-    private static final int ACTIVITY_TIMEOUT_MILLIS = 1000;
-    private static final int WINDOW_TIMEOUT_MILLIS = 1000;
-
-    private ITestDevice mDevice;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mDevice = getDevice();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        try {
-            resetDensity();
-
-            // Ensure app process is stopped.
-            forceStopPackage("android.displaysize.app");
-            forceStopPackage("android.server.app");
-        } catch (DeviceNotAvailableException e) {
-            // Do nothing.
-        }
-    }
-
-    public void testCompatibilityDialog() throws Exception {
-        // Launch some other app (not to perform density change on launcher).
-        startActivity("android.server.app", "TestActivity");
-        verifyWindowDisplayed("TestActivity", ACTIVITY_TIMEOUT_MILLIS);
-
-        setUnsupportedDensity();
-
-        // Launch target app.
-        startActivity("android.displaysize.app", "SmallestWidthActivity");
-        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
-        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
-    }
-
-    public void testCompatibilityDialogWhenFocused() throws Exception {
-        startActivity("android.displaysize.app", "SmallestWidthActivity");
-        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
-
-        setUnsupportedDensity();
-
-        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
-    }
-
-    public void testCompatibilityDialogAfterReturn() throws Exception {
-        // Launch target app.
-        startActivity("android.displaysize.app", "SmallestWidthActivity");
-        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
-        // Launch another activity.
-        startOtherActivityOnTop("android.displaysize.app", "SmallestWidthActivity");
-        verifyWindowDisplayed("TestActivity", ACTIVITY_TIMEOUT_MILLIS);
-
-        setUnsupportedDensity();
-
-        // Go back.
-        mDevice.executeShellCommand("input keyevent 4");
-
-        verifyWindowDisplayed("SmallestWidthActivity", ACTIVITY_TIMEOUT_MILLIS);
-        verifyWindowDisplayed("UnsupportedDisplaySizeDialog", WINDOW_TIMEOUT_MILLIS);
-    }
-
-    private void setUnsupportedDensity() throws DeviceNotAvailableException {
-        // Set device to 0.85 zoom. It doesn't matter that we're zooming out
-        // since the feature verifies that we're in a non-default density.
-        final int stableDensity = getStableDensity();
-        final int targetDensity = (int) (stableDensity * 0.85);
-        setDensity(targetDensity);
-    }
-
-    private int getStableDensity() {
-        try {
-            final String densityProp;
-            if (mDevice.getSerialNumber().startsWith("emulator-")) {
-                densityProp = DENSITY_PROP_EMULATOR;
-            } else {
-                densityProp = DENSITY_PROP_DEVICE;
-            }
-
-            return Integer.parseInt(mDevice.getProperty(densityProp));
-        } catch (DeviceNotAvailableException e) {
-            return 0;
-        }
-    }
-
-    private void setDensity(int targetDensity) throws DeviceNotAvailableException {
-        mDevice.executeShellCommand("wm density " + targetDensity);
-
-        // Verify that the density is changed.
-        final String output = mDevice.executeShellCommand("wm density");
-        final boolean success = output.contains("Override density: " + targetDensity);
-
-        assertTrue("Failed to set density to " + targetDensity, success);
-    }
-
-    private void resetDensity() throws DeviceNotAvailableException {
-        mDevice.executeShellCommand("wm density reset");
-    }
-
-    private void forceStopPackage(String packageName) throws DeviceNotAvailableException {
-        final String forceStopCmd = String.format(AM_FORCE_STOP, packageName);
-        mDevice.executeShellCommand(forceStopCmd);
-    }
-
-    private void startActivity(String packageName, String activityName)
-            throws DeviceNotAvailableException {
-        mDevice.executeShellCommand(getStartCommand(packageName, activityName));
-    }
-
-    private void startOtherActivityOnTop(String packageName, String activityName)
-            throws DeviceNotAvailableException {
-        final String startCmd = getStartCommand(packageName, activityName)
-                + " -f 0x20000000 --ez launch_another_activity true";
-        mDevice.executeShellCommand(startCmd);
-    }
-
-    private String getStartCommand(String packageName, String activityName) {
-        return String.format(AM_START_COMMAND, packageName, packageName, activityName);
-    }
-
-    private void verifyWindowDisplayed(String windowName, long timeoutMillis)
-            throws DeviceNotAvailableException {
-        boolean success = false;
-
-        // Verify that compatibility dialog is shown within 1000ms.
-        final long timeoutTimeMillis = System.currentTimeMillis() + timeoutMillis;
-        while (!success && System.currentTimeMillis() < timeoutTimeMillis) {
-            final String output = mDevice.executeShellCommand("dumpsys window");
-            success = output.contains(windowName);
-        }
-
-        assertTrue(windowName + " was not displayed", success);
-    }
-}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
deleted file mode 100644
index a057013..0000000
--- a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
+++ /dev/null
@@ -1,706 +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.server.cts;
-
-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 java.awt.Rectangle;
-import java.lang.String;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
-import static android.server.cts.StateLogger.log;
-import static android.server.cts.StateLogger.logE;
-
-class WindowManagerState {
-    private static final String DUMPSYS_WINDOWS_APPS = "dumpsys window apps";
-    private static final String DUMPSYS_WINDOWS_VISIBLE_APPS = "dumpsys window visible-apps";
-
-    private static final Pattern sWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:");
-    private static final Pattern sStartingWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Starting (.+)\\}\\:");
-    private static final Pattern sExitingWindowPattern =
-            Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+) EXITING\\}\\:");
-
-    private static final Pattern sFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) (\\S+)\\}");
-    private static final Pattern sAppErrorFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Application Error\\: (\\S+)\\}");
-    private static final Pattern sWaitingForDebuggerFocusedWindowPattern = Pattern.compile(
-            "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger\\: (\\S+)\\}");
-
-    private static final Pattern sFocusedAppPattern =
-            Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) "
-                    + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)");
-
-    private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
-
-    private static final Pattern[] sExtractStackExitPatterns = {
-            sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
-            sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
-            sWaitingForDebuggerFocusedWindowPattern, sFocusedAppPattern };
-
-    // Windows in z-order with the top most at the front of the list.
-    private List<String> mWindows = new ArrayList();
-    private List<WindowState> mWindowStates = new ArrayList();
-    private List<WindowStack> mStacks = new ArrayList();
-    private List<Display> mDisplays = new ArrayList();
-    private String mFocusedWindow = null;
-    private String mFocusedApp = null;
-    private final LinkedList<String> mSysDump = new LinkedList();
-
-    void computeState(ITestDevice device, boolean visibleOnly) throws DeviceNotAvailableException {
-        // It is possible the system is in the middle of transition to the right state when we get
-        // the dump. We try a few times to get the information we need before giving up.
-        int retriesLeft = 3;
-        boolean retry = false;
-        String dump = null;
-
-        log("==============================");
-        log("      WindowManagerState      ");
-        log("==============================");
-        do {
-            if (retry) {
-                log("***Incomplete WM state. Retrying...");
-                // Wait half a second between retries for window manager to finish transitioning...
-                try {
-                    Thread.sleep(500);
-                } catch (InterruptedException e) {
-                    log(e.toString());
-                    // Well I guess we are not waiting...
-                }
-            }
-
-            final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-            final String dumpsysCmd = visibleOnly ?
-                    DUMPSYS_WINDOWS_VISIBLE_APPS : DUMPSYS_WINDOWS_APPS;
-            device.executeShellCommand(dumpsysCmd, outputReceiver);
-            dump = outputReceiver.getOutput();
-            parseSysDump(dump, visibleOnly);
-
-            retry = mWindows.isEmpty() || mFocusedWindow == null || mFocusedApp == null;
-        } while (retry && retriesLeft-- > 0);
-
-        if (retry) {
-            log(dump);
-        }
-
-        if (mWindows.isEmpty()) {
-            logE("No Windows found...");
-        }
-        if (mFocusedWindow == null) {
-            logE("No Focused Window...");
-        }
-        if (mFocusedApp == null) {
-            logE("No Focused App...");
-        }
-    }
-
-    private void parseSysDump(String sysDump, boolean visibleOnly) {
-        reset();
-
-        Collections.addAll(mSysDump, sysDump.split("\\n"));
-
-        while (!mSysDump.isEmpty()) {
-            final Display display =
-                    Display.create(mSysDump, sExtractStackExitPatterns);
-            if (display != null) {
-                log(display.toString());
-                mDisplays.add(display);
-                continue;
-            }
-
-            final WindowStack stack =
-                    WindowStack.create(mSysDump, sStackIdPattern, sExtractStackExitPatterns);
-
-            if (stack != null) {
-                mStacks.add(stack);
-                continue;
-            }
-
-
-            final WindowState ws = WindowState.create(mSysDump, sExtractStackExitPatterns);
-            if (ws != null) {
-                log(ws.toString());
-
-                if (visibleOnly) {
-                    // Check to see if we are in the middle of transitioning. If we are, we want to
-                    // skip dumping until window manager is done transitioning windows.
-                    if (ws.isStartingWindow()) {
-                        log("Skipping dump due to starting window transition...");
-                        return;
-                    }
-
-                    if (ws.isExitingWindow()) {
-                        log("Skipping dump due to exiting window transition...");
-                        return;
-                    }
-                }
-
-                mWindows.add(ws.getName());
-                mWindowStates.add(ws);
-                continue;
-            }
-
-            final String line = mSysDump.pop().trim();
-
-            Matcher matcher = sFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sAppErrorFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sWaitingForDebuggerFocusedWindowPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedWindow = matcher.group(3);
-                log(focusedWindow);
-                mFocusedWindow = focusedWindow;
-                continue;
-            }
-
-            matcher = sFocusedAppPattern.matcher(line);
-            if (matcher.matches()) {
-                log(line);
-                final String focusedApp = matcher.group(5);
-                log(focusedApp);
-                mFocusedApp = focusedApp;
-                continue;
-            }
-        }
-    }
-
-    void getMatchingWindowTokens(final String windowName, List<String> tokenList) {
-        tokenList.clear();
-
-        for (WindowState ws : mWindowStates) {
-            if (windowName.equals(ws.getName())) {
-                tokenList.add(ws.getToken());
-            }
-        }
-    }
-
-    void getMatchingWindowState(final String windowName, List<WindowState> windowList) {
-        windowList.clear();
-        for (WindowState ws : mWindowStates) {
-            if (windowName.equals(ws.getName())) {
-                windowList.add(ws);
-            }
-        }
-    }
-
-    Display getDisplay(int displayId) {
-        for (Display display : mDisplays) {
-            if (displayId == display.getDisplayId()) {
-                return display;
-            }
-        }
-        return null;
-    }
-
-    String getFrontWindow() {
-        if (mWindows == null || mWindows.isEmpty()) {
-            return null;
-        }
-        return mWindows.get(0);
-    }
-
-    String getFocusedWindow() {
-        return mFocusedWindow;
-    }
-
-    String getFocusedApp() {
-        return mFocusedApp;
-    }
-
-    int getFrontStackId() {
-        return mStacks.get(0).mStackId;
-    }
-
-    boolean containsStack(int stackId) {
-        for (WindowStack stack : mStacks) {
-            if (stackId == stack.mStackId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    boolean isWindowVisible(String windowName) {
-        for (String window : mWindows) {
-            if (window.equals(windowName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    WindowStack getStack(int stackId) {
-        for (WindowStack stack : mStacks) {
-            if (stackId == stack.mStackId) {
-                return stack;
-            }
-        }
-        return null;
-    }
-
-    private void reset() {
-        mSysDump.clear();
-        mStacks.clear();
-        mDisplays.clear();
-        mWindows.clear();
-        mWindowStates.clear();
-        mFocusedWindow = null;
-        mFocusedApp = null;
-    }
-
-    static class WindowStack extends WindowContainer {
-
-        private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)");
-
-        int mStackId;
-        ArrayList<WindowTask> mTasks = new ArrayList();
-
-        private WindowStack() {
-
-        }
-
-        static WindowStack create(
-                LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = stackIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a stack.
-                return null;
-            }
-            // For the stack Id line we just read.
-            dump.pop();
-
-            final WindowStack stack = new WindowStack();
-            log(line);
-            final String stackId = matcher.group(1);
-            log(stackId);
-            stack.mStackId = Integer.parseInt(stackId);
-            stack.extract(dump, exitPatterns);
-            return stack;
-        }
-
-        void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
-            final List<Pattern> taskExitPatterns = new ArrayList();
-            Collections.addAll(taskExitPatterns, exitPatterns);
-            taskExitPatterns.add(sTaskIdPattern);
-            final Pattern[] taskExitPatternsArray =
-                    taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
-
-            while (!doneExtracting(dump, exitPatterns)) {
-                final WindowTask task =
-                        WindowTask.create(dump, sTaskIdPattern, taskExitPatternsArray);
-
-                if (task != null) {
-                    mTasks.add(task);
-                    continue;
-                }
-
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-            }
-        }
-
-        WindowTask getTask(int taskId) {
-            for (WindowTask task : mTasks) {
-                if (taskId == task.mTaskId) {
-                    return task;
-                }
-            }
-            return null;
-        }
-    }
-
-    static class WindowTask extends WindowContainer {
-        private static final Pattern sTempInsetBoundsPattern =
-                Pattern.compile("mTempInsetBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
-
-        private static final Pattern sAppTokenPattern = Pattern.compile(
-                "Activity #(\\d+) AppWindowToken\\{(\\S+) token=Token\\{(\\S+) "
-                + "ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}\\}\\}");
-
-
-        int mTaskId;
-        Rectangle mTempInsetBounds;
-        List<String> mAppTokens = new ArrayList();
-
-        private WindowTask() {
-        }
-
-        static WindowTask create(
-                LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            final Matcher matcher = taskIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                // Not a task.
-                return null;
-            }
-            // For the task Id line we just read.
-            dump.pop();
-
-            final WindowTask task = new WindowTask();
-            log(line);
-            final String taskId = matcher.group(1);
-            log(taskId);
-            task.mTaskId = Integer.parseInt(taskId);
-            task.extract(dump, exitPatterns);
-            return task;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                if (extractFullscreen(line)) {
-                    continue;
-                }
-
-                if (extractBounds(line)) {
-                    continue;
-                }
-
-                Matcher matcher = sTempInsetBoundsPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    mTempInsetBounds = extractBounds(matcher);
-                }
-
-                matcher = sAppTokenPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(line);
-                    final String appToken = matcher.group(6);
-                    log(appToken);
-                    mAppTokens.add(appToken);
-                    continue;
-                }
-            }
-        }
-    }
-
-    static abstract class WindowContainer {
-        protected static final Pattern sFullscreenPattern = Pattern.compile("mFullscreen=(\\S+)");
-        protected static final Pattern sBoundsPattern =
-                Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]");
-
-        protected boolean mFullscreen;
-        protected Rectangle mBounds;
-
-        static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
-            if (dump.isEmpty()) {
-                return true;
-            }
-            final String line = dump.peek().trim();
-
-            for (Pattern pattern : exitPatterns) {
-                if (pattern.matcher(line).matches()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean extractFullscreen(String line) {
-            final Matcher matcher = sFullscreenPattern.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            final String fullscreen = matcher.group(1);
-            log(fullscreen);
-            mFullscreen = Boolean.valueOf(fullscreen);
-            return true;
-        }
-
-        boolean extractBounds(String line) {
-            final Matcher matcher = sBoundsPattern.matcher(line);
-            if (!matcher.matches()) {
-                return false;
-            }
-            log(line);
-            mBounds = extractBounds(matcher);
-            return true;
-        }
-
-        static Rectangle extractBounds(Matcher matcher) {
-            final int left = Integer.valueOf(matcher.group(1));
-            final int top = Integer.valueOf(matcher.group(2));
-            final int right = Integer.valueOf(matcher.group(3));
-            final int bottom = Integer.valueOf(matcher.group(4));
-            final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
-
-            log(rect.toString());
-            return rect;
-        }
-
-        static void extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList) {
-            for (Rectangle rect : rectList) {
-                if (rect == null) {
-                    return;
-                }
-                final int left = Integer.valueOf(matcher.group(groupIndex++));
-                final int top = Integer.valueOf(matcher.group(groupIndex++));
-                final int right = Integer.valueOf(matcher.group(groupIndex++));
-                final int bottom = Integer.valueOf(matcher.group(groupIndex++));
-                rect.setBounds(left, top, right - left, bottom - top);
-            }
-        }
-
-        Rectangle getBounds() {
-            return mBounds;
-        }
-
-        boolean isFullscreen() {
-            return mFullscreen;
-        }
-    }
-
-    static class Display extends WindowContainer {
-        private static final String TAG = "[Display] ";
-
-        private static final Pattern sDisplayIdPattern =
-                Pattern.compile("Display: mDisplayId=(\\d+)");
-        private static final Pattern sDisplayInfoPattern =
-                Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
-
-        private final int mDisplayId;
-        private Rectangle mDisplayRect = new Rectangle();
-        private Rectangle mAppRect = new Rectangle();
-        private int mDpi;
-
-        private Display(int displayId) {
-            mDisplayId = displayId;
-        }
-
-        int getDisplayId() {
-            return mDisplayId;
-        }
-
-        int getDpi() {
-            return mDpi;
-        }
-
-        Rectangle getDisplayRect() {
-            return mDisplayRect;
-        }
-
-        Rectangle getAppRect() {
-            return mAppRect;
-        }
-
-        static Display create(LinkedList<String> dump, Pattern[] exitPatterns) {
-            // TODO: exit pattern for displays?
-            final String line = dump.peek().trim();
-
-            Matcher matcher = sDisplayIdPattern.matcher(line);
-            if (!matcher.matches()) {
-                return null;
-            }
-
-            log(TAG + "DISPLAY_ID: " + line);
-            dump.pop();
-
-            final int displayId = Integer.valueOf(matcher.group(1));
-            final Display display = new Display(displayId);
-            display.extract(dump, exitPatterns);
-            return display;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                final Matcher matcher = sDisplayInfoPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "DISPLAY_INFO: " + line);
-                    mDpi = Integer.valueOf(matcher.group(2));
-
-                    final int displayWidth = Integer.valueOf(matcher.group(3));
-                    final int displayHeight = Integer.valueOf(matcher.group(4));
-                    mDisplayRect.setBounds(0, 0, displayWidth, displayHeight);
-
-                    final int appWidth = Integer.valueOf(matcher.group(5));
-                    final int appHeight = Integer.valueOf(matcher.group(6));
-                    mAppRect.setBounds(0, 0, appWidth, appHeight);
-
-                    // break as we don't need other info for now
-                    break;
-                }
-                // Extract other info here if needed
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Display #" + mDisplayId + ": mDisplayRect=" + mDisplayRect
-                    + " mAppRect=" + mAppRect;
-        }
-    }
-
-    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 sFramePattern =
-                Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
-        private static final Pattern sWindowAssociationPattern =
-                Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
-
-        private final String mName;
-        private final String mAppToken;
-        private final boolean mStarting;
-        private final boolean mExiting;
-        private int mDisplayId;
-        private int mStackId;
-        private Rectangle mContainingFrame = new Rectangle();
-        private Rectangle mParentFrame = new Rectangle();
-
-        private WindowState(Matcher matcher, boolean starting, boolean exiting) {
-            mName = matcher.group(4);
-            mAppToken = matcher.group(2);
-            mStarting = starting;
-            mExiting = exiting;
-        }
-
-        String getName() {
-            return mName;
-        }
-
-        String getToken() {
-            return mAppToken;
-        }
-
-        boolean isStartingWindow() {
-            return mStarting;
-        }
-
-        boolean isExitingWindow() {
-            return mExiting;
-        }
-
-        int getDisplayId() {
-            return mDisplayId;
-        }
-
-        int getStackId() {
-            return mStackId;
-        }
-
-        Rectangle getContainingFrame() {
-            return mContainingFrame;
-        }
-
-        Rectangle getParentFrame() {
-            return mParentFrame;
-        }
-
-        static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) {
-            final String line = dump.peek().trim();
-
-            Matcher matcher = sWindowPattern.matcher(line);
-            if (!matcher.matches()) {
-                return null;
-            }
-
-            log(TAG + "WINDOW: " + line);
-            dump.pop();
-
-            final WindowState window;
-            Matcher specialMatcher = sStartingWindowPattern.matcher(line);
-            if (specialMatcher.matches()) {
-                log(TAG + "STARTING: " + line);
-                window = new WindowState(specialMatcher, true, false);
-            } else {
-                specialMatcher = sExitingWindowPattern.matcher(line);
-                if (specialMatcher.matches()) {
-                    log(TAG + "EXITING: " + line);
-                    window = new WindowState(specialMatcher, false, true);
-                } else {
-                    window = new WindowState(matcher, false, false);
-                }
-            }
-
-            window.extract(dump, exitPatterns);
-            return window;
-        }
-
-        private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-            while (!doneExtracting(dump, exitPatterns)) {
-                final String line = dump.pop().trim();
-
-                Matcher matcher = sWindowAssociationPattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "WINDOW_ASSOCIATION: " + line);
-                    mDisplayId = Integer.valueOf(matcher.group(1));
-                    mStackId = Integer.valueOf(matcher.group(2));
-                    continue;
-                }
-
-                matcher = sFramePattern.matcher(line);
-                if (matcher.matches()) {
-                    log(TAG + "FRAME: " + line);
-                    extractMultipleBounds(matcher, 1, mContainingFrame, mParentFrame);
-                    continue;
-                }
-
-                // Extract other info here if needed
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "WindowState: {" + mAppToken + " " + mName
-                    + (mStarting ? " STARTING" : "") + (mExiting ? " EXITING" : "") + "}"
-                    + " cf=" + mContainingFrame + " pf=" + mParentFrame;
-        }
-    }
-}
diff --git a/hostsidetests/services/windowmanager/Android.mk b/hostsidetests/services/windowmanager/Android.mk
deleted file mode 100644
index 4448d9a..0000000
--- a/hostsidetests/services/windowmanager/Android.mk
+++ /dev/null
@@ -1,35 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-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
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/windowmanager/AndroidTest.xml b/hostsidetests/services/windowmanager/AndroidTest.xml
deleted file mode 100644
index 8346b72..0000000
--- a/hostsidetests/services/windowmanager/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
--->
-<configuration description="Config for CTS drag and drop host test cases">
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsDragAndDropSourceApp.apk" />
-        <option name="test-file-name" value="CtsDragAndDropTargetApp.apk" />
-        <option name="test-file-name" value="CtsDragAndDropTargetAppSdk23.apk" />
-    </target_preparer>
-    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="CtsDragAndDropHostTestCases.jar" />
-    </test>
-</configuration>
diff --git a/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java b/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
deleted file mode 100644
index ff92656..0000000
--- a/hostsidetests/services/windowmanager/dndsourceapp/src/android/wm/cts/dndsourceapp/DragSource.java
+++ /dev/null
@@ -1,102 +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.wm.cts.dndsourceapp;
-
-import android.app.Activity;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.PersistableBundle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.TextView;
-
-public class DragSource extends Activity{
-    private static final String URI_PREFIX =
-            "content://" + DragSourceContentProvider.AUTHORITY + "/data";
-
-    private static final String MAGIC_VALUE = "42";
-    private static final long TIMEOUT_CANCEL = 150;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        View view = getLayoutInflater().inflate(R.layout.source_activity, null);
-        setContentView(view);
-
-        final Uri plainUri = Uri.parse(URI_PREFIX + "/" + MAGIC_VALUE);
-
-        setUpDragSource("disallow_global", plainUri, 0);
-        setUpDragSource("cancel_soon", plainUri, View.DRAG_FLAG_GLOBAL);
-
-        setUpDragSource("grant_none", plainUri, View.DRAG_FLAG_GLOBAL);
-        setUpDragSource("grant_read", plainUri,
-                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
-        setUpDragSource("grant_write", plainUri,
-                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_WRITE);
-        setUpDragSource("grant_read_persistable", plainUri,
-                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
-                        View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION);
-
-        final Uri prefixUri = Uri.parse(URI_PREFIX);
-
-        setUpDragSource("grant_read_prefix", prefixUri,
-                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
-                        View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION);
-        setUpDragSource("grant_read_noprefix", prefixUri,
-                View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ);
-    }
-
-    private void setUpDragSource(String mode, final Uri uri, final int flags) {
-        if (!mode.equals(getIntent().getStringExtra("mode"))) {
-            return;
-        }
-        final View source = findViewById(R.id.drag_source);
-        ((TextView) source).setText(mode);
-        source.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (event.getAction() != MotionEvent.ACTION_DOWN) {
-                    return false;
-                }
-                final ClipDescription clipDescription = new ClipDescription("", new String[] {
-                        ClipDescription.MIMETYPE_TEXT_URILIST });
-                PersistableBundle extras = new PersistableBundle(1);
-                extras.putString("extraKey", "extraValue");
-                clipDescription.setExtras(extras);
-                final ClipData clipData = new ClipData(clipDescription, new ClipData.Item(uri));
-                v.startDragAndDrop(
-                        clipData,
-                        new View.DragShadowBuilder(v),
-                        null,
-                        flags);
-                if (mode.equals("cancel_soon")) {
-                    new Handler().postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            v.cancelDragAndDrop();
-                        }
-                    }, TIMEOUT_CANCEL);
-                }
-                return true;
-            }
-        });
-    }
-}
diff --git a/hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java b/hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
deleted file mode 100644
index 904a422..0000000
--- a/hostsidetests/services/windowmanager/dndtargetapp/src/android/wm/cts/dndtargetapp/DropTarget.java
+++ /dev/null
@@ -1,249 +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.wm.cts.dndtargetapp;
-
-import android.app.Activity;
-import android.content.ClipData;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.util.Log;
-import android.view.DragAndDropPermissions;
-import android.view.DragEvent;
-import android.view.View;
-import android.widget.TextView;
-
-public class DropTarget extends Activity {
-    public static final String LOG_TAG = "DropTarget";
-
-    private static final String RESULT_KEY_DRAG_STARTED = "DRAG_STARTED";
-    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";
-
-    public static final String RESULT_OK = "OK";
-    public static final String RESULT_EXCEPTION = "Exception";
-
-    protected static final String MAGIC_VALUE = "42";
-
-    private TextView mTextView;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        View view = getLayoutInflater().inflate(R.layout.target_activity, null);
-        setContentView(view);
-
-        setUpDropTarget("request_none", new OnDragUriReadListener(false));
-        setUpDropTarget("request_read", new OnDragUriReadListener());
-        setUpDropTarget("request_write", new OnDragUriWriteListener());
-        setUpDropTarget("request_read_nested", new OnDragUriReadPrefixListener());
-        setUpDropTarget("request_take_persistable", new OnDragUriTakePersistableListener());
-    }
-
-    private void setUpDropTarget(String mode, OnDragUriListener listener) {
-        if (!mode.equals(getIntent().getStringExtra("mode"))) {
-            return;
-        }
-        mTextView = (TextView)findViewById(R.id.drag_target);
-        mTextView.setText(mode);
-        mTextView.setOnDragListener(listener);
-    }
-
-    private String checkExtraValue(DragEvent event) {
-        PersistableBundle extras = event.getClipDescription().getExtras();
-        if (extras == null) {
-            return "Null";
-        }
-
-        final String value = extras.getString("extraKey");
-        if ("extraValue".equals(value)) {
-            return RESULT_OK;
-        }
-        return value;
-    }
-
-    private void logResult(String key, String value) {
-        Log.i(LOG_TAG, key + "=" + value);
-        mTextView.setText(mTextView.getText() + "\n" + key + "=" + value);
-    }
-
-    private abstract class OnDragUriListener implements View.OnDragListener {
-        private final boolean requestPermissions;
-
-        public OnDragUriListener(boolean requestPermissions) {
-            this.requestPermissions = requestPermissions;
-        }
-
-        @Override
-        public boolean onDrag(View v, DragEvent event) {
-            switch (event.getAction()) {
-                case DragEvent.ACTION_DRAG_STARTED:
-                    logResult(RESULT_KEY_DRAG_STARTED, RESULT_OK);
-                    logResult(RESULT_KEY_EXTRAS, checkExtraValue(event));
-                    return true;
-
-                case DragEvent.ACTION_DRAG_ENTERED:
-                    return true;
-
-                case DragEvent.ACTION_DRAG_LOCATION:
-                    return true;
-
-                case DragEvent.ACTION_DRAG_EXITED:
-                    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);
-                    return true;
-
-                case DragEvent.ACTION_DRAG_ENDED:
-                    return true;
-
-                default:
-                    return false;
-            }
-        }
-
-        private String processDrop(DragEvent event, boolean requestPermissions) {
-            final ClipData clipData = event.getClipData();
-            if (clipData == null) {
-                return "Null ClipData";
-            }
-            if (clipData.getItemCount() == 0) {
-                return "Empty ClipData";
-            }
-            ClipData.Item item = clipData.getItemAt(0);
-            if (item == null) {
-                return "Null ClipData.Item";
-            }
-            Uri uri = item.getUri();
-            if (uri == null) {
-                return "Null Uri";
-            }
-
-            DragAndDropPermissions permissions = null;
-            if (requestPermissions) {
-                permissions = requestDragAndDropPermissions(event);
-                if (permissions == null) {
-                    return "Null DragAndDropPermissions";
-                }
-            }
-
-            try {
-                return processUri(uri);
-            } finally {
-                if (permissions != null) {
-                    permissions.release();
-                }
-            }
-        }
-
-        abstract protected String processUri(Uri uri);
-    }
-
-    private class OnDragUriReadListener extends OnDragUriListener {
-        OnDragUriReadListener(boolean requestPermissions) {
-            super(requestPermissions);
-        }
-
-        OnDragUriReadListener() {
-            super(true);
-        }
-
-        protected String processUri(Uri uri) {
-            return checkQueryResult(uri, MAGIC_VALUE);
-        }
-
-        protected String checkQueryResult(Uri uri, String expectedValue) {
-            Cursor cursor = null;
-            try {
-                cursor = getContentResolver().query(uri, null, null, null, null);
-                if (cursor == null) {
-                    return "Null Cursor";
-                }
-                cursor.moveToPosition(0);
-                String value = cursor.getString(0);
-                if (!expectedValue.equals(value)) {
-                    return "Wrong value: " + value;
-                }
-                return RESULT_OK;
-            } finally {
-                if (cursor != null) {
-                    cursor.close();
-                }
-            }
-        }
-    }
-
-    private class OnDragUriWriteListener extends OnDragUriListener {
-        OnDragUriWriteListener() {
-            super(true);
-        }
-
-        protected String processUri(Uri uri) {
-            ContentValues values = new ContentValues();
-            values.put("key", 100);
-            getContentResolver().update(uri, values, null, null);
-            return RESULT_OK;
-        }
-    }
-
-    private class OnDragUriReadPrefixListener extends OnDragUriReadListener {
-        @Override
-        protected String processUri(Uri uri) {
-            final String result1 = queryPrefixed(uri, "1");
-            if (!result1.equals(RESULT_OK)) {
-                return result1;
-            }
-            final String result2 = queryPrefixed(uri, "2");
-            if (!result2.equals(RESULT_OK)) {
-                return result2;
-            }
-            return queryPrefixed(uri, "3");
-        }
-
-        private String queryPrefixed(Uri uri, String selector) {
-            final Uri prefixedUri = Uri.parse(uri.toString() + "/" + selector);
-            return checkQueryResult(prefixedUri, selector);
-        }
-    }
-
-    private class OnDragUriTakePersistableListener extends OnDragUriListener {
-        OnDragUriTakePersistableListener() {
-            super(true);
-        }
-
-        @Override
-        protected String processUri(Uri uri) {
-            getContentResolver().takePersistableUriPermission(
-                    uri, View.DRAG_FLAG_GLOBAL_URI_READ);
-            getContentResolver().releasePersistableUriPermission(
-                    uri, View.DRAG_FLAG_GLOBAL_URI_READ);
-            return RESULT_OK;
-        }
-    }
-}
diff --git a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
deleted file mode 100644
index fa1ae69..0000000
--- a/hostsidetests/services/windowmanager/src/android/wm/cts/CrossAppDragAndDropTests.java
+++ /dev/null
@@ -1,416 +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.wm.cts;
-
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class CrossAppDragAndDropTests extends DeviceTestCase {
-    // Constants copied from ActivityManager.StackId. If they are changed there, these must be
-    // updated.
-    /** ID of stack where fullscreen activities are normally launched into. */
-    private static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
-
-    /** ID of stack where freeform/resized activities are normally launched into. */
-    private static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
-
-    /** ID of stack that occupies a dedicated region of the screen. */
-    private static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
-
-    /** ID of stack that always on top (always visible) when it exists. */
-    private static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
-
-    private static final String AM_FORCE_STOP = "am force-stop ";
-    private static final String AM_MOVE_TASK = "am stack movetask ";
-    private static final String AM_REMOVE_STACK = "am stack remove ";
-    private static final String AM_START_N = "am start -n ";
-    private static final String AM_STACK_LIST = "am stack list";
-    private static final String INPUT_MOUSE_SWIPE = "input mouse swipe ";
-    private static final String TASK_ID_PREFIX = "taskId";
-
-    private static final int SWIPE_DURATION_MS = 500;
-
-    private static final String SOURCE_PACKAGE_NAME = "android.wm.cts.dndsourceapp";
-    private static final String TARGET_PACKAGE_NAME = "android.wm.cts.dndtargetapp";
-    private static final String TARGET_23_PACKAGE_NAME = "android.wm.cts.dndtargetappsdk23";
-
-
-    private static final String SOURCE_ACTIVITY_NAME = "DragSource";
-    private static final String TARGET_ACTIVITY_NAME = "DropTarget";
-
-    private static final String DISALLOW_GLOBAL = "disallow_global";
-    private static final String CANCEL_SOON = "cancel_soon";
-    private static final String GRANT_NONE = "grant_none";
-    private static final String GRANT_READ = "grant_read";
-    private static final String GRANT_WRITE = "grant_write";
-    private static final String GRANT_READ_PREFIX = "grant_read_prefix";
-    private static final String GRANT_READ_NOPREFIX = "grant_read_noprefix";
-    private static final String GRANT_READ_PERSISTABLE = "grant_read_persistable";
-
-    private static final String REQUEST_NONE = "request_none";
-    private static final String REQUEST_READ = "request_read";
-    private static final String REQUEST_READ_NESTED = "request_read_nested";
-    private static final String REQUEST_TAKE_PERSISTABLE = "request_take_persistable";
-    private static final String REQUEST_WRITE = "request_write";
-
-    private static final String TARGET_LOG_TAG = "DropTarget";
-
-    private static final String RESULT_KEY_DRAG_STARTED = "DRAG_STARTED";
-    private static final String RESULT_KEY_EXTRAS = "EXTRAS";
-    private static final String RESULT_KEY_DROP_RESULT = "DROP";
-
-    private static final String RESULT_OK = "OK";
-    private static final String RESULT_EXCEPTION = "Exception";
-    private static final String RESULT_NULL_DROP_PERMISSIONS = "Null DragAndDropPermissions";
-
-    private ITestDevice mDevice;
-
-    private Map<String, String> mResults;
-
-    private String mSourcePackageName;
-    private String mTargetPackageName;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mDevice = getDevice();
-
-        if (!supportsDragAndDrop()) {
-            return;
-        }
-
-        mSourcePackageName = SOURCE_PACKAGE_NAME;
-        mTargetPackageName = TARGET_PACKAGE_NAME;
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        if (!supportsDragAndDrop()) {
-            return;
-        }
-
-        mDevice.executeShellCommand(AM_FORCE_STOP + mSourcePackageName);
-        mDevice.executeShellCommand(AM_FORCE_STOP + mTargetPackageName);
-    }
-
-    private String executeShellCommand(String command) throws DeviceNotAvailableException {
-        return mDevice.executeShellCommand(command);
-    }
-
-    private void clearLogs() throws DeviceNotAvailableException {
-        executeShellCommand("logcat -c");
-    }
-
-    private String getStartCommand(String componentName, String modeExtra) {
-        return AM_START_N + componentName + " -e mode " + modeExtra;
-    }
-
-    private String getMoveTaskCommand(int taskId, int stackId) throws Exception {
-        return AM_MOVE_TASK + taskId + " " + stackId + " true";
-    }
-
-    private String getComponentName(String packageName, String activityName) {
-        return packageName + "/" + packageName + "." + activityName;
-    }
-
-    /**
-     * Make sure that the special activity stacks are removed and the ActivityManager/WindowManager
-     * is in a good state.
-     */
-    private void cleanupState() throws Exception {
-        executeShellCommand(AM_FORCE_STOP + SOURCE_PACKAGE_NAME);
-        executeShellCommand(AM_FORCE_STOP + TARGET_PACKAGE_NAME);
-        executeShellCommand(AM_FORCE_STOP + TARGET_23_PACKAGE_NAME);
-        unlockDevice();
-
-        // Reinitialize the docked stack to force the window manager to reset its default bounds.
-        // See b/29068935.
-        clearLogs();
-        final String componentName = getComponentName(mSourcePackageName, SOURCE_ACTIVITY_NAME);
-        executeShellCommand(getStartCommand(componentName, null) + " --stack " +
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        final int taskId = getActivityTaskId(componentName);
-        // Moving a task from the full screen stack to the docked stack resets
-        // WindowManagerService#mDockedStackCreateBounds.
-        executeShellCommand(getMoveTaskCommand(taskId, DOCKED_STACK_ID));
-        waitForResume(mSourcePackageName, SOURCE_ACTIVITY_NAME);
-        executeShellCommand(AM_FORCE_STOP + SOURCE_PACKAGE_NAME);
-
-        // Remove special stacks.
-        executeShellCommand(AM_REMOVE_STACK + PINNED_STACK_ID);
-        executeShellCommand(AM_REMOVE_STACK + DOCKED_STACK_ID);
-        executeShellCommand(AM_REMOVE_STACK + FREEFORM_WORKSPACE_STACK_ID);
-    }
-
-    private void launchDockedActivity(String packageName, String activityName, String mode)
-            throws Exception {
-        clearLogs();
-        final String componentName = getComponentName(packageName, activityName);
-        executeShellCommand(getStartCommand(componentName, mode) + " --stack " + DOCKED_STACK_ID);
-        waitForResume(packageName, activityName);
-    }
-
-    private void launchFullscreenActivity(String packageName, String activityName, String mode)
-            throws Exception {
-        clearLogs();
-        final String componentName = getComponentName(packageName, activityName);
-        executeShellCommand(getStartCommand(componentName, mode) + " --stack "
-                + FULLSCREEN_WORKSPACE_STACK_ID);
-        waitForResume(packageName, activityName);
-    }
-
-    private void waitForResume(String packageName, String activityName) throws Exception {
-        final String fullActivityName = packageName + "." + activityName;
-        int retryCount = 3;
-        do {
-            Thread.sleep(500);
-            String logs = executeShellCommand("logcat -d -b events");
-            for (String line : logs.split("\\n")) {
-                if(line.contains("am_on_resume_called") && line.contains(fullActivityName)) {
-                    return;
-                }
-            }
-        } while (retryCount-- > 0);
-
-        throw new Exception(fullActivityName + " has failed to start");
-    }
-
-    private void injectInput(Point from, Point to, int durationMs) throws Exception {
-        executeShellCommand(
-                INPUT_MOUSE_SWIPE + from.x + " " + from.y + " " + to.x + " " + to.y + " " +
-                durationMs);
-    }
-
-    static class Point {
-        public int x, y;
-
-        public Point(int _x, int _y) {
-            x=_x;
-            y=_y;
-        }
-
-        public Point() {}
-    }
-
-    private String findTaskInfo(String name) throws Exception {
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
-        final String output = outputReceiver.getOutput();
-        for (String line : output.split("\\n")) {
-            if (line.contains(name)) {
-                return line;
-            }
-        }
-        return "";
-    }
-
-    private boolean getWindowBounds(String name, Point from, Point to) throws Exception {
-        final String taskInfo = findTaskInfo(name);
-        final String[] sections = taskInfo.split("\\[");
-        if (sections.length > 2) {
-            try {
-                parsePoint(sections[1], from);
-                parsePoint(sections[2], to);
-                return true;
-            } catch (Exception e) {
-                return false;
-            }
-        }
-        return false;
-    }
-
-    private int getActivityTaskId(String name) throws Exception {
-        final String taskInfo = findTaskInfo(name);
-        for (String word : taskInfo.split("\\s+")) {
-            if (word.startsWith(TASK_ID_PREFIX)) {
-                final String withColon = word.split("=")[1];
-                return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
-            }
-        }
-        return -1;
-    }
-
-    private Point getWindowCenter(String name) throws Exception {
-        Point p1 = new Point();
-        Point p2 = new Point();
-        if (getWindowBounds(name, p1, p2)) {
-            return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
-        }
-        return null;
-    }
-
-    private void parsePoint(String string, Point point) {
-        final String[] parts = string.split("[,|\\]]");
-        point.x = Integer.parseInt(parts[0]);
-        point.y = Integer.parseInt(parts[1]);
-    }
-
-    private void unlockDevice() throws DeviceNotAvailableException {
-        // Wake up the device, if necessary.
-        executeShellCommand("input keyevent 224");
-        // Unlock the screen.
-        executeShellCommand("input keyevent 82");
-    }
-
-    private Map<String, String> getLogResults(String className) throws Exception {
-        int retryCount = 3;
-        Map<String, String> output = new HashMap<String, String>();
-        do {
-
-            String logs = executeShellCommand("logcat -v brief -d " + className + ":I" + " *:S");
-            for (String line : logs.split("\\n")) {
-                if (line.startsWith("I/" + className)) {
-                    String payload = line.split(":")[1].trim();
-                    final String[] split = payload.split("=");
-                    if (split.length > 1) {
-                        output.put(split[0], split[1]);
-                    }
-                }
-            }
-            if (output.containsKey(RESULT_KEY_DROP_RESULT)) {
-                return output;
-            }
-        } while (retryCount-- > 0);
-        return output;
-    }
-
-    private void doTestDragAndDrop(String sourceMode, String targetMode, String expectedDropResult)
-            throws Exception {
-        if (!supportsDragAndDrop()) {
-            return;
-        }
-
-        launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
-        launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
-
-        clearLogs();
-
-        injectInput(
-                getWindowCenter(getComponentName(mSourcePackageName, SOURCE_ACTIVITY_NAME)),
-                getWindowCenter(getComponentName(mTargetPackageName, TARGET_ACTIVITY_NAME)),
-                SWIPE_DURATION_MS);
-
-        mResults = getLogResults(TARGET_LOG_TAG);
-        assertResult(RESULT_KEY_DROP_RESULT, expectedDropResult);
-    }
-
-    private void assertResult(String resultKey, String expectedResult) throws Exception {
-        if (!supportsDragAndDrop()) {
-            return;
-        }
-
-        if (expectedResult == null) {
-            if (mResults.containsKey(resultKey)) {
-                fail("Unexpected " + resultKey + "=" + mResults.get(resultKey));
-            }
-        } else {
-            assertTrue("Missing " + resultKey, mResults.containsKey(resultKey));
-            assertEquals(expectedResult, mResults.get(resultKey));
-        }
-    }
-
-    private boolean supportsDragAndDrop() throws Exception {
-        String supportsMultiwindow = mDevice.executeShellCommand("am supports-multiwindow").trim();
-        if ("true".equals(supportsMultiwindow)) {
-            return true;
-        } else if ("false".equals(supportsMultiwindow)) {
-            return false;
-        } else {
-            throw new Exception(
-                    "device does not support \"am supports-multiwindow\" shell command.");
-        }
-    }
-
-    public void testCancelSoon() throws Exception {
-        doTestDragAndDrop(CANCEL_SOON, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, RESULT_OK);
-        assertResult(RESULT_KEY_EXTRAS, RESULT_OK);
-    }
-
-    public void testDisallowGlobal() throws Exception {
-        doTestDragAndDrop(DISALLOW_GLOBAL, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, null);
-    }
-
-    public void testDisallowGlobalBelowSdk24() throws Exception {
-        mTargetPackageName = TARGET_23_PACKAGE_NAME;
-        doTestDragAndDrop(GRANT_NONE, REQUEST_NONE, null);
-        assertResult(RESULT_KEY_DRAG_STARTED, 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 {
-        doTestDragAndDrop(GRANT_NONE, REQUEST_READ, RESULT_NULL_DROP_PERMISSIONS);
-    }
-
-    public void testGrantNoneRequestWrite() throws Exception {
-        doTestDragAndDrop(GRANT_NONE, REQUEST_WRITE, RESULT_NULL_DROP_PERMISSIONS);
-    }
-
-    public void testGrantReadRequestNone() throws Exception {
-        doTestDragAndDrop(GRANT_READ, REQUEST_NONE, RESULT_EXCEPTION);
-    }
-
-    public void testGrantReadRequestRead() throws Exception {
-        doTestDragAndDrop(GRANT_READ, REQUEST_READ, RESULT_OK);
-    }
-
-    public void testGrantReadRequestWrite() throws Exception {
-        doTestDragAndDrop(GRANT_READ, REQUEST_WRITE, RESULT_EXCEPTION);
-    }
-
-    public void testGrantReadNoPrefixRequestReadNested() throws Exception {
-        doTestDragAndDrop(GRANT_READ_NOPREFIX, REQUEST_READ_NESTED, RESULT_EXCEPTION);
-    }
-
-    public void testGrantReadPrefixRequestReadNested() throws Exception {
-        doTestDragAndDrop(GRANT_READ_PREFIX, REQUEST_READ_NESTED, RESULT_OK);
-    }
-
-    public void testGrantPersistableRequestTakePersistable() throws Exception {
-        doTestDragAndDrop(GRANT_READ_PERSISTABLE, REQUEST_TAKE_PERSISTABLE, RESULT_OK);
-    }
-
-    public void testGrantReadRequestTakePersistable() throws Exception {
-        doTestDragAndDrop(GRANT_READ, REQUEST_TAKE_PERSISTABLE, RESULT_EXCEPTION);
-    }
-
-    public void testGrantWriteRequestNone() throws Exception {
-        doTestDragAndDrop(GRANT_WRITE, REQUEST_NONE, RESULT_EXCEPTION);
-    }
-
-    public void testGrantWriteRequestRead() throws Exception {
-        doTestDragAndDrop(GRANT_WRITE, REQUEST_READ, RESULT_EXCEPTION);
-    }
-
-    public void testGrantWriteRequestWrite() throws Exception {
-        doTestDragAndDrop(GRANT_WRITE, REQUEST_WRITE, RESULT_OK);
-    }
-}
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
index a463b59..810fe64 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher1/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
index 2f37101..3eb0cde 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher2/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk b/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
index 3bbd906..0b072a5 100644
--- a/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/launcher3/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
index 2ac759a..a729fe8 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher1/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
index 62ad16e..12a0995 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher2/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk b/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
index 049691d..4232034 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher3/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher3/src/android/content/pm/cts/shortcut/backup/publisher3/ShortcutManagerPostBackupTest.java b/hostsidetests/shortcuts/deviceside/backup/publisher3/src/android/content/pm/cts/shortcut/backup/publisher3/ShortcutManagerPostBackupTest.java
index a36cc66..870dab9 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher3/src/android/content/pm/cts/shortcut/backup/publisher3/ShortcutManagerPostBackupTest.java
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher3/src/android/content/pm/cts/shortcut/backup/publisher3/ShortcutManagerPostBackupTest.java
@@ -21,6 +21,9 @@
 
 public class ShortcutManagerPostBackupTest extends ShortcutManagerDeviceTestBase {
     public void testWithUninstall() {
+        assertWith(getManager().getDynamicShortcuts())
+                .isEmpty();
+
         // backup = false, so no pinned shortcuts should be restored.
         assertWith(getManager().getPinnedShortcuts())
                 .isEmpty();
@@ -29,4 +32,15 @@
                 .haveIds("ms1", "ms2")
                 .areAllNotPinned();
     }
+
+    public void testWithNoUninstall() {
+        // backup = false, so dynamic shortcuts shouldn't be overwritten.
+        assertWith(getManager().getDynamicShortcuts())
+                .haveIds("s1", "s2", "s3")
+                .areAllNotPinned();
+
+        assertWith(getManager().getManifestShortcuts())
+                .haveIds("ms1", "ms2")
+                .areAllNotPinned();
+    }
 }
diff --git a/hostsidetests/shortcuts/deviceside/multiuser/Android.mk b/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
index 2897e8c..183531b 100644
--- a/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/multiuser/Android.mk
@@ -34,7 +34,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/deviceside/upgrade/Android.mk b/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
index 21b07a0..11bfc2f 100644
--- a/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
+++ b/hostsidetests/shortcuts/deviceside/upgrade/Android.mk
@@ -38,7 +38,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
@@ -69,7 +69,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/hostsidetests/shortcuts/hostside/Android.mk b/hostsidetests/shortcuts/hostside/Android.mk
index 56b2e60..830ec94 100644
--- a/hostsidetests/shortcuts/hostside/Android.mk
+++ b/hostsidetests/shortcuts/hostside/Android.mk
@@ -24,9 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml
index 13b9e14..729cb8c 100644
--- a/hostsidetests/shortcuts/hostside/AndroidTest.xml
+++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml
@@ -16,6 +16,6 @@
 <configuration description="Config for the CTS ShortcutManager host tests">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsShortcutHostTestCases.jar" />
-        <option name="runtime-hint" value="20m" />
+        <option name="runtime-hint" value="10m" />
     </test>
 </configuration>
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
index fbd344b..c703e7f 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
@@ -15,7 +15,7 @@
  */
 package android.content.pm.cts.shortcuthost;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -102,9 +102,9 @@
     protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
             DeviceNotAvailableException {
         CLog.i("Installing app " + appFileName + " for user " + userId);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
         String result = getDevice().installPackageForUser(
-                MigrationHelper.getTestFile(mCtsBuild, appFileName), true, true,
-                userId, "-t");
+                buildHelper.getTestFile(appFileName), true, true, userId, "-t");
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
index 03e0e5c..595ee74 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
@@ -202,9 +202,11 @@
         }
 
         installAppAsUser(PUBLISHER1_APK, getPrimaryUserId());
+        installAppAsUser(PUBLISHER3_APK, getPrimaryUserId());
 
         // Prepare shortcuts
         runDeviceTestsAsUser(PUBLISHER1_PKG, ".ShortcutManagerPreBackupTest", getPrimaryUserId());
+        runDeviceTestsAsUser(PUBLISHER3_PKG, ".ShortcutManagerPreBackupTest", getPrimaryUserId());
 
         // Backup & restore.
         doBackup();
@@ -214,5 +216,9 @@
         runDeviceTestsAsUser(PUBLISHER1_PKG, ".ShortcutManagerPostBackupTest",
                 "testWithNoUninstall",
                 getPrimaryUserId());
+
+        runDeviceTestsAsUser(PUBLISHER3_PKG, ".ShortcutManagerPostBackupTest",
+                "testWithNoUninstall",
+                getPrimaryUserId());
     }
 }
\ No newline at end of file
diff --git a/hostsidetests/sustainedperf/Android.mk b/hostsidetests/sustainedperf/Android.mk
index 22c6d45..a9f06e4 100644
--- a/hostsidetests/sustainedperf/Android.mk
+++ b/hostsidetests/sustainedperf/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_COMPATIBILITY_SUITE := cts
 
 LOCAL_MODULE := CtsSustainedPerformanceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/sustainedperf/AndroidTest.xml b/hostsidetests/sustainedperf/AndroidTest.xml
index ae5cc27..8b843d2 100644
--- a/hostsidetests/sustainedperf/AndroidTest.xml
+++ b/hostsidetests/sustainedperf/AndroidTest.xml
@@ -29,5 +29,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsSustainedPerformanceHostTestCases.jar" />
+        <option name="runtime-hint" value="8m30s" />
     </test>
 </configuration>
diff --git a/hostsidetests/systemui/Android.mk b/hostsidetests/systemui/Android.mk
index 1c0dd06..d4305f5 100644
--- a/hostsidetests/systemui/Android.mk
+++ b/hostsidetests/systemui/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsSystemUiHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.systemui
 
diff --git a/hostsidetests/systemui/AndroidTest.xml b/hostsidetests/systemui/AndroidTest.xml
index c8b1883..21e7e4c 100644
--- a/hostsidetests/systemui/AndroidTest.xml
+++ b/hostsidetests/systemui/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsSystemUiHostTestCases.jar" />
+        <option name="runtime-hint" value="11m" />
     </test>
 </configuration>
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index 00ca6ba..7875b4d 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -25,9 +25,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsThemeHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.theme
 
diff --git a/hostsidetests/theme/android_device.py b/hostsidetests/theme/android_device.py
index 6687494..68f7404 100644
--- a/hostsidetests/theme/android_device.py
+++ b/hostsidetests/theme/android_device.py
@@ -89,6 +89,11 @@
     def getOrientation(self):
         return int(self.runShellCommand("dumpsys | grep SurfaceOrientation")[0].split()[1])
 
+    def getHWType(self):
+        (output, err) = self.runShellCommand("dumpsys | grep android.hardware.type")
+        output = output.strip()
+        return output
+
 def runAdbDevices():
     devices = subprocess.check_output(["adb", "devices"])
     devices = devices.split('\n')[1:]
diff --git a/hostsidetests/theme/app/AndroidManifest.xml b/hostsidetests/theme/app/AndroidManifest.xml
index d9a89c6..2bfc2be 100755
--- a/hostsidetests/theme/app/AndroidManifest.xml
+++ b/hostsidetests/theme/app/AndroidManifest.xml
@@ -32,6 +32,8 @@
             </intent-filter>
         </activity>
         <activity android:name=".GenerateImagesActivity" android:screenOrientation="portrait"
+                  android:configChanges=
+                          "screenSize|smallestScreenSize|screenLayout|orientation"
                   android:exported="true" />
     </application>
 
diff --git a/hostsidetests/theme/assets/tvdpi.zip b/hostsidetests/theme/assets/tvdpi.zip
new file mode 100644
index 0000000..3071780
--- /dev/null
+++ b/hostsidetests/theme/assets/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/run_theme_capture_device.py b/hostsidetests/theme/run_theme_capture_device.py
index a516717..20aecf8 100755
--- a/hostsidetests/theme/run_theme_capture_device.py
+++ b/hostsidetests/theme/run_theme_capture_device.py
@@ -27,7 +27,6 @@
 CTS_THEME_dict = {
     120 : "ldpi",
     160 : "mdpi",
-    213 : "tvdpi",
     240 : "hdpi",
     320 : "xhdpi",
     480 : "xxhdpi",
@@ -98,10 +97,15 @@
     device = androidDevice(deviceSerial)
 
     density = device.getDensity()
-    if CTS_THEME_dict.has_key(density):
-        resName = CTS_THEME_dict[density]
+    # Reference images generated for tv should not be categorized by density
+    # rather by tv type. This is because TV uses leanback-specific material
+    # themes.
+    if device.getHWType() == "android.hardware.type.television":
+      resName = "tvdpi"
+    elif CTS_THEME_dict.has_key(density):
+      resName = CTS_THEME_dict[density]
     else:
-        resName = str(density) + "dpi"
+      resName = str(density) + "dpi"
 
     device.uninstallApk("android.theme.app")
 
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index eb2cb80..c87ff63 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -16,8 +16,7 @@
 
 package android.theme.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
@@ -28,6 +27,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -94,6 +94,9 @@
 
     private ExecutorCompletionService<File> mCompletionService;
 
+    /** the string identifying the hardware type. */
+    private String mHardwareType;
+
     @Override
     public void setAbi(IAbi abi) {
         mAbi = abi;
@@ -110,13 +113,15 @@
 
         mDevice = getDevice();
         mDevice.uninstallPackage(APP_PACKAGE_NAME);
+        mHardwareType = mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim();
 
         // Get the APK from the build.
-        final File app = MigrationHelper.getTestFile(mBuildInfo, String.format("%s.apk", APK_NAME));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        final File app = buildHelper.getTestFile(String.format("%s.apk", APK_NAME));
         final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         mDevice.installPackage(app, true, true, options);
 
-        final String density = getDensityBucketForDevice(mDevice);
+        final String density = getDensityBucketForDevice(mDevice, mHardwareType);
         final String zipFile = String.format("/%s.zip", density);
         mReferences = extractReferenceImages(zipFile);
 
@@ -150,7 +155,7 @@
                 fail("Failed to unzip assets: " + zipFile);
             }
         } else {
-            if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+            if (checkHardwareTypeSkipTest(mHardwareType)) {
                 Log.logAndDisplay(LogLevel.WARN, LOG_TAG,
                         "Could not obtain resources for skipped themes test: " + zipFile);
             } else {
@@ -178,7 +183,7 @@
     }
 
     public void testThemes() throws Exception {
-        if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+        if (checkHardwareTypeSkipTest(mHardwareType)) {
             Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Skipped themes test for watch");
             return;
         }
@@ -301,14 +306,17 @@
         return receiver.getOutput().contains("OK ");
     }
 
-    private static String getDensityBucketForDevice(ITestDevice device) {
+    private static String getDensityBucketForDevice(ITestDevice device, String hardwareType) {
+        if (hardwareType.contains("android.hardware.type.television")) {
+            // references images for tv are under bucket "tvdpi".
+            return "tvdpi";
+        }
         final int density;
         try {
             density = getDensityForDevice(device);
         } catch (DeviceNotAvailableException e) {
             throw new RuntimeException("Failed to detect device density", e);
         }
-
         final String bucket;
         switch (density) {
             case 120:
@@ -317,9 +325,6 @@
             case 160:
                 bucket = "mdpi";
                 break;
-            case 213:
-                bucket = "tvdpi";
-                break;
             case 240:
                 bucket = "hdpi";
                 break;
@@ -360,7 +365,6 @@
     }
 
     private static boolean checkHardwareTypeSkipTest(String hardwareTypeString) {
-        return hardwareTypeString.contains("android.hardware.type.watch")
-                || hardwareTypeString.contains("android.hardware.type.television");
+        return hardwareTypeString.contains("android.hardware.type.watch");
     }
 }
diff --git a/hostsidetests/trustedvoice/Android.mk b/hostsidetests/trustedvoice/Android.mk
index 9d6237f..d80f725 100644
--- a/hostsidetests/trustedvoice/Android.mk
+++ b/hostsidetests/trustedvoice/Android.mk
@@ -23,7 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsTrustedVoiceHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.trustedvoice
 
diff --git a/hostsidetests/trustedvoice/AndroidTest.xml b/hostsidetests/trustedvoice/AndroidTest.xml
index 835db65..7a11095 100644
--- a/hostsidetests/trustedvoice/AndroidTest.xml
+++ b/hostsidetests/trustedvoice/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsTrustedVoiceHostTestCases.jar" />
+        <option name="runtime-hint" value="12m" />
     </test>
 </configuration>
diff --git a/hostsidetests/tv/Android.mk b/hostsidetests/tv/Android.mk
index bb5795b..cb5e2bd 100644
--- a/hostsidetests/tv/Android.mk
+++ b/hostsidetests/tv/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsHostsideTvTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.tv.hostsidetv
 
diff --git a/hostsidetests/tv/AndroidTest.xml b/hostsidetests/tv/AndroidTest.xml
index c3064eb..9191987 100644
--- a/hostsidetests/tv/AndroidTest.xml
+++ b/hostsidetests/tv/AndroidTest.xml
@@ -16,5 +16,6 @@
 <configuration description="Config for CTS tv host test cases">
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsHostsideTvTests.jar" />
+        <option name="runtime-hint" value="8m10s" />
     </test>
 </configuration>
diff --git a/hostsidetests/tv/app/Android.mk b/hostsidetests/tv/app/Android.mk
index 3235244..454d352 100644
--- a/hostsidetests/tv/app/Android.mk
+++ b/hostsidetests/tv/app/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/tv/app2/Android.mk b/hostsidetests/tv/app2/Android.mk
index a0dcab2..166baec 100644
--- a/hostsidetests/tv/app2/Android.mk
+++ b/hostsidetests/tv/app2/Android.mk
@@ -31,7 +31,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
index fe917ae..67cd752 100644
--- a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
+++ b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
@@ -16,9 +16,9 @@
 
 package com.android.cts.tv;
 
-import com.android.ddmlib.Log.LogLevel;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.VersionCodes;
-import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -51,8 +51,8 @@
 
     private void installPackage(String apk) throws FileNotFoundException,
             DeviceNotAvailableException {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuildInfo, apk), true));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuildInfo);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), true));
     }
 
     private void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
index 7060bdf..e2457c5 100644
--- a/hostsidetests/ui/Android.mk
+++ b/hostsidetests/ui/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsUiHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/hostsidetests/ui/appA/Android.mk b/hostsidetests/ui/appA/Android.mk
index e3d458b..2d94543 100644
--- a/hostsidetests/ui/appA/Android.mk
+++ b/hostsidetests/ui/appA/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/ui/appB/Android.mk b/hostsidetests/ui/appB/Android.mk
index c7642fd..24108ca 100644
--- a/hostsidetests/ui/appB/Android.mk
+++ b/hostsidetests/ui/appB/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/ui/control/Android.mk b/hostsidetests/ui/control/Android.mk
index 5365a6f..fa63c59 100644
--- a/hostsidetests/ui/control/Android.mk
+++ b/hostsidetests/ui/control/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java b/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java
index 358e1ac..6b99c20 100644
--- a/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java
+++ b/hostsidetests/ui/control/src/android/taskswitching/control/cts/TaskSwitchingDeviceTest.java
@@ -25,7 +25,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 
-import android.cts.util.CtsAndroidTestCase;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.MeasureRun;
diff --git a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
index ee9e7c6..1b49eca 100644
--- a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
@@ -16,14 +16,13 @@
 
 package android.ui.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.MeasureRun;
 import com.android.compatibility.common.util.MeasureTime;
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
-import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IBuildInfo;
@@ -32,6 +31,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 
@@ -78,7 +78,7 @@
                 String.format("%s#%s", getClass().getName(), "testInstallTime"), REPORT_LOG_NAME,
                 streamName);
         final int NUMBER_REPEAT = 10;
-        final IBuildInfo build = mBuild;
+        final CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         final ITestDevice device = mDevice;
         double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
             @Override
@@ -87,7 +87,7 @@
             }
             @Override
             public void run(int i) throws Exception {
-                File app = MigrationHelper.getTestFile(build, APK);
+                File app = buildHelper.getTestFile(APK);
                 String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
                 device.installPackage(app, false, options);
             }
diff --git a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
index 409264e..9cfd957 100644
--- a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
@@ -16,10 +16,9 @@
 
 package android.ui.cts;
 
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.MetricsStore;
 import com.android.compatibility.common.util.ReportLog;
-import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestRunResult;
@@ -30,6 +29,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -77,9 +77,10 @@
         super.setUp();
         mDevice = getDevice();
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         for (int i = 0; i < PACKAGES.length; i++) {
             mDevice.uninstallPackage(PACKAGES[i]);
-            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+            File app = buildHelper.getTestFile(APKS[i]);
             mDevice.installPackage(app, false, options);
         }
     }
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index 72b9473..482ba91 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -21,7 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsAppUsageHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.app.usage
 
diff --git a/hostsidetests/usage/AndroidTest.xml b/hostsidetests/usage/AndroidTest.xml
index bba2748..98a7899 100644
--- a/hostsidetests/usage/AndroidTest.xml
+++ b/hostsidetests/usage/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAppUsageHostTestCases.jar" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index a96c5d8..bc98445 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsUsbTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.usb
 
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index 5377711..81cc265 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -15,8 +15,7 @@
  */
 package com.android.cts.usb;
 
-import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestRunResult;
 import com.android.tradefed.build.IBuildInfo;
@@ -27,6 +26,7 @@
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.RunUtil;
@@ -62,7 +62,8 @@
         super.setUp();
         mDevice = getDevice();
         mDevice.uninstallPackage(PACKAGE_NAME);
-        File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        File app = buildHelper.getTestFile(APK_NAME);
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         mDevice.installPackage(app, false, options);
     }
diff --git a/hostsidetests/webkit/Android.mk b/hostsidetests/webkit/Android.mk
new file mode 100644
index 0000000..6fe433c
--- /dev/null
+++ b/hostsidetests/webkit/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := CtsHostsideWebViewTests
+
+LOCAL_JAVA_LIBRARIES := tradefed
+
+LOCAL_CTS_TEST_PACKAGE := android.webkit.hostside
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/webkit/AndroidTest.xml b/hostsidetests/webkit/AndroidTest.xml
new file mode 100644
index 0000000..5a0eeca
--- /dev/null
+++ b/hostsidetests/webkit/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS WebView host test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsWebViewStartupApp.apk" />
+    </target_preparer>
+
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsHostsideWebViewTests.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/webkit/app/Android.mk b/hostsidetests/webkit/app/Android.mk
new file mode 100644
index 0000000..6370fa4
--- /dev/null
+++ b/hostsidetests/webkit/app/Android.mk
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctsdeviceutillegacy \
+    ctstestserver \
+    ctstestrunner
+
+# When built, explicitly put it in the data partition.
+#LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsWebViewStartupApp
+
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/webkit/app/AndroidManifest.xml b/hostsidetests/webkit/app/AndroidManifest.xml
new file mode 100644
index 0000000..2491d6c
--- /dev/null
+++ b/hostsidetests/webkit/app/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.webkit">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application android:maxRecents="1">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name=".WebViewStartupCtsActivity"
+            android:label="WebViewStartupCtsActivity"
+            android:screenOrientation="nosensor">
+            <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"
+        android:targetPackage="com.android.cts.webkit"/>
+
+</manifest>
diff --git a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
new file mode 100644
index 0000000..a47d653
--- /dev/null
+++ b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.webkit;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.StrictMode;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.Log;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.WebView;
+import android.webkit.cts.CtsTestServer;
+import android.webkit.cts.WebViewOnUiThread;
+import android.webkit.WebView;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Test class testing different aspects of WebView loading.
+ * The test methods in this class should be run one-and-one from the host-side to ensure we
+ * don't run the tests in the same process (since we can only load WebView into a process
+ * once - after that we will reuse the same webview provider).
+ * This works because the instrumentation used to run device-tests from the host-side terminates the
+ * testing process after each run.
+ * OBS! When adding a test here - remember to add a corresponding host-side test that will start the
+ * device-test added here! See com.android.cts.webkit.WebViewHostSideStartupTest.
+ */
+public class WebViewDeviceSideStartupTest
+        extends ActivityInstrumentationTestCase2<WebViewStartupCtsActivity> {
+
+    private static final String TAG = WebViewDeviceSideStartupTest.class.getSimpleName();
+
+    private WebViewStartupCtsActivity mActivity;
+
+    public WebViewDeviceSideStartupTest() {
+        super("com.android.cts.webkit", WebViewStartupCtsActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    @UiThreadTest
+    public void testCookieManagerBlockingUiThread() throws Throwable {
+        CtsTestServer server = new CtsTestServer(mActivity, false);
+        final String url = server.getCookieUrl("death.html");
+
+        Thread background = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                CookieSyncManager csm = CookieSyncManager.createInstance(mActivity);
+                CookieManager cookieManager = CookieManager.getInstance();
+
+                cookieManager.removeAllCookie();
+                cookieManager.setAcceptCookie(true);
+                cookieManager.setCookie(url, "count=41");
+                Log.i(TAG, "done setting cookie before creating webview");
+            }
+        });
+        NullWebViewUtils.NullWebViewFromThreadExceptionHandler h =
+                new NullWebViewUtils.NullWebViewFromThreadExceptionHandler();
+
+        background.setUncaughtExceptionHandler(h);
+        background.start();
+        background.join();
+
+        if (!h.isWebViewAvailable(mActivity)) {
+            return;
+        }
+
+        // Now create WebView and test that setting the cookie beforehand really worked.
+        mActivity.createAndAttachWebView();
+        WebViewOnUiThread onUiThread = new WebViewOnUiThread(this, mActivity.getWebView());
+        onUiThread.loadUrlAndWaitForCompletion(url);
+        assertEquals("1|count=41", onUiThread.getTitle()); // outgoing cookie
+        CookieManager cookieManager = CookieManager.getInstance();
+        String cookie = cookieManager.getCookie(url);
+        assertNotNull(cookie);
+        final Pattern pat = Pattern.compile("count=(\\d+)");
+        Matcher m = pat.matcher(cookie);
+        assertTrue(m.matches());
+        assertEquals("42", m.group(1)); // value got incremented
+    }
+
+    @UiThreadTest
+    public void testGetCurrentWebViewPackageOnUiThread() throws Throwable {
+        runCurrentWebViewPackageTest(true /* alreadyOnMainThread */);
+    }
+
+    public void testGetCurrentWebViewPackage() throws Throwable {
+        runCurrentWebViewPackageTest(false /* alreadyOnMainThread */);
+    }
+
+    private void runCurrentWebViewPackageTest(boolean alreadyOnMainThread) throws Exception {
+        PackageManager pm = mActivity.getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+            PackageInfo webViewPackage = WebView.getCurrentWebViewPackage();
+            // Ensure that getCurrentWebViewPackage returns a package recognized by the package
+            // manager.
+            assertPackageEquals(pm.getPackageInfo(webViewPackage.packageName, 0), webViewPackage);
+
+            // Create WebView on the app's main thread
+            if (alreadyOnMainThread) {
+                mActivity.createAndAttachWebView();
+            } else {
+                getInstrumentation().runOnMainSync(new Runnable() {
+                    @Override
+                    public void run() {
+                        mActivity.createAndAttachWebView();
+                    }
+                });
+            }
+
+            // Ensure we are still using the same WebView package.
+            assertPackageEquals(webViewPackage, WebView.getCurrentWebViewPackage());
+        } else {
+            // if WebView isn't supported the API should return null.
+            assertNull(WebView.getCurrentWebViewPackage());
+        }
+    }
+
+    private void assertPackageEquals(PackageInfo expected, PackageInfo actual) {
+        if (expected == null) assertNull(actual);
+        assertEquals(expected.packageName, actual.packageName);
+        assertEquals(expected.versionCode, actual.versionCode);
+        assertEquals(expected.versionName, actual.versionName);
+        assertEquals(expected.lastUpdateTime, actual.lastUpdateTime);
+    }
+
+    @UiThreadTest
+    public void testStrictModeNotViolatedOnStartup() throws Throwable {
+        StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
+        StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy();
+        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                .detectAll()
+                .penaltyLog()
+                .penaltyDeath()
+                .build());
+        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+                .detectAll()
+                .penaltyLog()
+                .penaltyDeath()
+                .build());
+
+        try {
+            createWebViewAndNavigate();
+            // Try to force Garbage Collection to catch any StrictMode violations triggered in
+            // finalizers.
+            for(int n = 0; n < 5; n++) {
+                Runtime.getRuntime().gc();
+                Thread.sleep(200);
+            }
+        } finally {
+            StrictMode.setThreadPolicy(oldThreadPolicy);
+            StrictMode.setVmPolicy(oldVmPolicy);
+        }
+    }
+
+    private void createWebViewAndNavigate() {
+        try {
+            mActivity.createAndAttachWebView();
+        } catch (Throwable t) {
+            NullWebViewUtils.determineIfWebViewAvailable(mActivity, t);
+            if (NullWebViewUtils.isWebViewAvailable()) {
+                // Rethrow t if WebView is available (because then we failed in some way that
+                // indicates that the device supports WebView but couldn't load it for some reason).
+                throw t;
+            } else {
+                // No WebView available - bail out!
+                return;
+            }
+        }
+
+        // WebView is available, so try to call some WebView APIs to ensure they don't cause
+        // strictmode violations
+
+        WebViewOnUiThread onUiThread = new WebViewOnUiThread(this, mActivity.getWebView());
+        onUiThread.loadUrlAndWaitForCompletion("about:blank");
+        onUiThread.loadUrlAndWaitForCompletion("");
+    }
+}
diff --git a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewStartupCtsActivity.java b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewStartupCtsActivity.java
new file mode 100644
index 0000000..7a96816
--- /dev/null
+++ b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewStartupCtsActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.webkit;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+
+public class WebViewStartupCtsActivity extends Activity {
+    private WebView mWebView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    public WebView createAndAttachWebView() {
+        mWebView = new WebView(this);
+        setContentView(mWebView);
+        return mWebView;
+    }
+
+    public WebView getWebView() {
+        return mWebView;
+    }
+
+    public void detachAndDestroyWebView() {
+        if (mWebView != null) {
+            ViewGroup vg = (ViewGroup)mWebView.getParent();
+            vg.removeView(mWebView);
+            mWebView.destroy();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        detachAndDestroyWebView();
+        super.onDestroy();
+    }
+}
diff --git a/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
new file mode 100644
index 0000000..53f4a49
--- /dev/null
+++ b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.webkit;
+
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.ddmlib.testrunner.TestRunResult;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.Map;
+
+public class WebViewHostSideStartupTest extends DeviceTestCase {
+    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+
+    private static final String DEVICE_WEBVIEW_STARTUP_PKG = "com.android.cts.webkit";
+    private static final String DEVICE_WEBVIEW_STARTUP_TEST_CLASS = "WebViewDeviceSideStartupTest";
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testCookieManager() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testCookieManagerBlockingUiThread"));
+    }
+
+    public void testWebViewVersionApiOnUiThread() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testGetCurrentWebViewPackageOnUiThread"));
+    }
+
+    public void testWebViewVersionApi() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testGetCurrentWebViewPackage"));
+    }
+
+    public void testStrictMode() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testStrictModeNotViolatedOnStartup"));
+    }
+
+    private boolean runDeviceTest(String packageName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+        testClassName = packageName + "." + testClassName;
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                packageName, RUNNER, getDevice().getIDevice());
+        testRunner.setMethodName(testClassName, testMethodName);
+
+        CollectingTestListener listener = new CollectingTestListener();
+        assertTrue(getDevice().runInstrumentationTests(testRunner, listener));
+
+        TestRunResult runResult = listener.getCurrentRunResults();
+        return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
+    }
+}
diff --git a/libs/deviceutil/Android.mk b/libs/deviceutil/Android.mk
deleted file mode 100644
index 2acbf67..0000000
--- a/libs/deviceutil/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ctsdeviceutil
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/deviceutil/jni/android_cts_FileUtils.cpp b/libs/deviceutil/jni/android_cts_FileUtils.cpp
deleted file mode 100644
index 91b74bf..0000000
--- a/libs/deviceutil/jni/android_cts_FileUtils.cpp
+++ /dev/null
@@ -1,145 +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.
- */
-
-#include <grp.h>
-#include <jni.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <assert.h>
-
-static jclass gFileStatusClass;
-static jfieldID gFileStatusDevFieldID;
-static jfieldID gFileStatusInoFieldID;
-static jfieldID gFileStatusModeFieldID;
-static jfieldID gFileStatusNlinkFieldID;
-static jfieldID gFileStatusUidFieldID;
-static jfieldID gFileStatusGidFieldID;
-static jfieldID gFileStatusSizeFieldID;
-static jfieldID gFileStatusBlksizeFieldID;
-static jfieldID gFileStatusBlocksFieldID;
-static jfieldID gFileStatusAtimeFieldID;
-static jfieldID gFileStatusMtimeFieldID;
-static jfieldID gFileStatusCtimeFieldID;
-
-/*
- * Native methods used by
- * cts/libs/deviceutil/src/android/cts/util/FileUtils.java
- *
- * Copied from hidden API: frameworks/base/core/jni/android_FileUtils.cpp
- */
-
-jboolean android_cts_FileUtils_getFileStatus(JNIEnv* env, jobject thiz,
-        jstring path, jobject fileStatus, jboolean statLinks)
-{
-    const char* pathStr = env->GetStringUTFChars(path, NULL);
-    jboolean ret = false;
-    struct stat s;
-
-    int res = statLinks == true ? lstat(pathStr, &s) : stat(pathStr, &s);
-
-    if (res == 0) {
-        ret = true;
-        if (fileStatus != NULL) {
-            env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
-            env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
-            env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
-            env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
-            env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
-            env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
-            env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
-            env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
-            env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
-            env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
-            env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
-            env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
-        }
-    }
-
-    env->ReleaseStringUTFChars(path, pathStr);
-
-    return ret;
-}
-
-jstring android_cts_FileUtils_getUserName(JNIEnv* env, jobject thiz,
-        jint uid)
-{
-    struct passwd *pwd = getpwuid(uid);
-    return env->NewStringUTF(pwd->pw_name);
-}
-
-jstring android_cts_FileUtils_getGroupName(JNIEnv* env, jobject thiz,
-        jint gid)
-{
-    struct group *grp = getgrgid(gid);
-    return env->NewStringUTF(grp->gr_name);
-}
-
-jint android_cts_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
-        jstring file, jint mode)
-{
-    const char *fileStr = env->GetStringUTFChars(file, NULL);
-    if (fileStr == NULL) {
-        return -1;
-    }
-
-    if (strlen(fileStr) <= 0) {
-        env->ReleaseStringUTFChars(file, fileStr);
-        return ENOENT;
-    }
-
-    jint returnValue = chmod(fileStr, mode) == 0 ? 0 : errno;
-    env->ReleaseStringUTFChars(file, fileStr);
-    return returnValue;
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "getFileStatus", "(Ljava/lang/String;Landroid/cts/util/FileUtils$FileStatus;Z)Z",
-            (void *) android_cts_FileUtils_getFileStatus  },
-    {  "getUserName", "(I)Ljava/lang/String;",
-            (void *) android_cts_FileUtils_getUserName  },
-    {  "getGroupName", "(I)Ljava/lang/String;",
-            (void *) android_cts_FileUtils_getGroupName  },
-    {  "setPermissions", "(Ljava/lang/String;I)I",
-            (void *) android_cts_FileUtils_setPermissions },
-};
-
-int register_android_cts_FileUtils(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/cts/util/FileUtils");
-    assert(clazz != null);
-
-    gFileStatusClass = env->FindClass("android/cts/util/FileUtils$FileStatus");
-    assert(gFileStatusClass != null);
-    gFileStatusDevFieldID = env->GetFieldID(gFileStatusClass, "dev", "I");
-    gFileStatusInoFieldID = env->GetFieldID(gFileStatusClass, "ino", "I");
-    gFileStatusModeFieldID = env->GetFieldID(gFileStatusClass, "mode", "I");
-    gFileStatusNlinkFieldID = env->GetFieldID(gFileStatusClass, "nlink", "I");
-    gFileStatusUidFieldID = env->GetFieldID(gFileStatusClass, "uid", "I");
-    gFileStatusGidFieldID = env->GetFieldID(gFileStatusClass, "gid", "I");
-    gFileStatusSizeFieldID = env->GetFieldID(gFileStatusClass, "size", "J");
-    gFileStatusBlksizeFieldID = env->GetFieldID(gFileStatusClass, "blksize", "I");
-    gFileStatusBlocksFieldID = env->GetFieldID(gFileStatusClass, "blocks", "J");
-    gFileStatusAtimeFieldID = env->GetFieldID(gFileStatusClass, "atime", "J");
-    gFileStatusMtimeFieldID = env->GetFieldID(gFileStatusClass, "mtime", "J");
-    gFileStatusCtimeFieldID = env->GetFieldID(gFileStatusClass, "ctime", "J");
-
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/libs/deviceutil/src/android/cts/util/BitmapUtils.java b/libs/deviceutil/src/android/cts/util/BitmapUtils.java
deleted file mode 100644
index 157ee27..0000000
--- a/libs/deviceutil/src/android/cts/util/BitmapUtils.java
+++ /dev/null
@@ -1,92 +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.WallpaperManager;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.Color;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.Method;
-import java.util.Random;
-
-public class BitmapUtils {
-    private BitmapUtils() {}
-
-    // Compares two bitmaps by pixels.
-    public static boolean compareBitmaps(Bitmap bmp1, Bitmap bmp2) {
-        if (bmp1 == bmp2) {
-            return true;
-        }
-
-        if (bmp1 == null || bmp2 == null) {
-            return false;
-        }
-
-        if ((bmp1.getWidth() != bmp2.getWidth()) || (bmp1.getHeight() != bmp2.getHeight())) {
-            return false;
-        }
-
-        for (int i = 0; i < bmp1.getWidth(); i++) {
-            for (int j = 0; j < bmp1.getHeight(); j++) {
-                if (bmp1.getPixel(i, j) != bmp2.getPixel(i, j)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    public static Bitmap generateRandomBitmap(int width, int height) {
-        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        final Random generator = new Random();
-        for (int x = 0; x < width; x++) {
-            for (int y = 0; y < height; y++) {
-                bmp.setPixel(x, y, generator.nextInt(Integer.MAX_VALUE));
-            }
-        }
-        return bmp;
-    }
-
-    public static Bitmap generateWhiteBitmap(int width, int height) {
-        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        for (int x = 0; x < width; x++) {
-            for (int y = 0; y < height; y++) {
-                bmp.setPixel(x, y, Color.WHITE);
-            }
-        }
-        return bmp;
-    }
-
-    public static Bitmap getWallpaperBitmap(Context context) throws Exception {
-        WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
-        Class<?> noparams[] = {};
-        Class<?> wmClass = wallpaperManager.getClass();
-        Method methodGetBitmap = wmClass.getDeclaredMethod("getBitmap", noparams);
-        return (Bitmap) methodGetBitmap.invoke(wallpaperManager, null);
-    }
-
-    public static ByteArrayInputStream bitmapToInputStream(Bitmap bmp) {
-        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
-        byte[] bitmapData = bos.toByteArray();
-        return new ByteArrayInputStream(bitmapData);
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/BroadcastTestBase.java b/libs/deviceutil/src/android/cts/util/BroadcastTestBase.java
deleted file mode 100644
index c4da8f3..0000000
--- a/libs/deviceutil/src/android/cts/util/BroadcastTestBase.java
+++ /dev/null
@@ -1,125 +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 android.cts.util;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.cts.util.BroadcastTestStartActivity;
-import android.cts.util.BroadcastUtils;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class BroadcastTestBase extends ActivityInstrumentationTestCase2<
-                                       BroadcastTestStartActivity> {
-    static final String TAG = "BroadcastTestBase";
-    protected static final int TIMEOUT_MS = 20 * 1000;
-
-    protected Context mContext;
-    protected Bundle mResultExtras;
-    private CountDownLatch mLatch;
-    protected ActivityDoneReceiver mActivityDoneReceiver = null;
-    private BroadcastTestStartActivity mActivity;
-    private BroadcastUtils.TestcaseType mTestCaseType;
-    protected boolean mHasFeature;
-
-    public BroadcastTestBase() {
-        super(BroadcastTestStartActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mHasFeature = false;
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mHasFeature && mActivityDoneReceiver != null) {
-            try {
-                mContext.unregisterReceiver(mActivityDoneReceiver);
-            } catch (IllegalArgumentException e) {
-                // This exception is thrown if mActivityDoneReceiver in
-                // the above call to unregisterReceiver is never registered.
-                // If so, no harm done by ignoring this exception.
-            }
-            mActivityDoneReceiver = null;
-        }
-        super.tearDown();
-    }
-
-    protected boolean isIntentSupported(String intentStr) {
-        Intent intent = new Intent(intentStr);
-        final PackageManager manager = mContext.getPackageManager();
-        assertNotNull(manager);
-        if (manager.resolveActivity(intent, 0) == null) {
-            Log.i(TAG, "No Activity found for the intent: " + intentStr);
-            return false;
-        }
-        return true;
-    }
-
-    protected void startTestActivity(String intentSuffix) {
-        Intent intent = new Intent();
-        intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
-        intent.setComponent(new ComponentName(getInstrumentation().getContext(),
-                BroadcastTestStartActivity.class));
-        setActivityIntent(intent);
-        mActivity = getActivity();
-    }
-
-    protected void registerBroadcastReceiver(BroadcastUtils.TestcaseType testCaseType) throws Exception {
-        mTestCaseType = testCaseType;
-        mLatch = new CountDownLatch(1);
-        mActivityDoneReceiver = new ActivityDoneReceiver();
-        mContext.registerReceiver(mActivityDoneReceiver,
-                new IntentFilter(BroadcastUtils.BROADCAST_INTENT + testCaseType.toString()));
-    }
-
-    protected boolean startTestAndWaitForBroadcast(BroadcastUtils.TestcaseType testCaseType,
-                                                   String pkg, String cls) throws Exception {
-        Log.i(TAG, "Begin Testing: " + testCaseType);
-        registerBroadcastReceiver(testCaseType);
-        mActivity.startTest(testCaseType.toString(), pkg, cls);
-        if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-            fail("Failed to receive broadcast in " + TIMEOUT_MS + "msec");
-            return false;
-        }
-        return true;
-    }
-
-    class ActivityDoneReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(
-                    BroadcastUtils.BROADCAST_INTENT +
-                        BroadcastTestBase.this.mTestCaseType.toString())) {
-                Bundle extras = intent.getExtras();
-                Log.i(TAG, "received_broadcast for " + BroadcastUtils.toBundleString(extras));
-                BroadcastTestBase.this.mResultExtras = extras;
-                mLatch.countDown();
-            }
-        }
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/BroadcastTestStartActivity.java b/libs/deviceutil/src/android/cts/util/BroadcastTestStartActivity.java
deleted file mode 100644
index fda6786..0000000
--- a/libs/deviceutil/src/android/cts/util/BroadcastTestStartActivity.java
+++ /dev/null
@@ -1,80 +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 android.cts.util;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.util.Log;
-
-import android.cts.util.BroadcastUtils;
-
-public class BroadcastTestStartActivity extends Activity {
-    static final String TAG = "BroadcastTestStartActivity";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Log.i(TAG, " in onCreate");
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        Log.i(TAG, " in onResume");
-    }
-
-    void startTest(String testCaseType, String pkg, String cls) {
-        Intent intent = new Intent();
-        Log.i(TAG, "received_testcasetype = " + testCaseType);
-        intent.putExtra(BroadcastUtils.TESTCASE_TYPE, testCaseType);
-        intent.setAction("android.intent.action.VIMAIN_" + testCaseType);
-        intent.setComponent(new ComponentName(pkg, cls));
-        startActivity(intent);
-    }
-
-    @Override
-    protected void onPause() {
-        Log.i(TAG, " in onPause");
-        super.onPause();
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        Log.i(TAG, " in onStart");
-    }
-
-    @Override
-    protected void onRestart() {
-        super.onRestart();
-        Log.i(TAG, " in onRestart");
-    }
-
-    @Override
-    protected void onStop() {
-        Log.i(TAG, " in onStop");
-        super.onStop();
-    }
-
-    @Override
-    protected void onDestroy() {
-        Log.i(TAG, " in onDestroy");
-        super.onDestroy();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/BroadcastUtils.java b/libs/deviceutil/src/android/cts/util/BroadcastUtils.java
deleted file mode 100644
index 1392df2..0000000
--- a/libs/deviceutil/src/android/cts/util/BroadcastUtils.java
+++ /dev/null
@@ -1,49 +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 android.cts.util;
-
-import android.os.Bundle;
-
-public class BroadcastUtils {
-    public enum TestcaseType {
-        ZEN_MODE_ON,
-        ZEN_MODE_OFF,
-        AIRPLANE_MODE_ON,
-        AIRPLANE_MODE_OFF,
-        BATTERYSAVER_MODE_ON,
-        BATTERYSAVER_MODE_OFF,
-        THEATER_MODE_ON,
-        THEATER_MODE_OFF
-    }
-    public static final String TESTCASE_TYPE = "Testcase_type";
-    public static final String BROADCAST_INTENT =
-            "android.intent.action.FROM_UTIL_CTS_TEST_";
-    public static final int NUM_MINUTES_FOR_ZENMODE = 10;
-
-    public static final String toBundleString(Bundle bundle) {
-        if (bundle == null) {
-            return "*** Bundle is null ****";
-        }
-        StringBuilder buf = new StringBuilder();
-        if (bundle != null) {
-            buf.append("extras: ");
-            for (String s : bundle.keySet()) {
-                buf.append("(" + s + " = " + bundle.get(s) + "), ");
-            }
-        }
-        return buf.toString();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/CTSResult.java b/libs/deviceutil/src/android/cts/util/CTSResult.java
deleted file mode 100644
index c780f57..0000000
--- a/libs/deviceutil/src/android/cts/util/CTSResult.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-package android.cts.util;
-
-public interface CTSResult {
-    public static final int RESULT_OK = 1;
-    public static final int RESULT_FAIL = 2;
-    public void setResult(int resultCode);
-}
diff --git a/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java b/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java
deleted file mode 100644
index 7cf0f7e..0000000
--- a/libs/deviceutil/src/android/cts/util/CtsAndroidTestCase.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.
- */
-
-
-package android.cts.util;
-
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-
-/**
- *  This class emulates AndroidTestCase, but internally it is ActivityInstrumentationTestCase2
- *  to access Instrumentation.
- *  DummyActivity is not supposed to be accessed.
- */
-public class CtsAndroidTestCase extends ActivityInstrumentationTestCase2<DummyActivity> {
-    public CtsAndroidTestCase() {
-        super(DummyActivity.class);
-    }
-
-    public Context getContext() {
-        return getInstrumentation().getContext();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/DummyActivity.java b/libs/deviceutil/src/android/cts/util/DummyActivity.java
deleted file mode 100644
index 16e3507..0000000
--- a/libs/deviceutil/src/android/cts/util/DummyActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.Activity;
-
-public class DummyActivity extends Activity {
-
-}
diff --git a/libs/deviceutil/src/android/cts/util/EvaluateJsResultPollingCheck.java b/libs/deviceutil/src/android/cts/util/EvaluateJsResultPollingCheck.java
deleted file mode 100644
index 17d6a73..0000000
--- a/libs/deviceutil/src/android/cts/util/EvaluateJsResultPollingCheck.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.webkit.ValueCallback;
-
-public class EvaluateJsResultPollingCheck  extends PollingCheck
-        implements ValueCallback<String> {
-    private String mActualResult;
-    private String mExpectedResult;
-
-    public EvaluateJsResultPollingCheck(String expected) {
-        mExpectedResult = expected;
-    }
-
-    @Override
-    public synchronized boolean check() {
-        return mExpectedResult.equals(mActualResult);
-    }
-
-    @Override
-    public synchronized void onReceiveValue(String result) {
-        mActualResult = result;
-    }
-}
\ No newline at end of file
diff --git a/libs/deviceutil/src/android/cts/util/FileCopyHelper.java b/libs/deviceutil/src/android/cts/util/FileCopyHelper.java
deleted file mode 100644
index e84e920..0000000
--- a/libs/deviceutil/src/android/cts/util/FileCopyHelper.java
+++ /dev/null
@@ -1,100 +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.cts.util;
-
-import android.content.Context;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
-/**
- * The Class FileCopyHelper is used to copy files from resources to the
- * application directory and responsible for deleting the files.
- *
- * @see MediaStore_VideoTest
- * @see MediaStore_Images_MediaTest
- * @see MediaStore_Images_ThumbnailsTest
- */
-public class FileCopyHelper {
-    /** The context. */
-    private Context mContext;
-
-    /** The files added. */
-    private ArrayList<String> mFilesList;
-
-    /**
-     * Instantiates a new file copy helper.
-     *
-     * @param context the context
-     */
-    public FileCopyHelper(Context context) {
-        mContext = context;
-        mFilesList = new ArrayList<String>();
-    }
-
-    /**
-     * Copy the file from the resources with a filename .
-     *
-     * @param resId the res id
-     * @param fileName the file name
-     *
-     * @return the absolute path of the destination file
-     * @throws IOException
-     */
-    public String copy(int resId, String fileName) throws IOException {
-        InputStream source = mContext.getResources().openRawResource(resId);
-        OutputStream target = mContext.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
-        copyFile(source, target);
-        mFilesList.add(fileName);
-        return mContext.getFileStreamPath(fileName).getAbsolutePath();
-    }
-
-    public void copyToExternalStorage(int resId, File path) throws IOException {
-        InputStream source = mContext.getResources().openRawResource(resId);
-        OutputStream target = new FileOutputStream(path);
-        copyFile(source, target);
-    }
-
-    private void copyFile(InputStream source, OutputStream target) throws IOException {
-        try {
-            byte[] buffer = new byte[1024];
-            for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
-                target.write(buffer, 0, len);
-            }
-        } finally {
-            if (source != null) {
-                source.close();
-            }
-            if (target != null) {
-                target.close();
-            }
-        }
-    }
-
-    /**
-     * Delete all the files copied by the helper.
-     */
-    public void clear(){
-        for (String path : mFilesList) {
-            mContext.deleteFile(path);
-        }
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/FileUtils.java b/libs/deviceutil/src/android/cts/util/FileUtils.java
deleted file mode 100644
index 055f2d6..0000000
--- a/libs/deviceutil/src/android/cts/util/FileUtils.java
+++ /dev/null
@@ -1,163 +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.cts.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/** Bits and pieces copied from hidden API of android.os.FileUtils. */
-public class FileUtils {
-
-    public static final int S_IFMT  = 0170000;
-    public static final int S_IFSOCK = 0140000;
-    public static final int S_IFLNK = 0120000;
-    public static final int S_IFREG = 0100000;
-    public static final int S_IFBLK = 0060000;
-    public static final int S_IFDIR = 0040000;
-    public static final int S_IFCHR = 0020000;
-    public static final int S_IFIFO = 0010000;
-
-    public static final int S_ISUID = 0004000;
-    public static final int S_ISGID = 0002000;
-    public static final int S_ISVTX = 0001000;
-
-    public static final int S_IRWXU = 00700;
-    public static final int S_IRUSR = 00400;
-    public static final int S_IWUSR = 00200;
-    public static final int S_IXUSR = 00100;
-
-    public static final int S_IRWXG = 00070;
-    public static final int S_IRGRP = 00040;
-    public static final int S_IWGRP = 00020;
-    public static final int S_IXGRP = 00010;
-
-    public static final int S_IRWXO = 00007;
-    public static final int S_IROTH = 00004;
-    public static final int S_IWOTH = 00002;
-    public static final int S_IXOTH = 00001;
-
-    static {
-        System.loadLibrary("cts_jni");
-    }
-
-    public static class FileStatus {
-
-        public int dev;
-        public int ino;
-        public int mode;
-        public int nlink;
-        public int uid;
-        public int gid;
-        public int rdev;
-        public long size;
-        public int blksize;
-        public long blocks;
-        public long atime;
-        public long mtime;
-        public long ctime;
-
-        public boolean hasModeFlag(int flag) {
-            if (((S_IRWXU | S_IRWXG | S_IRWXO) & flag) != flag) {
-                throw new IllegalArgumentException("Inappropriate flag " + flag);
-            }
-            return (mode & flag) == flag;
-        }
-
-        public boolean isOfType(int type) {
-            if ((type & S_IFMT) != type) {
-                throw new IllegalArgumentException("Unknown type " + type);
-            }
-            return (mode & S_IFMT) == type;
-        }
-    }
-
-    /**
-     * @param path of the file to stat
-     * @param status object to set the fields on
-     * @param statLinks or don't stat links (lstat vs stat)
-     * @return whether or not we were able to stat the file
-     */
-    public native static boolean getFileStatus(String path, FileStatus status, boolean statLinks);
-
-    public native static String getUserName(int uid);
-
-    public native static String getGroupName(int gid);
-
-    public native static int setPermissions(String file, int mode);
-
-    /**
-     * Copy data from a source stream to destFile.
-     * Return true if succeed, return false if failed.
-     */
-    public static boolean copyToFile(InputStream inputStream, File destFile) {
-        try {
-            if (destFile.exists()) {
-                destFile.delete();
-            }
-            FileOutputStream out = new FileOutputStream(destFile);
-            try {
-                byte[] buffer = new byte[4096];
-                int bytesRead;
-                while ((bytesRead = inputStream.read(buffer)) >= 0) {
-                    out.write(buffer, 0, bytesRead);
-                }
-            } finally {
-                out.flush();
-                try {
-                    out.getFD().sync();
-                } catch (IOException e) {
-                }
-                out.close();
-            }
-            return true;
-        } catch (IOException e) {
-            return false;
-        }
-    }
-
-    public static void createFile(File file, int numBytes) throws IOException {
-        File parentFile = file.getParentFile();
-        if (parentFile != null) {
-            parentFile.mkdirs();
-        }
-        byte[] buffer = new byte[numBytes];
-        FileOutputStream output = new FileOutputStream(file);
-        try {
-            output.write(buffer);
-        } finally {
-            output.close();
-        }
-    }
-
-    public static byte[] readInputStreamFully(InputStream is) {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        byte[] buffer = new byte[32768];
-        int count;
-        try {
-            while ((count = is.read(buffer)) != -1) {
-                os.write(buffer, 0, count);
-            }
-            is.close();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        return os.toByteArray();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/IBinderParcelable.java b/libs/deviceutil/src/android/cts/util/IBinderParcelable.java
deleted file mode 100644
index c80716e..0000000
--- a/libs/deviceutil/src/android/cts/util/IBinderParcelable.java
+++ /dev/null
@@ -1,52 +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.cts.util;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class IBinderParcelable implements Parcelable {
-    public IBinder binder;
-
-    public IBinderParcelable(IBinder source) {
-        binder = source;
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(binder);
-    }
-
-    public static final Parcelable.Creator<IBinderParcelable>
-        CREATOR = new Parcelable.Creator<IBinderParcelable>() {
-
-        public IBinderParcelable createFromParcel(Parcel source) {
-            return new IBinderParcelable(source);
-        }
-
-        public IBinderParcelable[] newArray(int size) {
-            return new IBinderParcelable[size];
-        }
-    };
-
-    private IBinderParcelable(Parcel source) {
-        binder = source.readStrongBinder();
-    }
-}
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/LocationUtils.java b/libs/deviceutil/src/android/cts/util/LocationUtils.java
deleted file mode 100644
index 1f7af86..0000000
--- a/libs/deviceutil/src/android/cts/util/LocationUtils.java
+++ /dev/null
@@ -1,40 +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 android.cts.util;
-
-import android.app.Instrumentation;
-import android.util.Log;
-
-import java.io.IOException;
-
-public class LocationUtils {
-    private static String TAG = "LocationUtils";
-
-    public static void registerMockLocationProvider(Instrumentation instrumentation,
-            boolean enable) {
-        StringBuilder command = new StringBuilder();
-        command.append("appops set ");
-        command.append(instrumentation.getContext().getPackageName());
-        command.append(" android:mock_location ");
-        command.append(enable ? "allow" : "deny");
-        try {
-            SystemUtil.runShellCommand(instrumentation, command.toString());
-        } catch (IOException e) {
-            Log.e(TAG, "Error managing mock location app. Command: " + command, e);
-        }
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java b/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
deleted file mode 100644
index decbd4c..0000000
--- a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.
- */
-package android.cts.util;
-
-import android.media.MediaFormat;
-import android.util.Range;
-
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import java.util.Arrays;
-import android.util.Log;
-
-public class MediaPerfUtils {
-    private static final String TAG = "MediaPerfUtils";
-
-    private static final int MOVING_AVERAGE_NUM_FRAMES = 10;
-    private static final int MOVING_AVERAGE_WINDOW_MS = 1000;
-
-    // allow a variance of 2x for measured frame rates (e.g. half of lower-limit to double of
-    // upper-limit of the published values). Also allow an extra 10% margin. This also acts as
-    // a limit for the size of the published rates (e.g. upper-limit / lower-limit <= tolerance).
-    private static final double FRAMERATE_TOLERANCE = 2.0 * 1.1;
-
-    /*
-     *  ------------------ HELPER METHODS FOR ACHIEVABLE FRAME RATES ------------------
-     */
-
-    /** removes brackets from format to be included in JSON. */
-    private static String formatForReport(MediaFormat format) {
-        String asString = "" + format;
-        return asString.substring(1, asString.length() - 1);
-    }
-
-    /**
-     * Adds performance header info to |log| for |codecName|, |round|, |configFormat|, |inputFormat|
-     * and |outputFormat|. Also appends same to |message| and returns the resulting base message
-     * for logging purposes.
-     */
-    public static String addPerformanceHeadersToLog(
-            DeviceReportLog log, String message, int round, String codecName,
-            MediaFormat configFormat, MediaFormat inputFormat, MediaFormat outputFormat) {
-        String mime = configFormat.getString(MediaFormat.KEY_MIME);
-        int width = configFormat.getInteger(MediaFormat.KEY_WIDTH);
-        int height = configFormat.getInteger(MediaFormat.KEY_HEIGHT);
-
-        log.addValue("round", round, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("codec_name", codecName, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("mime_type", mime, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("width", width, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("height", height, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("config_format", formatForReport(configFormat),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("input_format", formatForReport(inputFormat),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("output_format", formatForReport(outputFormat),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-
-        message += " codec=" + codecName + " round=" + round + " configFormat=" + configFormat
-                + " inputFormat=" + inputFormat + " outputFormat=" + outputFormat;
-
-        Range<Double> reported =
-            MediaUtils.getVideoCapabilities(codecName, mime)
-                    .getAchievableFrameRatesFor(width, height);
-        if (reported != null) {
-            log.addValue("reported_low", reported.getLower(), ResultType.NEUTRAL, ResultUnit.FPS);
-            log.addValue("reported_high", reported.getUpper(), ResultType.NEUTRAL, ResultUnit.FPS);
-            message += " reported=" + reported.getLower() + "-" + reported.getUpper();
-        }
-
-        return message;
-    }
-
-    /**
-     * Adds performance statistics based on the raw |stats| to |log|. Also prints the same into
-     * logcat. Returns the "final fps" value.
-     */
-    public static double addPerformanceStatsToLog(
-            DeviceReportLog log, MediaUtils.Stats durationsUsStats, String message) {
-
-        MediaUtils.Stats frameAvgUsStats =
-            durationsUsStats.movingAverage(MOVING_AVERAGE_NUM_FRAMES);
-        log.addValue(
-                "window_frames", MOVING_AVERAGE_NUM_FRAMES, ResultType.NEUTRAL, ResultUnit.COUNT);
-        logPerformanceStats(log, frameAvgUsStats, "frame_avg_stats",
-                message + " window=" + MOVING_AVERAGE_NUM_FRAMES);
-
-        MediaUtils.Stats timeAvgUsStats =
-            durationsUsStats.movingAverageOverSum(MOVING_AVERAGE_WINDOW_MS * 1000);
-        log.addValue("window_time", MOVING_AVERAGE_WINDOW_MS, ResultType.NEUTRAL, ResultUnit.MS);
-        double fps = logPerformanceStats(log, timeAvgUsStats, "time_avg_stats",
-                message + " windowMs=" + MOVING_AVERAGE_WINDOW_MS);
-
-        log.setSummary("fps", fps, ResultType.HIGHER_BETTER, ResultUnit.FPS);
-        return fps;
-    }
-
-    /**
-     * Adds performance statistics based on the processed |stats| to |log| using |prefix|.
-     * Also prints the same into logcat using |message| as the base message. Returns the fps value
-     * for |stats|. |prefix| must be lowercase alphanumeric underscored format.
-     */
-    private static double logPerformanceStats(
-            DeviceReportLog log, MediaUtils.Stats statsUs, String prefix, String message) {
-        final String[] labels = {
-            "min", "p5", "p10", "p20", "p30", "p40", "p50", "p60", "p70", "p80", "p90", "p95", "max"
-        };
-        final double[] points = {
-             0,     5,    10,    20,    30,    40,    50,    60,    70,    80,    90,    95,    100
-        };
-
-        int num = statsUs.getNum();
-        long avg = Math.round(statsUs.getAverage());
-        long stdev = Math.round(statsUs.getStdev());
-        log.addValue(prefix + "_num", num, ResultType.NEUTRAL, ResultUnit.COUNT);
-        log.addValue(prefix + "_avg", avg / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
-        log.addValue(prefix + "_stdev", stdev / 1000., ResultType.LOWER_BETTER, ResultUnit.MS);
-        message += " num=" + num + " avg=" + avg + " stdev=" + stdev;
-        final double[] percentiles = statsUs.getPercentiles(points);
-        for (int i = 0; i < labels.length; ++i) {
-            long p = Math.round(percentiles[i]);
-            message += " " + labels[i] + "=" + p;
-            log.addValue(prefix + "_" + labels[i], p / 1000., ResultType.NEUTRAL, ResultUnit.MS);
-        }
-
-        // print result to logcat in case test aborts before logs are written
-        Log.i(TAG, message);
-
-        return 1e6 / percentiles[points.length - 2];
-    }
-
-    /** Verifies |measuredFps| against reported achievable rates. Returns null if at least
-     *  one measurement falls within the margins of the reported range. Otherwise, returns
-     *  an error message to display.*/
-    public static String verifyAchievableFrameRates(
-            String name, String mime, int w, int h, double... measuredFps) {
-        Range<Double> reported =
-            MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
-        String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
-        if (reported == null) {
-            return "Failed to get " + kind;
-        }
-        double lowerBoundary1 = reported.getLower() / FRAMERATE_TOLERANCE;
-        double upperBoundary1 = reported.getUpper() * FRAMERATE_TOLERANCE;
-        double lowerBoundary2 = reported.getUpper() / Math.pow(FRAMERATE_TOLERANCE, 2);
-        double upperBoundary2 = reported.getLower() * Math.pow(FRAMERATE_TOLERANCE, 2);
-        Log.d(TAG, name + " " + mime + " " + w + "x" + h +
-                " lowerBoundary1 " + lowerBoundary1 + " upperBoundary1 " + upperBoundary1 +
-                " lowerBoundary2 " + lowerBoundary2 + " upperBoundary2 " + upperBoundary2 +
-                " measured " + Arrays.toString(measuredFps));
-
-        for (double measured : measuredFps) {
-            if (measured >= lowerBoundary1 && measured <= upperBoundary1
-                    && measured >= lowerBoundary2 && measured <= upperBoundary2) {
-                return null;
-            }
-        }
-
-        return "Expected " + kind + ": " + reported + ".\n"
-                + "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
deleted file mode 100644
index 2c6aeae..0000000
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * 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 android.cts.util;
-
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecInfo.VideoCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaExtractor;
-import android.media.MediaFormat;
-import android.net.Uri;
-import android.util.Log;
-import android.util.Range;
-
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import java.lang.reflect.Method;
-import static java.lang.reflect.Modifier.isPublic;
-import static java.lang.reflect.Modifier.isStatic;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Map;
-
-import static junit.framework.Assert.assertTrue;
-
-import java.io.IOException;
-
-public class MediaUtils {
-    private static final String TAG = "MediaUtils";
-
-    /*
-     *  ----------------------- HELPER METHODS FOR SKIPPING TESTS -----------------------
-     */
-    private static final int ALL_AV_TRACKS = -1;
-
-    private static final MediaCodecList sMCL = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-
-    /**
-     * Returns the test name (heuristically).
-     *
-     * Since it uses heuristics, this method has only been verified for media
-     * tests. This centralizes the way to signal errors during a test.
-     */
-    public static String getTestName() {
-        return getTestName(false /* withClass */);
-    }
-
-    /**
-     * Returns the test name with the full class (heuristically).
-     *
-     * Since it uses heuristics, this method has only been verified for media
-     * tests. This centralizes the way to signal errors during a test.
-     */
-    public static String getTestNameWithClass() {
-        return getTestName(true /* withClass */);
-    }
-
-    private static String getTestName(boolean withClass) {
-        int bestScore = -1;
-        String testName = "test???";
-        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
-        for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
-            StackTraceElement[] stack = entry.getValue();
-            for (int index = 0; index < stack.length; ++index) {
-                // method name must start with "test"
-                String methodName = stack[index].getMethodName();
-                if (!methodName.startsWith("test")) {
-                    continue;
-                }
-
-                int score = 0;
-                // see if there is a public non-static void method that takes no argument
-                Class<?> clazz;
-                try {
-                    clazz = Class.forName(stack[index].getClassName());
-                    ++score;
-                    for (final Method method : clazz.getDeclaredMethods()) {
-                        if (method.getName().equals(methodName)
-                                && isPublic(method.getModifiers())
-                                && !isStatic(method.getModifiers())
-                                && method.getParameterTypes().length == 0
-                                && method.getReturnType().equals(Void.TYPE)) {
-                            ++score;
-                            break;
-                        }
-                    }
-                    if (score == 1) {
-                        // if we could read the class, but method is not public void, it is
-                        // not a candidate
-                        continue;
-                    }
-                } catch (ClassNotFoundException e) {
-                }
-
-                // even if we cannot verify the method signature, there are signals in the stack
-
-                // usually test method is invoked by reflection
-                int depth = 1;
-                while (index + depth < stack.length
-                        && stack[index + depth].getMethodName().equals("invoke")
-                        && stack[index + depth].getClassName().equals(
-                                "java.lang.reflect.Method")) {
-                    ++depth;
-                }
-                if (depth > 1) {
-                    ++score;
-                    // and usually test method is run by runMethod method in android.test package
-                    if (index + depth < stack.length) {
-                        if (stack[index + depth].getClassName().startsWith("android.test.")) {
-                            ++score;
-                        }
-                        if (stack[index + depth].getMethodName().equals("runMethod")) {
-                            ++score;
-                        }
-                    }
-                }
-
-                if (score > bestScore) {
-                    bestScore = score;
-                    testName = methodName;
-                    if (withClass) {
-                        testName = stack[index].getClassName() + "." + testName;
-                    }
-                }
-            }
-        }
-        return testName;
-    }
-
-    /**
-     * Finds test name (heuristically) and prints out standard skip message.
-     *
-     * Since it uses heuristics, this method has only been verified for media
-     * tests. This centralizes the way to signal a skipped test.
-     */
-    public static void skipTest(String tag, String reason) {
-        Log.i(tag, "SKIPPING " + getTestName() + "(): " + reason);
-        DeviceReportLog log = new DeviceReportLog("CtsMediaSkippedTests", "test_skipped");
-        log.addValue("reason", reason, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue(
-                "test", getTestNameWithClass(), ResultType.NEUTRAL, ResultUnit.NONE);
-        // TODO: replace with submit() when it is added to DeviceReportLog
-        try {
-            log.submit(null);
-        } catch (NullPointerException e) { }
-    }
-
-    /**
-     * Finds test name (heuristically) and prints out standard skip message.
-     *
-     * Since it uses heuristics, this method has only been verified for media
-     * tests.  This centralizes the way to signal a skipped test.
-     */
-    public static void skipTest(String reason) {
-        skipTest(TAG, reason);
-    }
-
-    public static boolean check(boolean result, String message) {
-        if (!result) {
-            skipTest(message);
-        }
-        return result;
-    }
-
-    /*
-     *  ------------------- HELPER METHODS FOR CHECKING CODEC SUPPORT -------------------
-     */
-
-    // returns the list of codecs that support any one of the formats
-    private static String[] getCodecNames(
-            boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
-        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        ArrayList<String> result = new ArrayList<>();
-        for (MediaCodecInfo info : mcl.getCodecInfos()) {
-            if (info.isEncoder() != isEncoder) {
-                continue;
-            }
-            if (isGoog != null
-                    && info.getName().toLowerCase().startsWith("omx.google.") != isGoog) {
-                continue;
-            }
-
-            for (MediaFormat format : formats) {
-                String mime = format.getString(MediaFormat.KEY_MIME);
-
-                CodecCapabilities caps = null;
-                try {
-                    caps = info.getCapabilitiesForType(mime);
-                } catch (IllegalArgumentException e) {  // mime is not supported
-                    continue;
-                }
-                if (caps.isFormatSupported(format)) {
-                    result.add(info.getName());
-                    break;
-                }
-            }
-        }
-        return result.toArray(new String[result.size()]);
-    }
-
-    /* Use isGoog = null to query all decoders */
-    public static String[] getDecoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
-        return getCodecNames(false /* isEncoder */, isGoog, formats);
-    }
-
-    public static String[] getDecoderNames(MediaFormat... formats) {
-        return getCodecNames(false /* isEncoder */, null /* isGoog */, formats);
-    }
-
-    /* Use isGoog = null to query all decoders */
-    public static String[] getEncoderNames(/* Nullable */ Boolean isGoog, MediaFormat... formats) {
-        return getCodecNames(true /* isEncoder */, isGoog, formats);
-    }
-
-    public static String[] getEncoderNames(MediaFormat... formats) {
-        return getCodecNames(true /* isEncoder */, null /* isGoog */, formats);
-    }
-
-    public static void verifyNumCodecs(
-            int count, boolean isEncoder, Boolean isGoog, MediaFormat... formats) {
-        String desc = (isEncoder ? "encoders" : "decoders") + " for "
-                + (formats.length == 1 ? formats[0].toString() : Arrays.toString(formats));
-        if (isGoog != null) {
-            desc = (isGoog ? "Google " : "non-Google ") + desc;
-        }
-
-        String[] codecs = getCodecNames(isEncoder, isGoog, formats);
-        assertTrue("test can only verify " + count + " " + desc + "; found " + codecs.length + ": "
-                + Arrays.toString(codecs), codecs.length <= count);
-    }
-
-    public static MediaCodec getDecoder(MediaFormat format) {
-        String decoder = sMCL.findDecoderForFormat(format);
-        if (decoder != null) {
-            try {
-                return MediaCodec.createByCodecName(decoder);
-            } catch (IOException e) {
-            }
-        }
-        return null;
-    }
-
-    public static boolean canEncode(MediaFormat format) {
-        if (sMCL.findEncoderForFormat(format) == null) {
-            Log.i(TAG, "no encoder for " + format);
-            return false;
-        }
-        return true;
-    }
-
-    public static boolean canDecode(MediaFormat format) {
-        if (sMCL.findDecoderForFormat(format) == null) {
-            Log.i(TAG, "no decoder for " + format);
-            return false;
-        }
-        return true;
-    }
-
-    public static boolean supports(String codecName, String mime, int w, int h) {
-        // While this could be simply written as such, give more graceful feedback.
-        // MediaFormat format = MediaFormat.createVideoFormat(mime, w, h);
-        // return supports(codecName, format);
-
-        VideoCapabilities vidCap = getVideoCapabilities(codecName, mime);
-        if (vidCap == null) {
-            return false;
-        } else if (vidCap.isSizeSupported(w, h)) {
-            return true;
-        }
-
-        Log.w(TAG, "unsupported size " + w + "x" + h);
-        return false;
-    }
-
-    public static boolean supports(String codecName, MediaFormat format) {
-        MediaCodec codec;
-        try {
-            codec = MediaCodec.createByCodecName(codecName);
-        } catch (IOException e) {
-            Log.w(TAG, "codec not found: " + codecName);
-            return false;
-        }
-
-        String mime = format.getString(MediaFormat.KEY_MIME);
-        CodecCapabilities cap = null;
-        try {
-            cap = codec.getCodecInfo().getCapabilitiesForType(mime);
-            return cap.isFormatSupported(format);
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "not supported mime: " + mime);
-            return false;
-        } finally {
-            codec.release();
-        }
-    }
-
-    public static boolean hasCodecForTrack(MediaExtractor ex, int track) {
-        int count = ex.getTrackCount();
-        if (track < 0 || track >= count) {
-            throw new IndexOutOfBoundsException(track + " not in [0.." + (count - 1) + "]");
-        }
-        return canDecode(ex.getTrackFormat(track));
-    }
-
-    /**
-     * return true iff all audio and video tracks are supported
-     */
-    public static boolean hasCodecsForMedia(MediaExtractor ex) {
-        for (int i = 0; i < ex.getTrackCount(); ++i) {
-            MediaFormat format = ex.getTrackFormat(i);
-            // only check for audio and video codecs
-            String mime = format.getString(MediaFormat.KEY_MIME).toLowerCase();
-            if (!mime.startsWith("audio/") && !mime.startsWith("video/")) {
-                continue;
-            }
-            if (!canDecode(format)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * return true iff any track starting with mimePrefix is supported
-     */
-    public static boolean hasCodecForMediaAndDomain(MediaExtractor ex, String mimePrefix) {
-        mimePrefix = mimePrefix.toLowerCase();
-        for (int i = 0; i < ex.getTrackCount(); ++i) {
-            MediaFormat format = ex.getTrackFormat(i);
-            String mime = format.getString(MediaFormat.KEY_MIME);
-            if (mime.toLowerCase().startsWith(mimePrefix)) {
-                if (canDecode(format)) {
-                    return true;
-                }
-                Log.i(TAG, "no decoder for " + format);
-            }
-        }
-        return false;
-    }
-
-    private static boolean hasCodecsForResourceCombo(
-            Context context, int resourceId, int track, String mimePrefix) {
-        try {
-            AssetFileDescriptor afd = null;
-            MediaExtractor ex = null;
-            try {
-                afd = context.getResources().openRawResourceFd(resourceId);
-                ex = new MediaExtractor();
-                ex.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-                if (mimePrefix != null) {
-                    return hasCodecForMediaAndDomain(ex, mimePrefix);
-                } else if (track == ALL_AV_TRACKS) {
-                    return hasCodecsForMedia(ex);
-                } else {
-                    return hasCodecForTrack(ex, track);
-                }
-            } finally {
-                if (ex != null) {
-                    ex.release();
-                }
-                if (afd != null) {
-                    afd.close();
-                }
-            }
-        } catch (IOException e) {
-            Log.i(TAG, "could not open resource");
-        }
-        return false;
-    }
-
-    /**
-     * return true iff all audio and video tracks are supported
-     */
-    public static boolean hasCodecsForResource(Context context, int resourceId) {
-        return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, null /* mimePrefix */);
-    }
-
-    public static boolean checkCodecsForResource(Context context, int resourceId) {
-        return check(hasCodecsForResource(context, resourceId), "no decoder found");
-    }
-
-    /**
-     * return true iff track is supported.
-     */
-    public static boolean hasCodecForResource(Context context, int resourceId, int track) {
-        return hasCodecsForResourceCombo(context, resourceId, track, null /* mimePrefix */);
-    }
-
-    public static boolean checkCodecForResource(Context context, int resourceId, int track) {
-        return check(hasCodecForResource(context, resourceId, track), "no decoder found");
-    }
-
-    /**
-     * return true iff any track starting with mimePrefix is supported
-     */
-    public static boolean hasCodecForResourceAndDomain(
-            Context context, int resourceId, String mimePrefix) {
-        return hasCodecsForResourceCombo(context, resourceId, ALL_AV_TRACKS, mimePrefix);
-    }
-
-    /**
-     * return true iff all audio and video tracks are supported
-     */
-    public static boolean hasCodecsForPath(Context context, String path) {
-        MediaExtractor ex = null;
-        try {
-            ex = new MediaExtractor();
-            Uri uri = Uri.parse(path);
-            String scheme = uri.getScheme();
-            if (scheme == null) { // file
-                ex.setDataSource(path);
-            } else if (scheme.equalsIgnoreCase("file")) {
-                ex.setDataSource(uri.getPath());
-            } else {
-                ex.setDataSource(context, uri, null);
-            }
-            return hasCodecsForMedia(ex);
-        } catch (IOException e) {
-            Log.i(TAG, "could not open path " + path);
-        } finally {
-            if (ex != null) {
-                ex.release();
-            }
-        }
-        return true;
-    }
-
-    public static boolean checkCodecsForPath(Context context, String path) {
-        return check(hasCodecsForPath(context, path), "no decoder found");
-    }
-
-    public static boolean hasCodecForDomain(boolean encoder, String domain) {
-        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
-            if (encoder != info.isEncoder()) {
-                continue;
-            }
-
-            for (String type : info.getSupportedTypes()) {
-                if (type.toLowerCase().startsWith(domain.toLowerCase() + "/")) {
-                    Log.i(TAG, "found codec " + info.getName() + " for mime " + type);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public static boolean checkCodecForDomain(boolean encoder, String domain) {
-        return check(hasCodecForDomain(encoder, domain),
-                "no " + domain + (encoder ? " encoder" : " decoder") + " found");
-    }
-
-    private static boolean hasCodecForMime(boolean encoder, String mime) {
-        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
-            if (encoder != info.isEncoder()) {
-                continue;
-            }
-
-            for (String type : info.getSupportedTypes()) {
-                if (type.equalsIgnoreCase(mime)) {
-                    Log.i(TAG, "found codec " + info.getName() + " for mime " + mime);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private static boolean hasCodecForMimes(boolean encoder, String[] mimes) {
-        for (String mime : mimes) {
-            if (!hasCodecForMime(encoder, mime)) {
-                Log.i(TAG, "no " + (encoder ? "encoder" : "decoder") + " for mime " + mime);
-                return false;
-            }
-        }
-        return true;
-    }
-
-
-    public static boolean hasEncoder(String... mimes) {
-        return hasCodecForMimes(true /* encoder */, mimes);
-    }
-
-    public static boolean hasDecoder(String... mimes) {
-        return hasCodecForMimes(false /* encoder */, mimes);
-    }
-
-    public static boolean checkDecoder(String... mimes) {
-        return check(hasCodecForMimes(false /* encoder */, mimes), "no decoder found");
-    }
-
-    public static boolean checkEncoder(String... mimes) {
-        return check(hasCodecForMimes(true /* encoder */, mimes), "no encoder found");
-    }
-
-    public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
-        MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
-        format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
-        return canDecode(format);
-    }
-
-    public static boolean canDecodeVideo(
-            String mime, int width, int height, float rate,
-            Integer profile, Integer level, Integer bitrate) {
-        MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
-        format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
-        if (profile != null) {
-            format.setInteger(MediaFormat.KEY_PROFILE, profile);
-            if (level != null) {
-                format.setInteger(MediaFormat.KEY_LEVEL, level);
-            }
-        }
-        if (bitrate != null) {
-            format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-        }
-        return canDecode(format);
-    }
-
-    public static boolean checkEncoderForFormat(MediaFormat format) {
-        return check(canEncode(format), "no encoder for " + format);
-    }
-
-    public static boolean checkDecoderForFormat(MediaFormat format) {
-        return check(canDecode(format), "no decoder for " + format);
-    }
-
-    /*
-     *  ----------------------- HELPER METHODS FOR MEDIA HANDLING -----------------------
-     */
-
-    public static VideoCapabilities getVideoCapabilities(String codecName, String mime) {
-        for (MediaCodecInfo info : sMCL.getCodecInfos()) {
-            if (!info.getName().equalsIgnoreCase(codecName)) {
-                continue;
-            }
-            CodecCapabilities caps;
-            try {
-                caps = info.getCapabilitiesForType(mime);
-            } catch (IllegalArgumentException e) {
-                // mime is not supported
-                Log.w(TAG, "not supported mime: " + mime);
-                return null;
-            }
-            VideoCapabilities vidCaps = caps.getVideoCapabilities();
-            if (vidCaps == null) {
-                Log.w(TAG, "not a video codec: " + codecName);
-            }
-            return vidCaps;
-        }
-        Log.w(TAG, "codec not found: " + codecName);
-        return null;
-    }
-
-    public static MediaFormat getTrackFormatForResource(
-            Context context, int resourceId, String mimeTypePrefix)
-            throws IOException {
-        MediaFormat format = null;
-        MediaExtractor extractor = new MediaExtractor();
-        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
-        try {
-            extractor.setDataSource(
-                    afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-        } finally {
-            afd.close();
-        }
-        int trackIndex;
-        for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
-            MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
-            if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
-                format = trackMediaFormat;
-                break;
-            }
-        }
-        extractor.release();
-        afd.close();
-        if (format == null) {
-            throw new RuntimeException("couldn't get a track for " + mimeTypePrefix);
-        }
-
-        return format;
-    }
-
-    public static MediaExtractor createMediaExtractorForMimeType(
-            Context context, int resourceId, String mimeTypePrefix)
-            throws IOException {
-        MediaExtractor extractor = new MediaExtractor();
-        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resourceId);
-        try {
-            extractor.setDataSource(
-                    afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-        } finally {
-            afd.close();
-        }
-        int trackIndex;
-        for (trackIndex = 0; trackIndex < extractor.getTrackCount(); trackIndex++) {
-            MediaFormat trackMediaFormat = extractor.getTrackFormat(trackIndex);
-            if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith(mimeTypePrefix)) {
-                extractor.selectTrack(trackIndex);
-                break;
-            }
-        }
-        if (trackIndex == extractor.getTrackCount()) {
-            extractor.release();
-            throw new IllegalStateException("couldn't get a track for " + mimeTypePrefix);
-        }
-
-        return extractor;
-    }
-
-    /*
-     *  ---------------------- HELPER METHODS FOR CODEC CONFIGURATION
-     */
-
-    /** Format must contain mime, width and height.
-     *  Throws Exception if encoder does not support this width and height */
-    public static void setMaxEncoderFrameAndBitrates(
-            MediaCodec encoder, MediaFormat format, int maxFps) {
-        String mime = format.getString(MediaFormat.KEY_MIME);
-
-        VideoCapabilities vidCaps =
-            encoder.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities();
-        setMaxEncoderFrameAndBitrates(vidCaps, format, maxFps);
-    }
-
-    public static void setMaxEncoderFrameAndBitrates(
-            VideoCapabilities vidCaps, MediaFormat format, int maxFps) {
-        int width = format.getInteger(MediaFormat.KEY_WIDTH);
-        int height = format.getInteger(MediaFormat.KEY_HEIGHT);
-
-        int maxWidth = vidCaps.getSupportedWidths().getUpper();
-        int maxHeight = vidCaps.getSupportedHeightsFor(maxWidth).getUpper();
-        int frameRate = Math.min(
-                maxFps, vidCaps.getSupportedFrameRatesFor(width, height).getUpper().intValue());
-        format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
-
-        int bitrate = vidCaps.getBitrateRange().clamp(
-            (int)(vidCaps.getBitrateRange().getUpper() /
-                  Math.sqrt((double)maxWidth * maxHeight / width / height)));
-        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-    }
-
-    /*
-     *  ------------------ HELPER METHODS FOR STATISTICS AND REPORTING ------------------
-     */
-
-    // TODO: migrate this into com.android.compatibility.common.util.Stat
-    public static class Stats {
-        /** does not support NaN or Inf in |data| */
-        public Stats(double[] data) {
-            mData = data;
-            if (mData != null) {
-                mNum = mData.length;
-            }
-        }
-
-        public int getNum() {
-            return mNum;
-        }
-
-        /** calculate mSumX and mSumXX */
-        private void analyze() {
-            if (mAnalyzed) {
-                return;
-            }
-
-            if (mData != null) {
-                for (double x : mData) {
-                    if (!(x >= mMinX)) { // mMinX may be NaN
-                        mMinX = x;
-                    }
-                    if (!(x <= mMaxX)) { // mMaxX may be NaN
-                        mMaxX = x;
-                    }
-                    mSumX += x;
-                    mSumXX += x * x;
-                }
-            }
-            mAnalyzed = true;
-        }
-
-        /** returns the maximum or NaN if it does not exist */
-        public double getMin() {
-            analyze();
-            return mMinX;
-        }
-
-        /** returns the minimum or NaN if it does not exist */
-        public double getMax() {
-            analyze();
-            return mMaxX;
-        }
-
-        /** returns the average or NaN if it does not exist. */
-        public double getAverage() {
-            analyze();
-            if (mNum == 0) {
-                return Double.NaN;
-            } else {
-                return mSumX / mNum;
-            }
-        }
-
-        /** returns the standard deviation or NaN if it does not exist. */
-        public double getStdev() {
-            analyze();
-            if (mNum == 0) {
-                return Double.NaN;
-            } else {
-                double average = mSumX / mNum;
-                return Math.sqrt(mSumXX / mNum - average * average);
-            }
-        }
-
-        /** returns the statistics for the moving average over n values */
-        public Stats movingAverage(int n) {
-            if (n < 1 || mNum < n) {
-                return new Stats(null);
-            } else if (n == 1) {
-                return this;
-            }
-
-            double[] avgs = new double[mNum - n + 1];
-            double sum = 0;
-            for (int i = 0; i < mNum; ++i) {
-                sum += mData[i];
-                if (i >= n - 1) {
-                    avgs[i - n + 1] = sum / n;
-                    sum -= mData[i - n + 1];
-                }
-            }
-            return new Stats(avgs);
-        }
-
-        /** returns the statistics for the moving average over a window over the
-         *  cumulative sum. Basically, moves a window from: [0, window] to
-         *  [sum - window, sum] over the cumulative sum, over ((sum - window) / average)
-         *  steps, and returns the average value over each window.
-         *  This method is used to average time-diff data over a window of a constant time.
-         */
-        public Stats movingAverageOverSum(double window) {
-            if (window <= 0 || mNum < 1) {
-                return new Stats(null);
-            }
-
-            analyze();
-            double average = mSumX / mNum;
-            if (window >= mSumX) {
-                return new Stats(new double[] { average });
-            }
-            int samples = (int)Math.ceil((mSumX - window) / average);
-            double[] avgs = new double[samples];
-
-            // A somewhat brute force approach to calculating the moving average.
-            // TODO: add support for weights in Stats, so we can do a more refined approach.
-            double sum = 0; // sum of elements in the window
-            int num = 0; // number of elements in the moving window
-            int bi = 0; // index of the first element in the moving window
-            int ei = 0; // index of the last element in the moving window
-            double space = window; // space at the end of the window
-            double foot = 0; // space at the beginning of the window
-
-            // invariants: foot + sum + space == window
-            //             bi + num == ei
-            //
-            //  window:             |-------------------------------|
-            //                      |    <-----sum------>           |
-            //                      <foot>               <---space-->
-            //                           |               |
-            //  intervals:   |-----------|-------|-------|--------------------|--------|
-            //                           ^bi             ^ei
-
-            int ix = 0; // index in the result
-            while (ix < samples) {
-                // add intervals while there is space in the window
-                while (ei < mData.length && mData[ei] <= space) {
-                    space -= mData[ei];
-                    sum += mData[ei];
-                    num++;
-                    ei++;
-                }
-
-                // calculate average over window and deal with odds and ends (e.g. if there are no
-                // intervals in the current window: pick whichever element overlaps the window
-                // most.
-                if (num > 0) {
-                    avgs[ix++] = sum / num;
-                } else if (bi > 0 && foot > space) {
-                    // consider previous
-                    avgs[ix++] = mData[bi - 1];
-                } else if (ei == mData.length) {
-                    break;
-                } else {
-                    avgs[ix++] = mData[ei];
-                }
-
-                // move the window to the next position
-                foot -= average;
-                space += average;
-
-                // remove intervals that are now partially or wholly outside of the window
-                while (bi < ei && foot < 0) {
-                    foot += mData[bi];
-                    sum -= mData[bi];
-                    num--;
-                    bi++;
-                }
-            }
-            return new Stats(Arrays.copyOf(avgs, ix));
-        }
-
-        /** calculate mSortedData */
-        private void sort() {
-            if (mSorted || mNum == 0) {
-                return;
-            }
-            mSortedData = Arrays.copyOf(mData, mNum);
-            Arrays.sort(mSortedData);
-            mSorted = true;
-        }
-
-        /** returns an array of percentiles for the points using nearest rank */
-        public double[] getPercentiles(double... points) {
-            sort();
-            double[] res = new double[points.length];
-            for (int i = 0; i < points.length; ++i) {
-                if (mNum < 1 || points[i] < 0 || points[i] > 100) {
-                    res[i] = Double.NaN;
-                } else {
-                    res[i] = mSortedData[(int)Math.round(points[i] / 100 * (mNum - 1))];
-                }
-            }
-            return res;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o instanceof Stats) {
-                Stats other = (Stats)o;
-                if (other.mNum != mNum) {
-                    return false;
-                } else if (mNum == 0) {
-                    return true;
-                }
-                return Arrays.equals(mData, other.mData);
-            }
-            return false;
-        }
-
-        private double[] mData;
-        private double mSumX = 0;
-        private double mSumXX = 0;
-        private double mMinX = Double.NaN;
-        private double mMaxX = Double.NaN;
-        private int mNum = 0;
-        private boolean mAnalyzed = false;
-        private double[] mSortedData;
-        private boolean mSorted = false;
-    }
-
-    /*
-     *  -------------------------------------- END --------------------------------------
-     */
-}
diff --git a/libs/deviceutil/src/android/cts/util/NullWebViewUtils.java b/libs/deviceutil/src/android/cts/util/NullWebViewUtils.java
deleted file mode 100644
index e1b23f7..0000000
--- a/libs/deviceutil/src/android/cts/util/NullWebViewUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.cts.util;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-/**
- * Utilities to enable the android.webkit.* CTS tests (and others that rely on a functioning
- * android.webkit.WebView implementation) to determine whether a functioning WebView is present
- * on the device or not.
- *
- * Test cases that require android.webkit.* classes should wrap their first usage of WebView in a
- * try catch block, and pass any exception that is thrown to
- * NullWebViewUtils.determineIfWebViewAvailable. The return value of
- * NullWebViewUtils.isWebViewAvailable will then determine if the test should expect to be able to
- * use a WebView.
- */
-public class NullWebViewUtils {
-
-    private static boolean sWebViewUnavailable;
-
-    /**
-     * @param context Current Activity context, used to query the PackageManager.
-     * @param t       An exception thrown by trying to invoke android.webkit.* APIs.
-     */
-    public static void determineIfWebViewAvailable(Context context, Throwable t) {
-        sWebViewUnavailable = !hasWebViewFeature(context) && checkCauseWasUnsupportedOperation(t);
-    }
-
-    /**
-     * After calling determineIfWebViewAvailable, this returns whether a WebView is available on the
-     * device and wheter the test can rely on it.
-     * @return True iff. PackageManager determined that there is no WebView on the device and the
-     *         exception thrown from android.webkit.* was UnsupportedOperationException.
-     */
-    public static boolean isWebViewAvailable() {
-        return !sWebViewUnavailable;
-    }
-
-    private static boolean hasWebViewFeature(Context context) {
-        // Query the system property that determins if there is a functional WebView on the device.
-        PackageManager pm = context.getPackageManager();
-        return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
-    }
-
-    private static boolean checkCauseWasUnsupportedOperation(Throwable t) {
-        if (t == null) return false;
-        while (t.getCause() != null) {
-            t = t.getCause();
-        }
-        return t instanceof UnsupportedOperationException;
-    }
-
-    /**
-     * Some CTS tests (by design) first use android.webkit.* from a background thread. This helper
-     * allows the test to catch the UnsupportedOperationException from that background thread, and
-     * then query the result from the test main thread.
-     */
-    public static class NullWebViewFromThreadExceptionHandler
-            implements Thread.UncaughtExceptionHandler {
-        private Throwable mPendingException;
-
-        @Override
-        public void uncaughtException(Thread t, Throwable e) {
-            mPendingException = e;
-        }
-
-        public boolean isWebViewAvailable(Context context) {
-            return hasWebViewFeature(context) ||
-                    !checkCauseWasUnsupportedOperation(mPendingException);
-        }
-    }
-}
\ No newline at end of file
diff --git a/libs/deviceutil/src/android/cts/util/PollingCheck.java b/libs/deviceutil/src/android/cts/util/PollingCheck.java
deleted file mode 100644
index 3a08c7e..0000000
--- a/libs/deviceutil/src/android/cts/util/PollingCheck.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.
- */
-
-package android.cts.util;
-
-import java.util.concurrent.Callable;
-
-import junit.framework.Assert;
-
-public abstract class PollingCheck {
-    private static final long TIME_SLICE = 50;
-    private long mTimeout = 3000;
-
-    public static interface PollingCheckCondition {
-        boolean canProceed();
-    }
-
-    public PollingCheck() {
-    }
-
-    public PollingCheck(long timeout) {
-        mTimeout = timeout;
-    }
-
-    protected abstract boolean check();
-
-    public void run() {
-        if (check()) {
-            return;
-        }
-
-        long timeout = mTimeout;
-        while (timeout > 0) {
-            try {
-                Thread.sleep(TIME_SLICE);
-            } catch (InterruptedException e) {
-                Assert.fail("unexpected InterruptedException");
-            }
-
-            if (check()) {
-                return;
-            }
-
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail("unexpected timeout");
-    }
-
-    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
-            throws Exception {
-        while (timeout > 0) {
-            if (condition.call()) {
-                return;
-            }
-
-            Thread.sleep(TIME_SLICE);
-            timeout -= TIME_SLICE;
-        }
-
-        Assert.fail(message.toString());
-    }
-
-    public static void waitFor(final PollingCheckCondition condition) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return condition.canProceed();
-            }
-        }.run();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/ReadElf.java b/libs/deviceutil/src/android/cts/util/ReadElf.java
deleted file mode 100644
index 559cbd0..0000000
--- a/libs/deviceutil/src/android/cts/util/ReadElf.java
+++ /dev/null
@@ -1,494 +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.cts.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A poor man's implementation of the readelf command. This program is designed
- * to parse ELF (Executable and Linkable Format) files.
- */
-public class ReadElf implements AutoCloseable {
-    /** The magic values for the ELF identification. */
-    private static final byte[] ELFMAG = {
-            (byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F', };
-
-    private static final int EI_NIDENT = 16;
-
-    private static final int EI_CLASS = 4;
-    private static final int EI_DATA = 5;
-
-    private static final int EM_386 = 3;
-    private static final int EM_MIPS = 8;
-    private static final int EM_ARM = 40;
-    private static final int EM_X86_64 = 62;
-    // http://en.wikipedia.org/wiki/Qualcomm_Hexagon
-    private static final int EM_QDSP6 = 164;
-    private static final int EM_AARCH64 = 183;
-
-    private static final int ELFCLASS32 = 1;
-    private static final int ELFCLASS64 = 2;
-
-    private static final int ELFDATA2LSB = 1;
-    private static final int ELFDATA2MSB = 2;
-
-    private static final int EV_CURRENT = 1;
-
-    private static final long PT_LOAD = 1;
-
-    private static final int SHT_SYMTAB = 2;
-    private static final int SHT_STRTAB = 3;
-    private static final int SHT_DYNAMIC = 6;
-    private static final int SHT_DYNSYM = 11;
-
-    public static class Symbol {
-        public static final int STB_LOCAL = 0;
-        public static final int STB_GLOBAL = 1;
-        public static final int STB_WEAK = 2;
-        public static final int STB_LOPROC = 13;
-        public static final int STB_HIPROC = 15;
-
-        public static final int STT_NOTYPE = 0;
-        public static final int STT_OBJECT = 1;
-        public static final int STT_FUNC = 2;
-        public static final int STT_SECTION = 3;
-        public static final int STT_FILE = 4;
-        public static final int STT_COMMON = 5;
-        public static final int STT_TLS = 6;
-
-        public final String name;
-        public final int bind;
-        public final int type;
-
-        Symbol(String name, int st_info) {
-            this.name = name;
-            this.bind = (st_info >> 4) & 0x0F;
-            this.type = st_info & 0x0F;
-        }
-
-        @Override
-        public String toString() {
-            return "Symbol[" + name + "," + toBind() + "," + toType() + "]";
-        }
-
-        private String toBind() {
-            switch (bind) {
-                case STB_LOCAL:
-                    return "LOCAL";
-                case STB_GLOBAL:
-                    return "GLOBAL";
-                case STB_WEAK:
-                    return "WEAK";
-            }
-            return "STB_??? (" + bind + ")";
-        }
-
-        private String toType() {
-            switch (type) {
-                case STT_NOTYPE:
-                    return "NOTYPE";
-                case STT_OBJECT:
-                    return "OBJECT";
-                case STT_FUNC:
-                    return "FUNC";
-                case STT_SECTION:
-                    return "SECTION";
-                case STT_FILE:
-                    return "FILE";
-                case STT_COMMON:
-                    return "COMMON";
-                case STT_TLS:
-                    return "TLS";
-            }
-            return "STT_??? (" + type + ")";
-        }
-    }
-
-    private final String mPath;
-    private final RandomAccessFile mFile;
-    private final byte[] mBuffer = new byte[512];
-    private int mEndian;
-    private boolean mIsDynamic;
-    private boolean mIsPIE;
-    private int mType;
-    private int mAddrSize;
-
-    /** Symbol Table offset */
-    private long mSymTabOffset;
-
-    /** Symbol Table size */
-    private long mSymTabSize;
-
-    /** Dynamic Symbol Table offset */
-    private long mDynSymOffset;
-
-    /** Dynamic Symbol Table size */
-    private long mDynSymSize;
-
-    /** Section Header String Table offset */
-    private long mShStrTabOffset;
-
-    /** Section Header String Table size */
-    private long mShStrTabSize;
-
-    /** String Table offset */
-    private long mStrTabOffset;
-
-    /** String Table size */
-    private long mStrTabSize;
-
-    /** Dynamic String Table offset */
-    private long mDynStrOffset;
-
-    /** Dynamic String Table size */
-    private long mDynStrSize;
-
-    /** Symbol Table symbol names */
-    private Map<String, Symbol> mSymbols;
-
-    /** Dynamic Symbol Table symbol names */
-    private Map<String, Symbol> mDynamicSymbols;
-
-    public static ReadElf read(File file) throws IOException {
-        return new ReadElf(file);
-    }
-
-    public static void main(String[] args) throws IOException {
-        for (String arg : args) {
-            ReadElf re = new ReadElf(new File(arg));
-            re.getSymbol("x");
-            re.getDynamicSymbol("x");
-            re.close();
-        }
-    }
-
-    public boolean isDynamic() {
-        return mIsDynamic;
-    }
-
-    public int getType() {
-        return mType;
-    }
-
-    public boolean isPIE() {
-        return mIsPIE;
-    }
-
-    private ReadElf(File file) throws IOException {
-        mPath = file.getPath();
-        mFile = new RandomAccessFile(file, "r");
-
-        if (mFile.length() < EI_NIDENT) {
-            throw new IllegalArgumentException("Too small to be an ELF file: " + file);
-        }
-
-        readHeader();
-    }
-
-    @Override
-    public void close() {
-        try {
-            mFile.close();
-        } catch (IOException ignored) {
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            close();
-        } finally {
-            super.finalize();
-        }
-    }
-
-    private void readHeader() throws IOException {
-        mFile.seek(0);
-        mFile.readFully(mBuffer, 0, EI_NIDENT);
-
-        if (mBuffer[0] != ELFMAG[0] || mBuffer[1] != ELFMAG[1] ||
-                mBuffer[2] != ELFMAG[2] || mBuffer[3] != ELFMAG[3]) {
-            throw new IllegalArgumentException("Invalid ELF file: " + mPath);
-        }
-
-        int elfClass = mBuffer[EI_CLASS];
-        if (elfClass == ELFCLASS32) {
-            mAddrSize = 4;
-        } else if (elfClass == ELFCLASS64) {
-            mAddrSize = 8;
-        } else {
-            throw new IOException("Invalid ELF EI_CLASS: " + elfClass + ": " + mPath);
-        }
-
-        mEndian = mBuffer[EI_DATA];
-        if (mEndian == ELFDATA2LSB) {
-        } else if (mEndian == ELFDATA2MSB) {
-            throw new IOException("Unsupported ELFDATA2MSB file: " + mPath);
-        } else {
-            throw new IOException("Invalid ELF EI_DATA: " + mEndian + ": " + mPath);
-        }
-
-        mType = readHalf();
-
-        int e_machine = readHalf();
-        if (e_machine != EM_386 && e_machine != EM_X86_64 &&
-                e_machine != EM_AARCH64 && e_machine != EM_ARM &&
-                e_machine != EM_MIPS &&
-                e_machine != EM_QDSP6) {
-            throw new IOException("Invalid ELF e_machine: " + e_machine + ": " + mPath);
-        }
-
-        // AbiTest relies on us rejecting any unsupported combinations.
-        if ((e_machine == EM_386 && elfClass != ELFCLASS32) ||
-                (e_machine == EM_X86_64 && elfClass != ELFCLASS64) ||
-                (e_machine == EM_AARCH64 && elfClass != ELFCLASS64) ||
-                (e_machine == EM_ARM && elfClass != ELFCLASS32) ||
-                (e_machine == EM_QDSP6 && elfClass != ELFCLASS32)) {
-            throw new IOException("Invalid e_machine/EI_CLASS ELF combination: " +
-                    e_machine + "/" + elfClass + ": " + mPath);
-        }
-
-        long e_version = readWord();
-        if (e_version != EV_CURRENT) {
-            throw new IOException("Invalid e_version: " + e_version + ": " + mPath);
-        }
-
-        long e_entry = readAddr();
-
-        long ph_off = readOff();
-        long sh_off = readOff();
-
-        long e_flags = readWord();
-        int e_ehsize = readHalf();
-        int e_phentsize = readHalf();
-        int e_phnum = readHalf();
-        int e_shentsize = readHalf();
-        int e_shnum = readHalf();
-        int e_shstrndx = readHalf();
-
-        readSectionHeaders(sh_off, e_shnum, e_shentsize, e_shstrndx);
-        readProgramHeaders(ph_off, e_phnum, e_phentsize);
-    }
-
-    private void readSectionHeaders(long sh_off, int e_shnum, int e_shentsize, int e_shstrndx)
-            throws IOException {
-        // Read the Section Header String Table offset first.
-        {
-            mFile.seek(sh_off + e_shstrndx * e_shentsize);
-
-            long sh_name = readWord();
-            long sh_type = readWord();
-            long sh_flags = readX(mAddrSize);
-            long sh_addr = readAddr();
-            long sh_offset = readOff();
-            long sh_size = readX(mAddrSize);
-            // ...
-
-            if (sh_type == SHT_STRTAB) {
-                mShStrTabOffset = sh_offset;
-                mShStrTabSize = sh_size;
-            }
-        }
-
-        for (int i = 0; i < e_shnum; ++i) {
-            // Don't bother to re-read the Section Header StrTab.
-            if (i == e_shstrndx) {
-                continue;
-            }
-
-            mFile.seek(sh_off + i * e_shentsize);
-
-            long sh_name = readWord();
-            long sh_type = readWord();
-            long sh_flags = readX(mAddrSize);
-            long sh_addr = readAddr();
-            long sh_offset = readOff();
-            long sh_size = readX(mAddrSize);
-
-            if (sh_type == SHT_SYMTAB || sh_type == SHT_DYNSYM) {
-                final String symTabName = readShStrTabEntry(sh_name);
-                if (".symtab".equals(symTabName)) {
-                    mSymTabOffset = sh_offset;
-                    mSymTabSize = sh_size;
-                } else if (".dynsym".equals(symTabName)) {
-                    mDynSymOffset = sh_offset;
-                    mDynSymSize = sh_size;
-                }
-            } else if (sh_type == SHT_STRTAB) {
-                final String strTabName = readShStrTabEntry(sh_name);
-                if (".strtab".equals(strTabName)) {
-                    mStrTabOffset = sh_offset;
-                    mStrTabSize = sh_size;
-                } else if (".dynstr".equals(strTabName)) {
-                    mDynStrOffset = sh_offset;
-                    mDynStrSize = sh_size;
-                }
-            } else if (sh_type == SHT_DYNAMIC) {
-                mIsDynamic = true;
-            }
-        }
-    }
-
-    private void readProgramHeaders(long ph_off, int e_phnum, int e_phentsize) throws IOException {
-        for (int i = 0; i < e_phnum; ++i) {
-            mFile.seek(ph_off + i * e_phentsize);
-
-            long p_type = readWord();
-            if (p_type == PT_LOAD) {
-                if (mAddrSize == 8) {
-                    // Only in Elf64_phdr; in Elf32_phdr p_flags is at the end.
-                    long p_flags = readWord();
-                }
-                long p_offset = readOff();
-                long p_vaddr = readAddr();
-                // ...
-
-                if (p_vaddr == 0) {
-                    mIsPIE = true;
-                }
-            }
-        }
-    }
-
-    private HashMap<String, Symbol> readSymbolTable(long symStrOffset, long symStrSize,
-            long tableOffset, long tableSize) throws IOException {
-        HashMap<String, Symbol> result = new HashMap<String, Symbol>();
-        mFile.seek(tableOffset);
-        while (mFile.getFilePointer() < tableOffset + tableSize) {
-            long st_name = readWord();
-            int st_info;
-            if (mAddrSize == 8) {
-                st_info = readByte();
-                int st_other = readByte();
-                int st_shndx = readHalf();
-                long st_value = readAddr();
-                long st_size = readX(mAddrSize);
-            } else {
-                long st_value = readAddr();
-                long st_size = readWord();
-                st_info = readByte();
-                int st_other = readByte();
-                int st_shndx = readHalf();
-            }
-            if (st_name == 0) {
-                continue;
-            }
-
-            final String symName = readStrTabEntry(symStrOffset, symStrSize, st_name);
-            if (symName != null) {
-                Symbol s = new Symbol(symName, st_info);
-                result.put(symName, s);
-            }
-        }
-        return result;
-    }
-
-    private String readShStrTabEntry(long strOffset) throws IOException {
-        if (mShStrTabOffset == 0 || strOffset < 0 || strOffset >= mShStrTabSize) {
-            return null;
-        }
-        return readString(mShStrTabOffset + strOffset);
-    }
-
-    private String readStrTabEntry(long tableOffset, long tableSize, long strOffset)
-            throws IOException {
-        if (tableOffset == 0 || strOffset < 0 || strOffset >= tableSize) {
-            return null;
-        }
-        return readString(tableOffset + strOffset);
-    }
-
-    private int readHalf() throws IOException {
-        return (int) readX(2);
-    }
-
-    private long readWord() throws IOException {
-        return readX(4);
-    }
-
-    private long readOff() throws IOException {
-        return readX(mAddrSize);
-    }
-
-    private long readAddr() throws IOException {
-        return readX(mAddrSize);
-    }
-
-    private long readX(int byteCount) throws IOException {
-        mFile.readFully(mBuffer, 0, byteCount);
-
-        int answer = 0;
-        if (mEndian == ELFDATA2LSB) {
-            for (int i = byteCount - 1; i >= 0; i--) {
-                answer = (answer << 8) | (mBuffer[i] & 0xff);
-            }
-        } else {
-            final int N = byteCount - 1;
-            for (int i = 0; i <= N; ++i) {
-                answer = (answer << 8) | (mBuffer[i] & 0xff);
-            }
-        }
-
-        return answer;
-    }
-
-    private String readString(long offset) throws IOException {
-        long originalOffset = mFile.getFilePointer();
-        mFile.seek(offset);
-        mFile.readFully(mBuffer, 0, (int) Math.min(mBuffer.length, mFile.length() - offset));
-        mFile.seek(originalOffset);
-
-        for (int i = 0; i < mBuffer.length; ++i) {
-            if (mBuffer[i] == 0) {
-                return new String(mBuffer, 0, i);
-            }
-        }
-
-        return null;
-    }
-
-    private int readByte() throws IOException {
-        return mFile.read() & 0xff;
-    }
-
-    public Symbol getSymbol(String name) {
-        if (mSymbols == null) {
-            try {
-                mSymbols = readSymbolTable(mStrTabOffset, mStrTabSize, mSymTabOffset, mSymTabSize);
-            } catch (IOException e) {
-                return null;
-            }
-        }
-        return mSymbols.get(name);
-    }
-
-    public Symbol getDynamicSymbol(String name) {
-        if (mDynamicSymbols == null) {
-            try {
-                mDynamicSymbols = readSymbolTable(
-                        mDynStrOffset, mDynStrSize, mDynSymOffset, mDynSymSize);
-            } catch (IOException e) {
-                return null;
-            }
-        }
-        return mDynamicSymbols.get(name);
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/SystemUtil.java b/libs/deviceutil/src/android/cts/util/SystemUtil.java
deleted file mode 100644
index 6e7fd38..0000000
--- a/libs/deviceutil/src/android/cts/util/SystemUtil.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.
- */
-
-package android.cts.util;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.MemoryInfo;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.os.StatFs;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-
-public class SystemUtil {
-    public static long getFreeDiskSize(Context context) {
-        StatFs statFs = new StatFs(context.getFilesDir().getAbsolutePath());
-        return (long)statFs.getAvailableBlocks() * statFs.getBlockSize();
-    }
-
-    public static long getFreeMemory(Context context) {
-        MemoryInfo info = new MemoryInfo();
-        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        activityManager.getMemoryInfo(info);
-        return info.availMem;
-    }
-
-    public static long getTotalMemory(Context context) {
-        MemoryInfo info = new MemoryInfo();
-        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        activityManager.getMemoryInfo(info);
-        return info.totalMem; // TODO totalMem N/A in ICS.
-    }
-
-    /**
-     * Executes a shell command using shell user identity, and return the standard output in string
-     * <p>Note: calling this function requires API level 21 or above
-     * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
-     * instrumentation framework
-     * @param cmd the command to run
-     * @return the standard output of the command
-     * @throws Exception
-     */
-    public static String runShellCommand(Instrumentation instrumentation, String cmd)
-            throws IOException {
-        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
-        byte[] buf = new byte[512];
-        int bytesRead;
-        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-        StringBuffer stdout = new StringBuffer();
-        while ((bytesRead = fis.read(buf)) != -1) {
-            stdout.append(new String(buf, 0, bytesRead));
-        }
-        fis.close();
-        return stdout.toString();
-    }
-
-}
diff --git a/libs/deviceutil/src/android/cts/util/TestThread.java b/libs/deviceutil/src/android/cts/util/TestThread.java
deleted file mode 100644
index 14df61c..0000000
--- a/libs/deviceutil/src/android/cts/util/TestThread.java
+++ /dev/null
@@ -1,93 +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.cts.util;
-
-/**
- * Thread class for executing a Runnable containing assertions in a separate thread.
- * Uncaught exceptions in the Runnable are rethrown in the context of the the thread
- * calling the <code>runTest()</code> method.
- */
-public final class TestThread extends Thread {
-    private Throwable mThrowable;
-    private Runnable mTarget;
-
-    public TestThread(Runnable target) {
-        mTarget = target;
-    }
-
-    @Override
-    public final void run() {
-        try {
-            mTarget.run();
-        } catch (Throwable t) {
-            mThrowable = t;
-        }
-    }
-
-    /**
-     * Run the target Runnable object and wait until the test finish or throw
-     * out Exception if test fail.
-     *
-     * @param runTime
-     * @throws Throwable
-     */
-    public void runTest(long runTime) throws Throwable {
-        start();
-        joinAndCheck(runTime);
-    }
-
-    /**
-     * Get the Throwable object which is thrown when test running
-     * @return  The Throwable object
-     */
-    public Throwable getThrowable() {
-        return mThrowable;
-    }
-
-    /**
-     * Set the Throwable object which is thrown when test running
-     * @param t The Throwable object
-     */
-    public void setThrowable(Throwable t) {
-        mThrowable = t;
-    }
-
-    /**
-     * Wait for the test thread to complete and throw the stored exception if there is one.
-     *
-     * @param runTime The time to wait for the test thread to complete.
-     * @throws Throwable
-     */
-    public void joinAndCheck(long runTime) throws Throwable {
-        this.join(runTime);
-        if (this.isAlive()) {
-            this.interrupt();
-            this.join(runTime);
-            throw new Exception("Thread did not finish within allotted time.");
-        }
-        checkException();
-    }
-
-    /**
-     * Check whether there is an exception when running Runnable object.
-     * @throws Throwable
-     */
-    public void checkException() throws Throwable {
-        if (mThrowable != null) {
-            throw mThrowable;
-        }
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/WatchDog.java b/libs/deviceutil/src/android/cts/util/WatchDog.java
deleted file mode 100644
index ab2a9d9..0000000
--- a/libs/deviceutil/src/android/cts/util/WatchDog.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.
- */
-package android.cts.util;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import android.util.Log;
-
-import junit.framework.Assert;
-
-/**
- * class for checking if rendering function is alive or not.
- * panic if watch-dog is not reset over certain amount of time
- */
-public class WatchDog implements Runnable {
-    private static final String TAG = "WatchDog";
-    private Thread mThread;
-    private Semaphore mSemaphore;
-    private volatile boolean mStopRequested;
-    private final long mTimeoutInMilliSecs;
-    private TimeoutCallback mCallback = null;
-
-    public WatchDog(long timeoutInMilliSecs) {
-        mTimeoutInMilliSecs = timeoutInMilliSecs;
-    }
-
-    public WatchDog(long timeoutInMilliSecs, TimeoutCallback callback) {
-        this(timeoutInMilliSecs);
-        mCallback = callback;
-    }
-
-    /** start watch-dog */
-    public void start() {
-        Log.i(TAG, "start");
-        mStopRequested = false;
-        mSemaphore = new Semaphore(0);
-        mThread = new Thread(this);
-        mThread.start();
-    }
-
-    /** stop watch-dog */
-    public void stop() {
-        Log.i(TAG, "stop");
-        if (mThread == null) {
-            return; // already finished
-        }
-        mStopRequested = true;
-        mSemaphore.release();
-        try {
-            mThread.join();
-        } catch (InterruptedException e) {
-            // ignore
-        }
-        mThread = null;
-        mSemaphore = null;
-    }
-
-    /** resets watch-dog, thus prevent it from panic */
-    public void reset() {
-        if (!mStopRequested) { // stop requested, but rendering still on-going
-            mSemaphore.release();
-        }
-    }
-
-    @Override
-    public void run() {
-        while (!mStopRequested) {
-            try {
-                boolean success = mSemaphore.tryAcquire(mTimeoutInMilliSecs, TimeUnit.MILLISECONDS);
-                if (mCallback == null) {
-                    Assert.assertTrue("Watchdog timed-out", success);
-                } else if (!success) {
-                    mCallback.onTimeout();
-                }
-            } catch (InterruptedException e) {
-                // this thread will not be interrupted,
-                // but if it happens, just check the exit condition.
-            }
-        }
-    }
-
-    /**
-     * Called by the Watchdog when it has timed out.
-     */
-    public interface TimeoutCallback {
-
-        public void onTimeout();
-    }
-}
diff --git a/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java b/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java
deleted file mode 100644
index 813672e..0000000
--- a/libs/deviceutil/src/android/cts/util/WidgetTestUtils.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.
- */
-
-package android.cts.util;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-import java.io.IOException;
-
-import junit.framework.Assert;
-
-/**
- * The useful methods for widget test.
- */
-public class WidgetTestUtils {
-    /**
-     * Assert that two bitmaps are equal.
-     *
-     * @param Bitmap b1 the first bitmap which needs to compare.
-     * @param Bitmap b2 the second bitmap which needs to compare.
-     */
-    public static void assertEquals(Bitmap b1, Bitmap b2) {
-        if (b1 == b2) {
-            return;
-        }
-
-        if (b1 == null || b2 == null) {
-            Assert.fail("the bitmaps are not equal");
-        }
-
-        // b1 and b2 are all not null.
-        if (b1.getWidth() != b2.getWidth() || b1.getHeight() != b2.getHeight()
-            || b1.getConfig() != b2.getConfig()) {
-            Assert.fail("the bitmaps are not equal");
-        }
-
-        int w = b1.getWidth();
-        int h = b1.getHeight();
-        int s = w * h;
-        int[] pixels1 = new int[s];
-        int[] pixels2 = new int[s];
-
-        b1.getPixels(pixels1, 0, w, 0, 0, w, h);
-        b2.getPixels(pixels2, 0, w, 0, 0, w, h);
-
-        for (int i = 0; i < s; i++) {
-            if (pixels1[i] != pixels2[i]) {
-                Assert.fail("the bitmaps are not equal");
-            }
-        }
-    }
-
-    /**
-     * Find beginning of the special element.
-     * @param parser XmlPullParser will be parsed.
-     * @param firstElementName the target element name.
-     *
-     * @throws XmlPullParserException if XML Pull Parser related faults occur.
-     * @throws IOException if I/O-related error occur when parsing.
-     */
-    public static final void beginDocument(XmlPullParser parser, String firstElementName)
-            throws XmlPullParserException, IOException {
-        Assert.assertNotNull(parser);
-        Assert.assertNotNull(firstElementName);
-
-        int type;
-        while ((type = parser.next()) != XmlPullParser.START_TAG
-                && type != XmlPullParser.END_DOCUMENT) {
-            ;
-        }
-
-        if (!parser.getName().equals(firstElementName)) {
-            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
-                    + ", expected " + firstElementName);
-        }
-    }
-
-    /**
-     * Compare the expected pixels with actual, scaling for the target context density
-     *
-     * @throws AssertionFailedError
-     */
-    public static void assertScaledPixels(int expected, int actual, Context context) {
-        Assert.assertEquals(expected * context.getResources().getDisplayMetrics().density,
-                actual, 3);
-    }
-
-    /** Converts dips into pixels using the {@link Context}'s density. */
-    public static int convertDipToPixels(Context context, int dip) {
-      float density = context.getResources().getDisplayMetrics().density;
-      return Math.round(density * dip);
-    }
-
-    /**
-     * Retrieve a bitmap that can be used for comparison on any density
-     * @param resources
-     * @return the {@link Bitmap} or <code>null</code>
-     */
-    public static Bitmap getUnscaledBitmap(Resources resources, int resId) {
-        BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inScaled = false;
-        return BitmapFactory.decodeResource(resources, resId, options);
-    }
-
-    /**
-     * Retrieve a dithered bitmap that can be used for comparison on any density
-     * @param resources
-     * @param config the preferred config for the returning bitmap
-     * @return the {@link Bitmap} or <code>null</code>
-     */
-    public static Bitmap getUnscaledAndDitheredBitmap(Resources resources,
-            int resId, Bitmap.Config config) {
-        BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inDither = true;
-        options.inScaled = false;
-        options.inPreferredConfig = config;
-        return BitmapFactory.decodeResource(resources, resId, options);
-    }
-}
diff --git a/libs/deviceutillegacy/Android.mk b/libs/deviceutillegacy/Android.mk
index 852ce38..3784394 100644
--- a/libs/deviceutillegacy/Android.mk
+++ b/libs/deviceutillegacy/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
 
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src)
diff --git a/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java b/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
index ee44f8a..b528417 100644
--- a/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
+++ b/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
@@ -16,8 +16,9 @@
 
 package android.webkit.cts;
 
-import android.cts.util.PollingCheck;
-import android.cts.util.TestThread;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.TestThread;
+
 import android.graphics.Bitmap;
 import android.graphics.Picture;
 import android.graphics.Rect;
@@ -27,6 +28,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.print.PrintDocumentAdapter;
+import android.support.test.rule.ActivityTestRule;
 import android.test.InstrumentationTestCase;
 import android.util.DisplayMetrics;
 import android.view.View;
@@ -88,6 +90,11 @@
     private InstrumentationTestCase mTest;
 
     /**
+     * The test rule that this class is being used in. Used for runTestOnUiThread.
+     */
+    private ActivityTestRule mActivityTestRule;
+
+    /**
      * The WebView that calls will be made on.
      */
     private WebView mWebView;
@@ -101,8 +108,10 @@
      *
      * @param test The test in which this is being run.
      * @param webView The webView that the methods should call.
-     * @see loadUrlAndWaitForCompletion
+     * @see #loadDataAndWaitForCompletion(String, String, String)
+     * @deprecated Use {@link WebViewOnUiThread#WebViewOnUiThread(ActivityTestRule, WebView)}
      */
+    @Deprecated
     public WebViewOnUiThread(InstrumentationTestCase test, WebView webView) {
         mTest = test;
         mWebView = webView;
@@ -119,6 +128,29 @@
     }
 
     /**
+     * Initializes the webView with a WebViewClient, WebChromeClient,
+     * and PictureListener to prepare for loadUrlAndWaitForCompletion.
+     *
+     * A new WebViewOnUiThread should be called during setUp so as to
+     * reinitialize between calls.
+     *
+     * @param activityTestRule The test rule in which this is being run.
+     * @param webView The webView that the methods should call.
+     * @see #loadDataAndWaitForCompletion(String, String, String)
+     */
+    public WebViewOnUiThread(ActivityTestRule activityTestRule, WebView webView) {
+        mActivityTestRule = activityTestRule;
+        mWebView = webView;
+        final WebViewClient webViewClient = new WaitForLoadedClient(this);
+        final WebChromeClient webChromeClient = new WaitForProgressClient(this);
+        runOnUiThread(() -> {
+            mWebView.setWebViewClient(webViewClient);
+            mWebView.setWebChromeClient(webChromeClient);
+            mWebView.setPictureListener(new WaitForNewPicture());
+        });
+    }
+
+    /**
      * Called after a test is complete and the WebView should be disengaged from
      * the tests.
      */
@@ -847,7 +879,8 @@
      * a test failure. If this is already the UI thread then it runs
      * the code immediately.
      *
-     * @see runTestOnUiThread
+     * @see InstrumentationTestCase#runTestOnUiThread(Runnable)
+     * @see ActivityTestRule#runOnUiThread(Runnable)
      * @param r The code to run in the UI thread
      */
     public void runOnUiThread(Runnable r) {
@@ -855,7 +888,11 @@
             if (isUiThread()) {
                 r.run();
             } else {
-                mTest.runTestOnUiThread(r);
+                if (mActivityTestRule != null) {
+                    mActivityTestRule.runOnUiThread(r);
+                } else {
+                    mTest.runTestOnUiThread(r);
+                }
             }
         } catch (Throwable t) {
             Assert.fail("Unexpected error while running on UI thread: "
diff --git a/libs/migration/Android.mk b/libs/migration/Android.mk
deleted file mode 100644
index 11173d6..0000000
--- a/libs/migration/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := cts-migration-lib
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/libs/migration/src/com/android/cts/migration/MigrationHelper.java b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
deleted file mode 100644
index 0595486..0000000
--- a/libs/migration/src/com/android/cts/migration/MigrationHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.android.cts.migration;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * A temporary helper to enable tests to work with both cts v1 and v2.
- */
-public class MigrationHelper {
-
-    private static final String COMPATIBILITY_BUILD_HELPER =
-            "com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper";
-    private static final String CTS_BUILD_HELPER =
-            "com.android.cts.tradefed.build.CtsBuildHelper";
-
-    public static File getTestFile(IBuildInfo mBuild, String filename)
-            throws FileNotFoundException {
-        try {
-            Class<?> cls = Class.forName(COMPATIBILITY_BUILD_HELPER);
-            Constructor<?> cons = cls.getConstructor(IBuildInfo.class);
-            Object instance = cons.newInstance(mBuild);
-            Method method = cls.getMethod("getTestsDir");
-            File dir = (File) method.invoke(instance);
-            File file = new File(dir, filename);
-            CLog.i("Looking for test file %s in dir %s", filename, dir.getAbsolutePath());
-            if (file.exists()) {
-                CLog.i("File %s found", filename);
-                return file;
-            }
-        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
-                IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            // Ignore and fall back to CtsBuildHelper
-        }
-        try {
-            Class<?> cls = Class.forName(CTS_BUILD_HELPER);
-            Method builder = cls.getMethod("createBuildHelper", IBuildInfo.class);
-            Object helper = builder.invoke(null, mBuild);
-            Method method = cls.getMethod("getTestApp", String.class);
-            File file = (File) method.invoke(helper, filename);
-            CLog.i("Looking for test file %s as %s", filename, file.getAbsolutePath());
-            if (file.exists()) {
-                CLog.i("File %s found", filename);
-                return file;
-            }
-        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
-                IllegalArgumentException | InvocationTargetException e) {
-            // Ignore
-        }
-        throw new FileNotFoundException("Couldn't load file " + filename);
-    }
-
-}
diff --git a/test_defs.sh b/test_defs.sh
index 5d5090d..cc92685 100644
--- a/test_defs.sh
+++ b/test_defs.sh
@@ -22,7 +22,7 @@
 COMMON_JARS="
     ddmlib-prebuilt\
     hosttestlib\
-    tradefed-prebuilt"
+    tradefed"
 
 checkFile() {
     if [ ! -f "$1" ]; then
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
index 153a4fd..d907344 100755
--- a/tests/JobScheduler/Android.mk
+++ b/tests/JobScheduler/Android.mk
@@ -22,7 +22,7 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/acceleration/AndroidTest.xml b/tests/acceleration/AndroidTest.xml
index 1786c8e..9bf8136 100644
--- a/tests/acceleration/AndroidTest.xml
+++ b/tests/acceleration/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.acceleration.cts" />
+        <option name="runtime-hint" value="13m" />
     </test>
 </configuration>
diff --git a/tests/accessibility/Android.mk b/tests/accessibility/Android.mk
index 1bcc20d..7af9d90 100644
--- a/tests/accessibility/Android.mk
+++ b/tests/accessibility/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_PACKAGE_NAME := CtsAccessibilityTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/accessibility/AndroidTest.xml b/tests/accessibility/AndroidTest.xml
index b6c8ab5..bc18a7f 100644
--- a/tests/accessibility/AndroidTest.xml
+++ b/tests/accessibility/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.view.accessibility.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index db4e54b..aa9db4f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -19,6 +19,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityRecord;
@@ -158,7 +159,25 @@
         assertEqualsAccessiblityEvent(marshaledEvent, unmarshaledEvent);
     }
 
+    /**
+     * While CharSequence is immutable, some classes implementing it are mutable. Make sure they
+     * can't change the object by changing the objects backing CharSequence
+     */
+    @SmallTest
+    public void testChangeTextAfterSetting_shouldNotAffectEvent() {
+        final String originalText = "Cassowary";
+        final String newText = "Hornbill";
+        AccessibilityEvent event = AccessibilityEvent.obtain();
+        StringBuffer updatingString = new StringBuffer(originalText);
+        event.setBeforeText(updatingString);
+        event.setContentDescription(updatingString);
 
+        updatingString.delete(0, updatingString.length());
+        updatingString.append(newText);
+
+        assertTrue(TextUtils.equals(originalText, event.getBeforeText()));
+        assertTrue(TextUtils.equals(originalText, event.getContentDescription()));
+    }
 
     /**
      * Fully populates the {@link AccessibilityEvent} to marshal.
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1256546..caba01c 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -19,13 +19,14 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Service;
 import android.content.pm.ServiceInfo;
-import android.cts.util.PollingCheck;
 import android.test.InstrumentationTestCase;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.List;
 
 /**
@@ -173,7 +174,7 @@
     }
 
     public void testInterrupt() throws Exception {
-        // The APIs are heavily tested in the android.accessibiliyservice package.
+        // The APIs are heavily tested in the android.accessibilityservice package.
         // This just makes sure the call does not throw an exception.
         waitForAccessibilityEnabled();
         mAccessibilityManager.interrupt();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 9c9b0db..0072e7f 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -163,6 +164,28 @@
     }
 
     /**
+     * While CharSequence is immutable, some classes implementing it are mutable. Make sure they
+     * can't change the object by changing the objects backing CharSequence
+     */
+    @SmallTest
+    public void testChangeTextAfterSetting_shouldNotAffectInfo() {
+        final String originalText = "Cassowaries";
+        final String newText = "Hornbill";
+        AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+        StringBuffer updatingString = new StringBuffer(originalText);
+        info.setText(updatingString);
+        info.setError(updatingString);
+        info.setContentDescription(updatingString);
+
+        updatingString.delete(0, updatingString.length());
+        updatingString.append(newText);
+
+        assertTrue(TextUtils.equals(originalText, info.getText()));
+        assertTrue(TextUtils.equals(originalText, info.getError()));
+        assertTrue(TextUtils.equals(originalText, info.getContentDescription()));
+    }
+
+    /**
      * Fully populates the {@link AccessibilityNodeInfo} to marshal.
      *
      * @param info The node info to populate.
diff --git a/tests/accessibilityservice/Android.mk b/tests/accessibilityservice/Android.mk
index aee708c..62f2e57 100644
--- a/tests/accessibilityservice/Android.mk
+++ b/tests/accessibilityservice/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner mockito-target-minus-junit4
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
index c121071..282e624 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
@@ -21,7 +21,10 @@
 import android.app.UiAutomation;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
 
+import java.util.List;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -53,6 +56,7 @@
 
         AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
         info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+        info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
         info.flags &= ~AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
         getInstrumentation().getUiAutomation().setServiceInfo(info);
 
@@ -96,13 +100,18 @@
                 new UiAutomation.AccessibilityEventFilter() {
             @Override
             public boolean accept(AccessibilityEvent event) {
-                final int eventType = event.getEventType();
-                // Do not check the package name since an event of this type may
-                // come concurrently from the app and from the IME (since input
-                // focus goes to the first focusable) but we dispatch one event
-                // of each type within a timeout. Hence, sometimes the window
-                // change event from the IME may override the one from the app.
-                return (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                List<AccessibilityWindowInfo> windows = getInstrumentation().getUiAutomation()
+                        .getWindows();
+                // Wait for a window state changed event with our window showing
+                for (int i = 0; i < windows.size(); i++) {
+                    AccessibilityNodeInfo root = windows.get(i).getRoot();
+                    if ((root != null) &&
+                            root.getPackageName().equals(getActivity().getPackageName())) {
+                        return (event.getEventType()
+                                == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    }
+                }
+                return false;
             }
         },
         TIMEOUT_ASYNC_PROCESSING);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index d8a1be1..499b366 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -29,6 +30,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ListView;
@@ -314,7 +316,7 @@
     @SuppressWarnings("deprecation")
     public void testTypeNotificationStateChangedAccessibilityEvent() throws Throwable {
         // No notification UI on televisions.
-        if((getActivity().getResources().getConfiguration().uiMode
+        if ((getActivity().getResources().getConfiguration().uiMode
                 & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
             Log.i(LOG_TAG, "Skipping: testTypeNotificationStateChangedAccessibilityEvent" +
                     " - No notification UI on televisions.");
@@ -323,56 +325,101 @@
 
         String message = getActivity().getString(R.string.notification_message);
 
-        // create the notification to send
-        final int notificationId = 1;
-        final Notification notification = new Notification.Builder(getActivity())
-                .setSmallIcon(android.R.drawable.stat_notify_call_mute)
-                .setContentIntent(PendingIntent.getActivity(getActivity(), 0, new Intent(),
-                        PendingIntent.FLAG_CANCEL_CURRENT))
-                .setTicker(message)
-                .setContentTitle("")
-                .setContentText("")
-                .setPriority(Notification.PRIORITY_MAX)
-                // Mark the notification as "interruptive" by specifying a vibration pattern. This
-                // ensures it's announced properly on watch-type devices.
-                .setVibrate(new long[] {})
-                .build();
+        final NotificationManager notificationManager =
+                (NotificationManager) getActivity().getSystemService(Service.NOTIFICATION_SERVICE);
+        final NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        try {
+            // create the notification to send
+            channel.enableVibration(true);
+            channel.setLights(true);
+            channel.setBypassDnd(true);
+            notificationManager.createNotificationChannel(channel, (createdChannel) -> {}, null);
+            NotificationChannel created =
+                    notificationManager.getNotificationChannel(channel.getId());
+            final int notificationId = 1;
+            final Notification notification = new Notification.Builder(getActivity())
+                    .setSmallIcon(android.R.drawable.stat_notify_call_mute)
+                    .setContentIntent(PendingIntent.getActivity(getActivity(), 0, new Intent(),
+                            PendingIntent.FLAG_CANCEL_CURRENT))
+                    .setTicker(message)
+                    .setContentTitle("")
+                    .setContentText("")
+                    .setChannel(channel.getId())
+                    .setPriority(Notification.PRIORITY_MAX)
+                    // Mark the notification as "interruptive" by specifying a vibration pattern.
+                    // This ensures it's announced properly on watch-type devices.
+                    .setVibrate(new long[]{})
+                    .build();
 
-        // create and populate the expected event
-        final AccessibilityEvent expected = AccessibilityEvent.obtain();
-        expected.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-        expected.setClassName(Notification.class.getName());
-        expected.setPackageName(getActivity().getPackageName());
-        expected.getText().add(message);
-        expected.setParcelableData(notification);
+            // create and populate the expected event
+            final AccessibilityEvent expected = AccessibilityEvent.obtain();
+            expected.setEventType(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+            expected.setClassName(Notification.class.getName());
+            expected.setPackageName(getActivity().getPackageName());
+            expected.getText().add(message);
+            expected.setParcelableData(notification);
 
-        AccessibilityEvent awaitedEvent =
-            getInstrumentation().getUiAutomation().executeAndWaitForEvent(
-                new Runnable() {
-            @Override
-            public void run() {
-                // trigger the event
-                getActivity().runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        // trigger the event
-                        NotificationManager notificationManager =
-                            (NotificationManager) getActivity().getSystemService(
-                                    Service.NOTIFICATION_SERVICE);
-                        notificationManager.notify(notificationId, notification);
-                        getActivity().finish();
+            AccessibilityEvent awaitedEvent =
+                    getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    // trigger the event
+                                    getActivity().runOnUiThread(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            // trigger the event
+                                            notificationManager
+                                                    .notify(notificationId, notification);
+                                            getActivity().finish();
+                                        }
+                                    });
+                                }
+                            },
+                            new UiAutomation.AccessibilityEventFilter() {
+                                // check the received event
+                                @Override
+                                public boolean accept(AccessibilityEvent event) {
+                                    return equalsAccessiblityEvent(event, expected);
+                                }
+                            },
+                            TIMEOUT_ASYNC_PROCESSING);
+            assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+        } finally {
+            notificationManager.deleteNotificationChannel(channel.getId());
+        }
+    }
+
+    @MediumTest
+    public void testInterrupt_notifiesService() {
+        getInstrumentation()
+                .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
+                this, InstrumentedAccessibilityService.class);
+        try {
+            assertFalse(service.wasOnInterruptCalled());
+
+            getActivity().runOnUiThread(() -> {
+                AccessibilityManager accessibilityManager = (AccessibilityManager) getActivity()
+                        .getSystemService(Service.ACCESSIBILITY_SERVICE);
+                accessibilityManager.interrupt();
+            });
+
+            Object waitObject = service.getInterruptWaitObject();
+            synchronized (waitObject) {
+                if (!service.wasOnInterruptCalled()) {
+                    try {
+                        waitObject.wait(TIMEOUT_ASYNC_PROCESSING);
+                    } catch (InterruptedException e) {
+                        // Do nothing
                     }
-                });
-            }},
-            new UiAutomation.AccessibilityEventFilter() {
-                // check the received event
-                @Override
-                public boolean accept(AccessibilityEvent event) {
-                    return equalsAccessiblityEvent(event, expected);
                 }
-            },
-            TIMEOUT_ASYNC_PROCESSING);
-        assertNotNull("Did not receive expected event: " + expected, awaitedEvent);
+            }
+            assertTrue(service.wasOnInterruptCalled());
+        } finally {
+            service.disableSelfAndRemove();
+        }
     }
 
     /**
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 8dbbeef..31ccee1 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -14,12 +14,23 @@
 
 package android.accessibilityservice.cts;
 
+import static android.accessibilityservice.GestureDescription.StrokeDescription.INVALID_STROKE_ID;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.any;
+import static org.hamcrest.CoreMatchers.both;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.StrokeDescription;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -29,6 +40,9 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.TextView;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -42,6 +56,20 @@
     private static final int GESTURE_COMPLETION_TIMEOUT = 5000; // millis
     private static final int MOTION_EVENT_TIMEOUT = 1000; // millis
 
+    private static final Matcher<MotionEvent> IS_ACTION_DOWN =
+            new MotionEventActionMatcher(MotionEvent.ACTION_DOWN);
+    private static final Matcher<MotionEvent> IS_ACTION_POINTER_DOWN =
+            new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_DOWN);
+    private static final Matcher<MotionEvent> IS_ACTION_UP =
+            new MotionEventActionMatcher(MotionEvent.ACTION_UP);
+    private static final Matcher<MotionEvent> IS_ACTION_POINTER_UP =
+            new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_UP);
+    private static final Matcher<MotionEvent> IS_ACTION_CANCEL =
+            new MotionEventActionMatcher(MotionEvent.ACTION_CANCEL);
+    private static final Matcher<MotionEvent> IS_ACTION_MOVE =
+            new MotionEventActionMatcher(MotionEvent.ACTION_MOVE);
+
+
     final List<MotionEvent> mMotionEvents = new ArrayList<>();
     StubGestureAccessibilityService mService;
     MyTouchListener mMyTouchListener = new MyTouchListener();
@@ -60,7 +88,6 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-
         PackageManager pm = getInstrumentation().getContext().getPackageManager();
         mHasTouchScreen = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
                 || pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
@@ -100,20 +127,19 @@
             return;
         }
 
-        final int clickXInsideView = 10;
-        final int clickYInsideView = 20;
-        int clickX = clickXInsideView + mViewBounds.left;
-        int clickY = clickYInsideView + mViewBounds.top;
-        GestureDescription click = createClick(clickX, clickY);
+        Point clickPoint = new Point(10, 20);
+        GestureDescription click = createClickInViewBounds(clickPoint);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
         mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
-        waitForMotionEvents(2);
+        waitForMotionEvents(any(MotionEvent.class), 2);
 
         assertEquals(2, mMotionEvents.size());
         MotionEvent clickDown = mMotionEvents.get(0);
         MotionEvent clickUp = mMotionEvents.get(1);
+        assertThat(clickDown, both(IS_ACTION_DOWN).and(isAtPoint(clickPoint)));
+        assertThat(clickUp, both(IS_ACTION_UP).and(isAtPoint(clickPoint)));
 
-        assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
+        // Verify other MotionEvent fields in this test to make sure they get initialized.
         assertEquals(0, clickDown.getActionIndex());
         assertEquals(0, clickDown.getDeviceId());
         assertEquals(0, clickDown.getEdgeFlags());
@@ -121,18 +147,14 @@
         assertEquals(1F, clickDown.getYPrecision());
         assertEquals(1, clickDown.getPointerCount());
         assertEquals(1F, clickDown.getPressure());
-        assertEquals((float) clickXInsideView, clickDown.getX());
-        assertEquals((float) clickYInsideView, clickDown.getY());
-        assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
 
-        assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
+        // Verify timing matches click
+        assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
         assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
         assertEquals(ViewConfiguration.getTapTimeout(),
                 clickUp.getEventTime() - clickUp.getDownTime());
         assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
                 > clickUp.getEventTime());
-        assertEquals((float) clickXInsideView, clickUp.getX());
-        assertEquals((float) clickYInsideView, clickUp.getY());
     }
 
     public void testLongClickAt_producesEventsWithLongClickTiming() throws InterruptedException {
@@ -140,30 +162,21 @@
             return;
         }
 
-        final int clickXInsideView = 10;
-        final int clickYInsideView = 20;
-        int clickX = clickXInsideView + mViewBounds.left;
-        int clickY = clickYInsideView + mViewBounds.top;
-        GestureDescription longClick = createLongClick(clickX, clickY);
+        Point clickPoint = new Point(10, 20);
+        GestureDescription longClick = createLongClickInViewBounds(clickPoint);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(longClick, mCallback, null));
         mCallback.assertGestureCompletes(
                 ViewConfiguration.getLongPressTimeout() + GESTURE_COMPLETION_TIMEOUT);
 
-        waitForMotionEvents(2);
+        waitForMotionEvents(any(MotionEvent.class), 2);
         MotionEvent clickDown = mMotionEvents.get(0);
         MotionEvent clickUp = mMotionEvents.get(1);
+        assertThat(clickDown, both(IS_ACTION_DOWN).and(isAtPoint(clickPoint)));
+        assertThat(clickUp, both(IS_ACTION_UP).and(isAtPoint(clickPoint)));
 
-        assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
-
-        assertEquals((float) clickXInsideView, clickDown.getX());
-        assertEquals((float) clickYInsideView, clickDown.getY());
-
-        assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
         assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
                 <= clickUp.getEventTime());
         assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
-        assertEquals((float) clickXInsideView, clickUp.getX());
-        assertEquals((float) clickYInsideView, clickUp.getY());
     }
 
     public void testSwipe_shouldContainPointsInALine() throws InterruptedException {
@@ -171,45 +184,34 @@
             return;
         }
 
-        int startXInsideView = 10;
-        int startYInsideView = 20;
-        int endXInsideView = 20;
-        int endYInsideView = 40;
-        int startX = startXInsideView + mViewBounds.left;
-        int startY = startYInsideView + mViewBounds.top;
-        int endX = endXInsideView + mViewBounds.left;
-        int endY = endYInsideView + mViewBounds.top;
+        Point startPoint = new Point(10, 20);
+        Point endPoint = new Point(20, 40);
         int gestureTime = 500;
-        float swipeTolerance = 2.0f;
 
-        GestureDescription swipe = createSwipe(startX, startY, endX, endY, gestureTime);
+        GestureDescription swipe = createSwipeInViewBounds(startPoint, endPoint, gestureTime);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(swipe, mCallback, null));
         mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
-        waitForUpEvent();
+        waitForMotionEvents(IS_ACTION_UP, 1);
+
         int numEvents = mMotionEvents.size();
 
         MotionEvent downEvent = mMotionEvents.get(0);
-        assertEquals(MotionEvent.ACTION_DOWN, downEvent.getActionMasked());
-        assertEquals(startXInsideView, (int) downEvent.getX());
-        assertEquals(startYInsideView, (int) downEvent.getY());
-
         MotionEvent upEvent = mMotionEvents.get(numEvents - 1);
-        assertEquals(MotionEvent.ACTION_UP, upEvent.getActionMasked());
-        assertEquals(endXInsideView, (int) upEvent.getX());
-        assertEquals(endYInsideView, (int) upEvent.getY());
+        assertThat(downEvent, both(IS_ACTION_DOWN).and(isAtPoint(startPoint)));
+        assertThat(upEvent, both(IS_ACTION_UP).and(isAtPoint(endPoint)));
         assertEquals(gestureTime, upEvent.getEventTime() - downEvent.getEventTime());
 
         long lastEventTime = downEvent.getEventTime();
         for (int i = 1; i < numEvents - 1; i++) {
             MotionEvent moveEvent = mMotionEvents.get(i);
-            assertEquals(MotionEvent.ACTION_MOVE, moveEvent.getActionMasked());
             assertTrue(moveEvent.getEventTime() >= lastEventTime);
             float fractionOfSwipe =
                     ((float) (moveEvent.getEventTime() - downEvent.getEventTime())) / gestureTime;
-            float fractionX = ((float) (endXInsideView - startXInsideView)) * fractionOfSwipe;
-            float fractionY = ((float) (endYInsideView - startYInsideView)) * fractionOfSwipe;
-            assertEquals(startXInsideView + fractionX, moveEvent.getX(), swipeTolerance);
-            assertEquals(startYInsideView + fractionY, moveEvent.getY(), swipeTolerance);
+            float fractionX = ((float) (endPoint.x - startPoint.x)) * fractionOfSwipe + 0.5f;
+            float fractionY = ((float) (endPoint.y - startPoint.y)) * fractionOfSwipe + 0.5f;
+            Point intermediatePoint = new Point(startPoint);
+            intermediatePoint.offset((int) fractionX, (int) fractionY);
+            assertThat(moveEvent, both(IS_ACTION_MOVE).and(isAtPoint(intermediatePoint)));
             lastEventTime = moveEvent.getEventTime();
         }
     }
@@ -219,40 +221,24 @@
             return;
         }
 
-        int startXInsideView = 10;
-        int startYInsideView = 20;
-        int endXInsideView = 11;
-        int endYInsideView = 22;
-        int startX = startXInsideView + mViewBounds.left;
-        int startY = startYInsideView + mViewBounds.top;
-        int endX = endXInsideView + mViewBounds.left;
-        int endY = endYInsideView + mViewBounds.top;
+        Point startPoint = new Point(10, 20);
+        Point intermediatePoint1 = new Point(10, 21);
+        Point intermediatePoint2 = new Point(11, 21);
+        Point intermediatePoint3 = new Point(11, 22);
+        Point endPoint = new Point(11, 22);
         int gestureTime = 1000;
 
-        GestureDescription swipe = createSwipe(startX, startY, endX, endY, gestureTime);
+        GestureDescription swipe = createSwipeInViewBounds(startPoint, endPoint, gestureTime);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(swipe, mCallback, null));
         mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
-        waitForUpEvent();
+        waitForMotionEvents(IS_ACTION_UP, 1);
 
         assertEquals(5, mMotionEvents.size());
-
-        assertEquals(MotionEvent.ACTION_DOWN, mMotionEvents.get(0).getActionMasked());
-        assertEquals(MotionEvent.ACTION_MOVE, mMotionEvents.get(1).getActionMasked());
-        assertEquals(MotionEvent.ACTION_MOVE, mMotionEvents.get(2).getActionMasked());
-        assertEquals(MotionEvent.ACTION_MOVE, mMotionEvents.get(3).getActionMasked());
-        assertEquals(MotionEvent.ACTION_UP, mMotionEvents.get(4).getActionMasked());
-
-        assertEquals(startXInsideView, (int) mMotionEvents.get(0).getX());
-        assertEquals(startXInsideView, (int) mMotionEvents.get(1).getX());
-        assertEquals(startXInsideView + 1, (int) mMotionEvents.get(2).getX());
-        assertEquals(startXInsideView + 1, (int) mMotionEvents.get(3).getX());
-        assertEquals(startXInsideView + 1, (int) mMotionEvents.get(4).getX());
-
-        assertEquals(startYInsideView, (int) mMotionEvents.get(0).getY());
-        assertEquals(startYInsideView + 1, (int) mMotionEvents.get(1).getY());
-        assertEquals(startYInsideView + 1, (int) mMotionEvents.get(2).getY());
-        assertEquals(startYInsideView + 2, (int) mMotionEvents.get(3).getY());
-        assertEquals(startYInsideView + 2, (int) mMotionEvents.get(4).getY());
+        assertThat(mMotionEvents.get(0), both(IS_ACTION_DOWN).and(isAtPoint(startPoint)));
+        assertThat(mMotionEvents.get(1), both(IS_ACTION_MOVE).and(isAtPoint(intermediatePoint1)));
+        assertThat(mMotionEvents.get(2), both(IS_ACTION_MOVE).and(isAtPoint(intermediatePoint2)));
+        assertThat(mMotionEvents.get(3), both(IS_ACTION_MOVE).and(isAtPoint(intermediatePoint3)));
+        assertThat(mMotionEvents.get(4), both(IS_ACTION_UP).and(isAtPoint(endPoint)));
     }
 
     public void testAngledPinch_looksReasonable() throws InterruptedException {
@@ -260,71 +246,42 @@
             return;
         }
 
-        int centerXInsideView = 50;
-        int centerYInsideView = 60;
-        int centerX = centerXInsideView + mViewBounds.left;
-        int centerY = centerYInsideView + mViewBounds.top;
+        Point centerPoint = new Point(50, 60);
         int startSpacing = 100;
         int endSpacing = 50;
         int gestureTime = 500;
         float pinchTolerance = 2.0f;
 
-        GestureDescription pinch = createPinch(centerX, centerY, startSpacing,
+        GestureDescription pinch = createPinchInViewBounds(centerPoint, startSpacing,
                 endSpacing, 45.0F, gestureTime);
         mService.runOnServiceSync(() -> mService.doDispatchGesture(pinch, mCallback, null));
         mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
-        waitForUpEvent();
+        waitForMotionEvents(IS_ACTION_UP, 1);
         int numEvents = mMotionEvents.size();
 
-        // First two events are the initial down and the pointer down
-        assertEquals(MotionEvent.ACTION_DOWN, mMotionEvents.get(0).getActionMasked());
-        assertEquals(MotionEvent.ACTION_POINTER_DOWN, mMotionEvents.get(1).getActionMasked());
+        // First and last two events are the pointers going down and up
+        assertThat(mMotionEvents.get(0), IS_ACTION_DOWN);
+        assertThat(mMotionEvents.get(1), IS_ACTION_POINTER_DOWN);
+        assertThat(mMotionEvents.get(numEvents - 2), IS_ACTION_POINTER_UP);
+        assertThat(mMotionEvents.get(numEvents - 1), IS_ACTION_UP);
+        // The rest of the events are all moves
+        assertEquals(numEvents - 4, getEventsMatching(IS_ACTION_MOVE).size());
 
-        // The second event must have two pointers at the initial spacing along a 45 degree angle
-        MotionEvent firstEventWithTwoPointers = mMotionEvents.get(1);
-        assertEquals(2, firstEventWithTwoPointers.getPointerCount());
-        MotionEvent.PointerCoords coords0 = new MotionEvent.PointerCoords();
-        MotionEvent.PointerCoords coords1 = new MotionEvent.PointerCoords();
-        firstEventWithTwoPointers.getPointerCoords(0, coords0);
-        firstEventWithTwoPointers.getPointerCoords(1, coords1);
-        // Verify center point
-        assertEquals((float) centerXInsideView, (coords0.x + coords1.x) / 2, pinchTolerance);
-        assertEquals((float) centerYInsideView, (coords0.y + coords1.y) / 2, pinchTolerance);
-        // Verify angle
-        assertEquals(coords0.x - centerXInsideView, coords0.y - centerYInsideView, pinchTolerance);
-        assertEquals(coords1.x - centerXInsideView, coords1.y - centerYInsideView, pinchTolerance);
-        // Verify spacing
-        assertEquals(startSpacing, distance(coords0, coords1), pinchTolerance);
-
-        // The last two events are the pointer up and the final up
-        assertEquals(MotionEvent.ACTION_UP, mMotionEvents.get(numEvents - 1).getActionMasked());
-
-        MotionEvent lastEventWithTwoPointers = mMotionEvents.get(numEvents - 2);
-        assertEquals(MotionEvent.ACTION_POINTER_UP, lastEventWithTwoPointers.getActionMasked());
-        lastEventWithTwoPointers.getPointerCoords(0, coords0);
-        lastEventWithTwoPointers.getPointerCoords(1, coords1);
-        // Verify center point
-        assertEquals((float) centerXInsideView, (coords0.x + coords1.x) / 2, pinchTolerance);
-        assertEquals((float) centerYInsideView, (coords0.y + coords1.y) / 2, pinchTolerance);
-        // Verify angle
-        assertEquals(coords0.x - centerXInsideView, coords0.y - centerYInsideView, pinchTolerance);
-        assertEquals(coords1.x - centerXInsideView, coords1.y - centerYInsideView, pinchTolerance);
-        // Verify spacing
-        assertEquals(endSpacing, distance(coords0, coords1), pinchTolerance);
-
+        // All but the first and last events have two pointers
         float lastSpacing = startSpacing;
-        for (int i = 2; i < numEvents - 2; i++) {
-            MotionEvent eventInMiddle = mMotionEvents.get(i);
-            assertEquals(MotionEvent.ACTION_MOVE, eventInMiddle.getActionMasked());
-            eventInMiddle.getPointerCoords(0, coords0);
-            eventInMiddle.getPointerCoords(1, coords1);
+        for (int i = 1; i < numEvents - 1; i++) {
+            MotionEvent.PointerCoords coords0 = new MotionEvent.PointerCoords();
+            MotionEvent.PointerCoords coords1 = new MotionEvent.PointerCoords();
+            MotionEvent event = mMotionEvents.get(i);
+            event.getPointerCoords(0, coords0);
+            event.getPointerCoords(1, coords1);
             // Verify center point
-            assertEquals((float) centerXInsideView, (coords0.x + coords1.x) / 2, pinchTolerance);
-            assertEquals((float) centerYInsideView, (coords0.y + coords1.y) / 2, pinchTolerance);
+            assertEquals((float) centerPoint.x, (coords0.x + coords1.x) / 2, pinchTolerance);
+            assertEquals((float) centerPoint.y, (coords0.y + coords1.y) / 2, pinchTolerance);
             // Verify angle
-            assertEquals(coords0.x - centerXInsideView, coords0.y - centerYInsideView,
+            assertEquals(coords0.x - centerPoint.x, coords0.y - centerPoint.y,
                     pinchTolerance);
-            assertEquals(coords1.x - centerXInsideView, coords1.y - centerYInsideView,
+            assertEquals(coords1.x - centerPoint.x, coords1.y - centerPoint.y,
                     pinchTolerance);
             float spacing = distance(coords0, coords1);
             assertTrue(spacing <= lastSpacing + pinchTolerance);
@@ -336,17 +293,24 @@
     // This test assumes device's screen contains its center (W/2, H/2) with some surroundings
     // and should work for rectangular, round and round with chin screens.
     public void testClickWhenMagnified_matchesActualTouch() throws InterruptedException {
+        final float POINT_TOL = 2.0f;
+        final float CLICK_SHIFT_FROM_CENTER_X = 10;
+        final float CLICK_SHIFT_FROM_CENTER_Y = 20;
+        final float MAGNIFICATION_FACTOR = 2;
         if (!mHasTouchScreen) {
             return;
         }
 
-        final int clickShiftFromCenterX = 10;
-        final int clickShiftFromCenterY = 20;
         final Resources res = getInstrumentation().getTargetContext().getResources();
         final DisplayMetrics metrics = res.getDisplayMetrics();
-        final int centerX = metrics.widthPixels / 2;
-        final int centerY = metrics.heightPixels / 2;
-        final float TOUCH_TOLERANCE = 2.0f;
+        final float centerX = metrics.widthPixels / 2;
+        final float centerY = metrics.heightPixels / 2;
+        final PointF clickPoint = new PointF(
+                centerX + CLICK_SHIFT_FROM_CENTER_X * MAGNIFICATION_FACTOR,
+                centerY + CLICK_SHIFT_FROM_CENTER_Y * MAGNIFICATION_FACTOR);
+        final PointF offsetMagnifiedPointInView = new PointF(
+                centerX + CLICK_SHIFT_FROM_CENTER_X - mViewBounds.left,
+                centerY + CLICK_SHIFT_FROM_CENTER_Y - mViewBounds.top);
 
         StubMagnificationAccessibilityService magnificationService =
                 StubMagnificationAccessibilityService.enableSelf(this);
@@ -355,19 +319,16 @@
         try {
             // Magnify screen by 2x with a magnification center in the center of the screen
             final AtomicBoolean setScale = new AtomicBoolean();
-            final float magnificationFactor = 2.0f;
             magnificationService.runOnServiceSync(() -> {
-                        setScale.set(magnificationController.setScale(magnificationFactor, false));
+                        setScale.set(magnificationController.setScale(MAGNIFICATION_FACTOR, false));
                         magnificationController.setCenter(centerX, centerY, false);
                     });
             assertTrue("Failed to set scale", setScale.get());
 
-            final int clickMagnifiedX = (int) (centerX + magnificationFactor * clickShiftFromCenterX);
-            final int clickMagnifiedY = (int) (centerY + magnificationFactor * clickShiftFromCenterY);
-            GestureDescription click = createClick(clickMagnifiedX, clickMagnifiedY);
+            GestureDescription click = createClick(clickPoint);
             mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
             mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
-            waitForMotionEvents(3);
+            waitForMotionEvents(any(MotionEvent.class), 2);
         } finally {
             // Reset magnification
             final AtomicBoolean result = new AtomicBoolean();
@@ -378,23 +339,136 @@
         }
 
         assertEquals(2, mMotionEvents.size());
-        MotionEvent clickDown = mMotionEvents.get(0);
-        MotionEvent clickUp = mMotionEvents.get(1);
-
-        final int centerXInsideView = centerX - mViewBounds.left;
-        final int centerYInsideView = centerY - mViewBounds.top;
-        final int expectedClickXInsideView = centerXInsideView + clickShiftFromCenterX;
-        final int expectedClickYInsideView = centerYInsideView + clickShiftFromCenterY;
-        assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
-        assertEquals((float) expectedClickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
-        assertEquals((float) expectedClickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
-        assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
-
-        assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
-        assertEquals((float) expectedClickXInsideView, clickUp.getX(), TOUCH_TOLERANCE);
-        assertEquals((float) expectedClickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
+        assertThat(mMotionEvents.get(0),
+                both(IS_ACTION_DOWN).and(isAtPoint(offsetMagnifiedPointInView, POINT_TOL)));
+        assertThat(mMotionEvents.get(1),
+                both(IS_ACTION_UP).and(isAtPoint(offsetMagnifiedPointInView, POINT_TOL)));
     }
 
+    public void testContinuedGestures_motionEventsContinue() throws Exception {
+        if (!mHasTouchScreen) {
+            return;
+        }
+
+        Point start = new Point(10, 20);
+        Point mid1 = new Point(20, 20);
+        Point mid2 = new Point(20, 25);
+        Point end = new Point(20, 30);
+        int gestureTime = 500;
+
+        StrokeDescription s1 =
+                lineStrokeInViewBounds(start, mid1, gestureTime, INVALID_STROKE_ID, true);
+        StrokeDescription s2 = lineStrokeInViewBounds(mid1, mid2, gestureTime, s1.getId(), true);
+        StrokeDescription s3 = lineStrokeInViewBounds(mid2, end, gestureTime, s2.getId(), false);
+        GestureDescription gesture1 = new GestureDescription.Builder().addStroke(s1).build();
+        GestureDescription gesture2 = new GestureDescription.Builder().addStroke(s2).build();
+        GestureDescription gesture3 = new GestureDescription.Builder().addStroke(s3).build();
+
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture1, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+        mCallback.reset();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture2, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+        mCallback.reset();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture3, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+        waitForMotionEvents(IS_ACTION_UP, 1);
+
+        assertThat(mMotionEvents.get(0), allOf(IS_ACTION_DOWN, isAtPoint(start)));
+        assertThat(mMotionEvents.subList(1, mMotionEvents.size() - 1), everyItem(IS_ACTION_MOVE));
+        assertThat(mMotionEvents, hasItem(isAtPoint(mid1)));
+        assertThat(mMotionEvents, hasItem(isAtPoint(mid2)));
+        assertThat(mMotionEvents.get(mMotionEvents.size() - 1),
+                allOf(IS_ACTION_UP, isAtPoint(end)));
+    }
+
+    public void testContinuedGesture_withLineDisconnect_isCancelled() throws Exception {
+        if (!mHasTouchScreen) {
+            return;
+        }
+
+        Point startPoint = new Point(10, 20);
+        Point midPoint = new Point(20, 20);
+        Point endPoint = new Point(20, 30);
+        int gestureTime = 500;
+
+        StrokeDescription stroke1 = lineStrokeInViewBounds(
+                startPoint, midPoint, gestureTime, INVALID_STROKE_ID, true);
+        GestureDescription gesture1 = new GestureDescription.Builder().addStroke(stroke1).build();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture1, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+        waitForMotionEvents(both(IS_ACTION_MOVE).and(isAtPoint(midPoint)), 1);
+
+        StrokeDescription stroke2 = lineStrokeInViewBounds(endPoint, midPoint, gestureTime,
+                stroke1.getId(), false);
+        GestureDescription gesture2 = new GestureDescription.Builder().addStroke(stroke2).build();
+        mCallback.reset();
+        mMotionEvents.clear();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture2, mCallback, null));
+        mCallback.assertGestureCancels(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+
+        waitForMotionEvents(IS_ACTION_CANCEL, 1);
+        assertEquals(1, mMotionEvents.size());
+    }
+
+    public void testContinuedGesture_nextGestureDoesntContinue_isCancelled() throws Exception {
+        if (!mHasTouchScreen) {
+            return;
+        }
+
+        Point startPoint = new Point(10, 20);
+        Point midPoint = new Point(20, 20);
+        Point endPoint = new Point(20, 30);
+        int gestureTime = 500;
+
+        StrokeDescription stroke1 = lineStrokeInViewBounds(
+                startPoint, midPoint, gestureTime, INVALID_STROKE_ID, true);
+        GestureDescription gesture1 = new GestureDescription.Builder().addStroke(stroke1).build();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture1, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+
+        StrokeDescription stroke2 = lineStrokeInViewBounds(
+                midPoint, endPoint, gestureTime, INVALID_STROKE_ID, false);
+        GestureDescription gesture2 = new GestureDescription.Builder().addStroke(stroke2).build();
+        mCallback.reset();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture2, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+
+        waitForMotionEvents(IS_ACTION_UP, 1);
+
+        List<MotionEvent> cancelEvent = getEventsMatching(IS_ACTION_CANCEL);
+        assertEquals(1, cancelEvent.size());
+        // Confirm that a down follows the cancel
+        assertThat(mMotionEvents.get(mMotionEvents.indexOf(cancelEvent.get(0)) + 1),
+                both(IS_ACTION_DOWN).and(isAtPoint(midPoint)));
+        // Confirm that the last point is an up
+        assertThat(mMotionEvents.get(mMotionEvents.size() - 1),
+                both(IS_ACTION_UP).and(isAtPoint(endPoint)));
+    }
+
+    public void testContinuingGesture_withNothingToContinue_isCancelled() {
+        if (!mHasTouchScreen) {
+            return;
+        }
+
+        Point startPoint = new Point(10, 20);
+        Point midPoint = new Point(20, 20);
+        Point endPoint = new Point(20, 30);
+        int gestureTime = 500;
+
+        StrokeDescription stroke1 = lineStrokeInViewBounds(
+                startPoint, midPoint, gestureTime, INVALID_STROKE_ID, false);
+        GestureDescription gesture1 = new GestureDescription.Builder().addStroke(stroke1).build();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture1, mCallback, null));
+        mCallback.assertGestureCompletes(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+
+        StrokeDescription stroke2 = lineStrokeInViewBounds(
+                midPoint, endPoint, gestureTime, stroke1.getId(), false);
+        GestureDescription gesture2 = new GestureDescription.Builder().addStroke(stroke2).build();
+        mCallback.reset();
+        mService.runOnServiceSync(() -> mService.doDispatchGesture(gesture2, mCallback, null));
+        mCallback.assertGestureCancels(gestureTime + GESTURE_COMPLETION_TIMEOUT);
+    }
 
     public static class GestureDispatchActivity extends AccessibilityTestActivity {
         public GestureDispatchActivity() {
@@ -433,27 +507,51 @@
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
-            assertTrue("Gesture did not complete.", mCompleted);
+            assertTrue("Gesture did not complete. Canceled = " + mCancelled, mCompleted);
+        }
+
+        public synchronized void assertGestureCancels(long timeout) {
+            if (mCancelled) {
+                return;
+            }
+            try {
+                wait(timeout);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            assertTrue("Gesture did not cancel. Completed = " + mCompleted, mCancelled);
+        }
+
+        public synchronized void reset() {
+            mCancelled = false;
+            mCompleted = false;
         }
     }
 
-    private void waitForMotionEvents(int numEventsExpected) throws InterruptedException {
+    private void waitForMotionEvents(Matcher<MotionEvent> matcher, int numEventsExpected)
+            throws InterruptedException {
         synchronized (mMotionEvents) {
             long endMillis = SystemClock.uptimeMillis() + MOTION_EVENT_TIMEOUT;
-            while ((mMotionEvents.size() < numEventsExpected)
-                    && (SystemClock.uptimeMillis() < endMillis)) {
+            boolean gotEvents = getEventsMatching(matcher).size() >= numEventsExpected;
+            while (!gotEvents && (SystemClock.uptimeMillis() < endMillis)) {
                 mMotionEvents.wait(endMillis - SystemClock.uptimeMillis());
+                gotEvents = getEventsMatching(matcher).size() >= numEventsExpected;
             }
+            assertTrue("Did not receive required events. Got:\n" + mMotionEvents + "\n filtered:\n"
+                    + getEventsMatching(matcher), gotEvents);
         }
     }
 
-    private void waitForUpEvent() throws InterruptedException {
+    private List<MotionEvent> getEventsMatching(Matcher<MotionEvent> matcher) {
+        List<MotionEvent> events = new ArrayList<>();
         synchronized (mMotionEvents) {
-            long endMillis = SystemClock.uptimeMillis() + MOTION_EVENT_TIMEOUT;
-            while (!mGotUpEvent && (SystemClock.uptimeMillis() < endMillis)) {
-                mMotionEvents.wait(endMillis - SystemClock.uptimeMillis());
+            for (MotionEvent event : mMotionEvents) {
+                if (matcher.matches(event)) {
+                    events.add(event);
+                }
             }
         }
+        return events;
     }
 
     private float distance(MotionEvent.PointerCoords point1, MotionEvent.PointerCoords point2) {
@@ -474,45 +572,53 @@
         }
     }
 
-    private GestureDescription createClick(int x, int y) {
+    private GestureDescription createClickInViewBounds(Point clickPoint) {
+        Point offsetClick = new Point(clickPoint);
+        offsetClick.offset(mViewBounds.left, mViewBounds.top);
+        return createClick(offsetClick);
+    }
+
+    private GestureDescription createClick(Point clickPoint) {
+        return createClick(new PointF(clickPoint.x, clickPoint.y));
+    }
+
+    private GestureDescription createClick(PointF clickPoint) {
         Path clickPath = new Path();
-        clickPath.moveTo(x, y);
-        GestureDescription.StrokeDescription clickStroke =
-                new GestureDescription.StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout());
+        clickPath.moveTo(clickPoint.x, clickPoint.y);
+        StrokeDescription clickStroke =
+                new StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout());
         GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
         clickBuilder.addStroke(clickStroke);
         return clickBuilder.build();
     }
 
-    private GestureDescription createLongClick(int x, int y) {
+    private GestureDescription createLongClickInViewBounds(Point clickPoint) {
+        Point offsetPoint = new Point(clickPoint);
+        offsetPoint.offset(mViewBounds.left, mViewBounds.top);
         Path clickPath = new Path();
-        clickPath.moveTo(x, y);
+        clickPath.moveTo(offsetPoint.x, offsetPoint.y);
         int longPressTime = ViewConfiguration.getLongPressTimeout();
 
-        GestureDescription.StrokeDescription longClickStroke =
-                new GestureDescription.StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2));
+        StrokeDescription longClickStroke =
+                new StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2));
         GestureDescription.Builder longClickBuilder = new GestureDescription.Builder();
         longClickBuilder.addStroke(longClickStroke);
         return longClickBuilder.build();
     }
 
-    private GestureDescription createSwipe(
-            int startX, int startY, int endX, int endY, long duration) {
-        Path swipePath = new Path();
-        swipePath.moveTo(startX, startY);
-        swipePath.lineTo(endX, endY);
-
-        GestureDescription.StrokeDescription swipeStroke = new GestureDescription.StrokeDescription(swipePath, 0, duration);
-        GestureDescription.Builder swipeBuilder = new GestureDescription.Builder();
-        swipeBuilder.addStroke(swipeStroke);
-        return swipeBuilder.build();
+    private GestureDescription createSwipeInViewBounds(Point start, Point end, long duration) {
+        return new GestureDescription.Builder()
+                .addStroke(lineStrokeInViewBounds(start, end, duration, INVALID_STROKE_ID, false))
+                .build();
     }
 
-    private GestureDescription createPinch(int centerX, int centerY, int startSpacing,
+    private GestureDescription createPinchInViewBounds(Point centerPoint, int startSpacing,
             int endSpacing, float orientation, long duration) {
         if ((startSpacing < 0) || (endSpacing < 0)) {
             throw new IllegalArgumentException("Pinch spacing cannot be negative");
         }
+        Point offsetCenter = new Point(centerPoint);
+        offsetCenter.offset(mViewBounds.left, mViewBounds.top);
         float[] startPoint1 = new float[2];
         float[] endPoint1 = new float[2];
         float[] startPoint2 = new float[2];
@@ -531,7 +637,7 @@
         /* Rotate and translate the points */
         Matrix matrix = new Matrix();
         matrix.setRotate(orientation);
-        matrix.postTranslate(centerX, centerY);
+        matrix.postTranslate(offsetCenter.x, offsetCenter.y);
         matrix.mapPoints(startPoint1);
         matrix.mapPoints(endPoint1);
         matrix.mapPoints(startPoint2);
@@ -544,11 +650,57 @@
         path2.moveTo(startPoint2[0], startPoint2[1]);
         path2.lineTo(endPoint2[0], endPoint2[1]);
 
-        GestureDescription.StrokeDescription path1Stroke = new GestureDescription.StrokeDescription(path1, 0, duration);
-        GestureDescription.StrokeDescription path2Stroke = new GestureDescription.StrokeDescription(path2, 0, duration);
+        StrokeDescription path1Stroke = new StrokeDescription(path1, 0, duration);
+        StrokeDescription path2Stroke = new StrokeDescription(path2, 0, duration);
         GestureDescription.Builder swipeBuilder = new GestureDescription.Builder();
         swipeBuilder.addStroke(path1Stroke);
         swipeBuilder.addStroke(path2Stroke);
         return swipeBuilder.build();
     }
+
+    StrokeDescription lineStrokeInViewBounds(Point startPoint, Point endPoint, long duration,
+            int continuedStroke, boolean isContinued) {
+        Path path = new Path();
+        path.moveTo(startPoint.x + mViewBounds.left, startPoint.y + mViewBounds.top);
+        path.lineTo(endPoint.x + mViewBounds.left, endPoint.y + mViewBounds.top);
+        return new StrokeDescription(path, 0, duration, continuedStroke, isContinued);
+    }
+
+    private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> {
+        int mAction;
+
+        MotionEventActionMatcher(int action) {
+            super();
+            mAction = action;
+        }
+
+        @Override
+        protected boolean matchesSafely(MotionEvent motionEvent) {
+            return motionEvent.getActionMasked() == mAction;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to action " + mAction);
+        }
+    }
+
+
+    Matcher<MotionEvent> isAtPoint(final Point point) {
+        return isAtPoint(new PointF(point.x, point.y), 0.01f);
+    }
+
+    Matcher<MotionEvent> isAtPoint(final PointF point, final float tol) {
+        return new TypeSafeMatcher<MotionEvent>() {
+            @Override
+            protected boolean matchesSafely(MotionEvent event) {
+                return Math.hypot(event.getX() - point.x, event.getY() - point.y) < tol;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Matching to point " + point);
+            }
+        };
+    }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
index a292e4e..60dace3 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
@@ -19,13 +19,13 @@
 import android.content.Context;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import android.accessibilityservice.cts.R;
+import android.widget.Button;
 import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.ArrayList;
 
 /**
  * Test cases for testing the accessibility focus APIs exposed to accessibility
@@ -274,6 +274,47 @@
         assertFalse(firstButtonNode.isImportantForAccessibility());
     }
 
+    @MediumTest
+    public void testAddViewToLayout_receiveSubtreeEvent() throws Throwable {
+        final LinearLayout layout =
+                (LinearLayout) getActivity().findViewById(R.id.secondLinearLayout);
+        final Button newButton = new Button(getActivity());
+        newButton.setText("New Button");
+        newButton.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+        newButton.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+        AccessibilityEvent awaitedEvent =
+                getInstrumentation().getUiAutomation().executeAndWaitForEvent(
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                // trigger the event
+                                getActivity().runOnUiThread(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        layout.addView(newButton);
+                                    }
+                                });
+                            }},
+                        new UiAutomation.AccessibilityEventFilter() {
+                            // check the received event
+                            @Override
+                            public boolean accept(AccessibilityEvent event) {
+                                boolean isContentChanged = event.getEventType()
+                                        == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+                                int isSubTree = (event.getContentChangeTypes()
+                                        & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+                                boolean isFromThisPackage = event.getPackageName()
+                                        .equals(getActivity().getPackageName());
+                                return isContentChanged && (isSubTree != 0) && isFromThisPackage;
+                            }
+                        },
+                        TIMEOUT_ASYNC_PROCESSING);
+        // The event should come from a view that's important for accessibility, even though the
+        // layout we added it to isn't important. Otherwise services may not find out about the
+        // new button.
+        assertTrue(awaitedEvent.getSource().isImportantForAccessibility());
+    }
+
     private UiAutomation getUiAutomation(boolean getNonImportantViews) {
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         AccessibilityServiceInfo serviceInfo = uiAutomation.getServiceInfo();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index fae014e..5dc7ed1 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -85,6 +85,11 @@
 
     @MediumTest
     public void testNoWindowsAccessIfFlagNotSet() throws Exception {
+        // Clear window access flag
+        AccessibilityServiceInfo info = getInstrumentation().getUiAutomation().getServiceInfo();
+        info.flags &= ~AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        getInstrumentation().getUiAutomation().setServiceInfo(info);
+
         // Make sure the windows cannot be accessed.
         UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
         assertTrue(uiAutomation.getWindows().isEmpty());
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
index d17a285..c638951 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
@@ -24,5 +24,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.accessibility_window_reporting_test);
+        setTitle("AccessibilityWindowReportingActivity");
     }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 3fee77c..c9eef93 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -58,6 +58,34 @@
         window.recycle();
     }
 
+    public void testUpdatedWindowTitle_generatesEventAndIsReturnedByGetTitle() {
+        final String updatedTitle = "Updated Title";
+        try {
+            mUiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    getInstrumentation().runOnMainSync(new Runnable() {
+                        @Override
+                        public void run() {
+                            getActivity().setTitle(updatedTitle);
+                        }
+                    });
+                }
+            }, new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return (event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+                }
+            }, TIMEOUT_ASYNC_PROCESSING);
+        } catch (TimeoutException exception) {
+            throw new RuntimeException(
+                    "Failed to get windows changed event for title update", exception);
+        }
+        AccessibilityWindowInfo window = findWindowByTitle(updatedTitle);
+        assertNotNull("Updated window title not reported to accessibility", window);
+        window.recycle();
+    }
+
     public void testGetAnchorForDropDownForAutoCompleteTextView_returnsTextViewNode() {
         final AutoCompleteTextView autoCompleteTextView =
                 (AutoCompleteTextView) getActivity().findViewById(R.id.autoCompleteLayout);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index 234f66a..b1c37cf 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -15,10 +15,14 @@
 package android.accessibilityservice.cts;
 
 import android.accessibilityservice.GestureDescription;
+import android.accessibilityservice.GestureDescription.StrokeDescription;
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 import android.test.InstrumentationTestCase;
 
+import static android.accessibilityservice.GestureDescription.StrokeDescription.INVALID_STROKE_ID;
+import static android.test.MoreAsserts.assertNotEqual;
+
 /**
  * Tests for creating gesture descriptions.
  */
@@ -35,7 +39,7 @@
 
     public void testCreateStroke_noDuration_shouldThrow() {
         try {
-            new GestureDescription.StrokeDescription(mNominalPath, 0, 0);
+            new StrokeDescription(mNominalPath, 0, 0);
             fail("Missing exception for stroke with no duration.");
         } catch (IllegalArgumentException e) {
         }
@@ -43,7 +47,7 @@
 
     public void testCreateStroke_negativeStartTime_shouldThrow() {
         try {
-            new GestureDescription.StrokeDescription(mNominalPath, -1, NOMINAL_PATH_DURATION);
+            new StrokeDescription(mNominalPath, -1, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with negative start time.");
         } catch (IllegalArgumentException e) {
         }
@@ -54,7 +58,7 @@
         negativeStartXPath.moveTo(-1, 0);
         negativeStartXPath.lineTo(10, 10);
         try {
-            new GestureDescription.StrokeDescription(negativeStartXPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(negativeStartXPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with negative start x coord.");
         } catch (IllegalArgumentException e) {
         }
@@ -65,7 +69,7 @@
         negativeStartYPath.moveTo(0, -1);
         negativeStartYPath.lineTo(10, 10);
         try {
-            new GestureDescription.StrokeDescription(negativeStartYPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(negativeStartYPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with negative start y coord.");
         } catch (IllegalArgumentException e) {
         }
@@ -76,7 +80,7 @@
         negativeEndXPath.moveTo(0, 0);
         negativeEndXPath.lineTo(-10, 10);
         try {
-            new GestureDescription.StrokeDescription(negativeEndXPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(negativeEndXPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with negative end x coord.");
         } catch (IllegalArgumentException e) {
         }
@@ -87,7 +91,7 @@
         negativeEndYPath.moveTo(0, 0);
         negativeEndYPath.lineTo(10, -10);
         try {
-            new GestureDescription.StrokeDescription(negativeEndYPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(negativeEndYPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with negative end y coord.");
         } catch (IllegalArgumentException e) {
         }
@@ -96,7 +100,7 @@
     public void testCreateStroke_withEmptyPath_shouldThrow() {
         Path emptyPath = new Path();
         try {
-            new GestureDescription.StrokeDescription(emptyPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(emptyPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for empty path.");
         } catch (IllegalArgumentException e) {
         }
@@ -109,27 +113,48 @@
         multiContourPath.moveTo(20, 0);
         multiContourPath.lineTo(20, 10);
         try {
-            new GestureDescription.StrokeDescription(multiContourPath, 0, NOMINAL_PATH_DURATION);
+            new StrokeDescription(multiContourPath, 0, NOMINAL_PATH_DURATION);
             fail("Missing exception for stroke with multi-contour path.");
         } catch (IllegalArgumentException e) {
         }
     }
 
+    public void testStrokeDescriptionGettersForContinuation() {
+        StrokeDescription strokeDescription = new StrokeDescription(mNominalPath, 0, 100);
+        assertFalse(strokeDescription.isContinued());
+
+        strokeDescription = new StrokeDescription(mNominalPath, 0, 100, INVALID_STROKE_ID, true);
+        assertTrue(strokeDescription.isContinued());
+
+        strokeDescription = new StrokeDescription(mNominalPath, 0, 100, INVALID_STROKE_ID, false);
+        assertFalse(strokeDescription.isContinued());
+
+        int idOfContinuedStroke = strokeDescription.getId() - 1;
+        strokeDescription = new StrokeDescription(mNominalPath, 0, 100, idOfContinuedStroke, false);
+        assertEquals(idOfContinuedStroke, strokeDescription.getContinuedStrokeId());
+    }
+
+    public void testStrokeDescriptionIds() {
+        StrokeDescription strokeDescription1 =
+                new StrokeDescription(mNominalPath, 0, 100);
+        StrokeDescription strokeDescription2 =
+                new StrokeDescription(mNominalPath, 0, 100);
+        assertNotEqual(strokeDescription1.getId(), strokeDescription2.getId());
+    }
+
     public void testAddStroke_allowUpToMaxPaths() {
         GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
         for (int i = 0; i < GestureDescription.getMaxStrokeCount(); i++) {
             Path path = new Path();
             path.moveTo(i, i);
             path.lineTo(10 + i, 10 + i);
-            gestureBuilder.addStroke(
-                    new GestureDescription.StrokeDescription(path, 0, NOMINAL_PATH_DURATION));
+            gestureBuilder.addStroke(new StrokeDescription(path, 0, NOMINAL_PATH_DURATION));
         }
         Path path = new Path();
         path.moveTo(10, 10);
         path.lineTo(20, 20);
         try {
-            gestureBuilder.addStroke(
-                    new GestureDescription.StrokeDescription(path, 0, NOMINAL_PATH_DURATION));
+            gestureBuilder.addStroke(new StrokeDescription(path, 0, NOMINAL_PATH_DURATION));
             fail("Missing exception for adding too many strokes.");
         } catch (RuntimeException e) {
         }
@@ -141,8 +166,8 @@
         path.lineTo(20, 20);
         GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
         try {
-            gestureBuilder.addStroke(new GestureDescription.StrokeDescription(
-                    path, 0, GestureDescription.getMaxGestureDuration() + 1));
+            gestureBuilder.addStroke(
+                    new StrokeDescription(path, 0, GestureDescription.getMaxGestureDuration() + 1));
             fail("Missing exception for adding stroke with duration too long.");
         } catch (RuntimeException e) {
         }
@@ -166,7 +191,7 @@
         Path path = new Path();
         path.moveTo(x, startY);
         path.lineTo(x, endY);
-        GestureDescription.StrokeDescription strokeDescription = new GestureDescription.StrokeDescription(path, start, duration);
+        StrokeDescription strokeDescription = new StrokeDescription(path, start, duration);
         GestureDescription.Builder builder = new GestureDescription.Builder();
         builder.addStroke(strokeDescription);
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
index 4a9ce08..31c78c5 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
@@ -30,6 +30,9 @@
             sInstances = new HashMap<>();
 
     private final Handler mHandler = new Handler();
+    final Object mInterruptWaitObject = new Object();
+    public boolean mOnInterruptCalled;
+
 
     @Override
     protected void onServiceConnected() {
@@ -53,7 +56,10 @@
 
     @Override
     public void onInterrupt() {
-        // Stub method.
+        synchronized (mInterruptWaitObject) {
+            mOnInterruptCalled = true;
+            mInterruptWaitObject.notifyAll();
+        }
     }
 
     public void disableSelfAndRemove() {
@@ -70,6 +76,16 @@
         assertTrue("Timed out waiting for runOnServiceSync()", sr.waitForComplete());
     }
 
+    public boolean wasOnInterruptCalled() {
+        synchronized (mInterruptWaitObject) {
+            return mOnInterruptCalled;
+        }
+    }
+
+    public Object getInterruptWaitObject() {
+        return mInterruptWaitObject;
+    }
+
     private static final class SyncRunnable implements Runnable {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final Runnable mTarget;
diff --git a/tests/admin/Android.mk b/tests/admin/Android.mk
index 74bfc70..595c0a3 100644
--- a/tests/admin/Android.mk
+++ b/tests/admin/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner mockito-target
+    ctstestrunner mockito-target-minus-junit4
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index 03cc150..43602f0 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -27,7 +27,7 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.admin.cts" />
-        <option name="runtime-hint" value="20s" />
+        <option name="runtime-hint" value="17m" />
     </test>
 
     <!-- Instrument the app to clear the device admins so the apk can be uninstalled -->
diff --git a/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java b/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
index 81ea503..b7d2895 100644
--- a/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
+++ b/tests/admin/src/android/admin/cts/DeviceAdminReceiverTest.java
@@ -29,6 +29,8 @@
     private static final String TAG = DeviceAdminReceiverTest.class.getSimpleName();
     private static final String DISABLE_WARNING = "Disable Warning";
     private static final String BUGREPORT_HASH = "f4k3h45h";
+    private static final long NETWORK_LOGS_TOKEN = 0L;
+    private static final int NETWORK_LOGS_COUNT = 0;
 
     private static final String ACTION_BUGREPORT_SHARING_DECLINED =
             "android.app.action.BUGREPORT_SHARING_DECLINED";
@@ -41,6 +43,13 @@
             "android.app.extra.BUGREPORT_FAILURE_REASON";
     private static final String EXTRA_BUGREPORT_HASH = "android.app.extra.BUGREPORT_HASH";
 
+    private static final String ACTION_NETWORK_LOGS_AVAILABLE
+            = "android.app.action.NETWORK_LOGS_AVAILABLE";
+    private static final String EXTRA_NETWORK_LOGS_TOKEN =
+            "android.app.extra.EXTRA_NETWORK_LOGS_TOKEN";
+    private static final String EXTRA_NETWORK_LOGS_COUNT =
+            "android.app.extra.EXTRA_NETWORK_LOGS_COUNT";
+
     private static final int PASSWORD_CHANGED = 0x1;
     private static final int PASSWORD_FAILED = 0x2;
     private static final int PASSWORD_SUCCEEDED = 0x4;
@@ -51,6 +60,7 @@
     private static final int BUGREPORT_FAILED = 0x80;
     private static final int BUGREPORT_SHARED = 0x100;
     private static final int SECURITY_LOGS_AVAILABLE = 0x200;
+    private static final int NETWORK_LOGS_AVAILABLE = 0x400;
 
     private TestReceiver mReceiver;
     private boolean mDeviceAdmin;
@@ -112,6 +122,15 @@
         mReceiver.reset();
         mReceiver.onReceive(mContext, new Intent(ACTION_SECURITY_LOGS_AVAILABLE));
         assertTrue(mReceiver.hasFlags(SECURITY_LOGS_AVAILABLE));
+
+        mReceiver.reset();
+        Intent networkLogsAvailableIntent = new Intent(ACTION_NETWORK_LOGS_AVAILABLE);
+        networkLogsAvailableIntent.putExtra(EXTRA_NETWORK_LOGS_TOKEN, NETWORK_LOGS_TOKEN);
+        networkLogsAvailableIntent.putExtra(EXTRA_NETWORK_LOGS_COUNT, NETWORK_LOGS_COUNT);
+        mReceiver.onReceive(mContext, networkLogsAvailableIntent);
+        assertTrue(mReceiver.hasFlags(NETWORK_LOGS_AVAILABLE));
+        assertEquals(NETWORK_LOGS_TOKEN, mReceiver.getNetworkLogsToken());
+        assertEquals(NETWORK_LOGS_COUNT, mReceiver.getNetworkLogsCount());
     }
 
     private class TestReceiver extends DeviceAdminReceiver {
@@ -119,10 +138,14 @@
         private int mFlags = 0;
         private int bugreportFailureCode = -1;
         private String bugreportHash;
+        private long networkLogsToken = -1L;
+        private int networkLogsCount = -1;
 
         void reset() {
             mFlags = 0;
             bugreportFailureCode = -1;
+            networkLogsToken = -1L;
+            networkLogsCount = -1;
             bugreportHash = null;
         }
 
@@ -138,6 +161,14 @@
             return bugreportHash;
         }
 
+        long getNetworkLogsToken() {
+            return networkLogsToken;
+        }
+
+        int getNetworkLogsCount() {
+            return networkLogsCount;
+        }
+
         @Override
         public void onPasswordChanged(Context context, Intent intent) {
             super.onPasswordChanged(context, intent);
@@ -199,5 +230,14 @@
             super.onSecurityLogsAvailable(context, intent);
             mFlags |= SECURITY_LOGS_AVAILABLE;
         }
+
+        @Override
+        public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken,
+                int networkLogsCount) {
+            super.onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
+            mFlags |= NETWORK_LOGS_AVAILABLE;
+            this.networkLogsToken = batchToken;
+            this.networkLogsCount = networkLogsCount;
+        }
     }
 }
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index deb1854..aa4a688 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -174,6 +174,44 @@
         }
     }
 
+    public void testSetNetworkLoggingEnabled_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetNetworkLoggingEnabled_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setNetworkLoggingEnabled(mComponent, true);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testIsNetworkLoggingEnabled_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testIsNetworkLoggingEnabled_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.isNetworkLoggingEnabled(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
+    public void testRetrieveNetworkLogs_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testRetrieveNetworkLogs_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.retrieveNetworkLogs(mComponent, /* batchToken */ 0);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
     public void testRemoveUser_failIfNotDeviceOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testRemoveUser_failIfNotDeviceOwner");
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index d62ee46..a1298cb 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 := compatibility-device-util ctstestrunner ctstestserver mockito-target-minus-junit4 android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/app/app/Android.mk b/tests/app/app/Android.mk
index 24b5c5c..8463a56 100644
--- a/tests/app/app/Android.mk
+++ b/tests/app/app/Android.mk
@@ -25,7 +25,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 := compatibility-device-util ctstestrunner ctstestserver mockito-target-minus-junit4
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
               src/android/app/stubs/ISecondary.aidl
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index b5460a6..a03edf4 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -41,6 +41,7 @@
     <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.BODY_SENSORS" />
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <application android:label="Android TestCase"
                 android:icon="@drawable/size_48x48"
@@ -196,7 +197,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 +330,9 @@
 
         <activity android:name="android.app.stubs.KeyboardShortcutsActivity" />
 
+        <activity android:name="android.app.stubs.NewDocumentTestActivity"
+                  android:documentLaunchMode="intoExisting" />
+
         <service
             android:name="android.app.stubs.LiveWallpaper"
             android:icon="@drawable/robot"
diff --git a/tests/app/app/res/layout/fragment_a.xml b/tests/app/app/res/layout/fragment_a.xml
deleted file mode 100644
index 38e0423..0000000
--- a/tests/app/app/res/layout/fragment_a.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_b.xml b/tests/app/app/res/layout/fragment_b.xml
deleted file mode 100644
index d8ed961..0000000
--- a/tests/app/app/res/layout/fragment_b.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textB"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_c.xml b/tests/app/app/res/layout/fragment_c.xml
deleted file mode 100644
index ed3c753..0000000
--- a/tests/app/app/res/layout/fragment_c.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textC"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_end.xml b/tests/app/app/res/layout/fragment_end.xml
deleted file mode 100644
index aa3d9e8..0000000
--- a/tests/app/app/res/layout/fragment_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:transitionName="destination"
-              android:id="@+id/hello"
-              android:text="@string/hello"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:id="@+id/redSquare"/>
-</LinearLayout>
diff --git a/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java b/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java
index 44ff6b2..7e8d764 100644
--- a/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java
+++ b/tests/app/app/src/android/app/stubs/CTSActivityTestCaseBase.java
@@ -16,9 +16,10 @@
 
 package android.app.stubs;
 
-import android.cts.util.CTSResult;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.CTSResult;
+
 public class CTSActivityTestCaseBase extends InstrumentationTestCase implements CTSResult {
 
     private Sync mSync;
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/IntentServiceStub.java b/tests/app/app/src/android/app/stubs/IntentServiceStub.java
index 626e464..65e9b2a 100644
--- a/tests/app/app/src/android/app/stubs/IntentServiceStub.java
+++ b/tests/app/app/src/android/app/stubs/IntentServiceStub.java
@@ -18,10 +18,11 @@
 
 import android.app.IntentService;
 import android.content.Intent;
-import android.cts.util.PollingCheck;
 import android.os.Binder;
 import android.os.IBinder;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 public class IntentServiceStub extends IntentService {
     public IntentServiceStub() {
         super("IntentServiceStub");
diff --git a/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
index 8e28ee4..1ab931d 100644
--- a/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
+++ b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
@@ -21,10 +21,11 @@
 import android.app.ActivityGroup;
 import android.app.LocalActivityManager;
 import android.content.Intent;
-import android.cts.util.CTSResult;
 import android.os.Bundle;
 import android.view.Window;
 
+import com.android.compatibility.common.util.CTSResult;
+
 public class LocalActivityManagerTestHelper extends ActivityGroup {
 
     public static final String ACTION_DISPATCH_RESUME = "dispatchResume";
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
index 119b9f8..d0f63bb 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundService.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -20,12 +20,13 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
-import android.cts.util.IBinderParcelable;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.Log;
 import android.app.stubs.R;
 
+import com.android.compatibility.common.util.IBinderParcelable;
+
 public class LocalForegroundService extends LocalService {
 
     private static final String TAG = "LocalForegroundService";
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
index 01e098b..f0624b2 100644
--- a/tests/app/app/src/android/app/stubs/LocalService.java
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -18,12 +18,13 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.cts.util.IBinderParcelable;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
 
+import com.android.compatibility.common.util.IBinderParcelable;
+
 public class LocalService extends Service {
     public static final String SERVICE_LOCAL =
             "android.app.cts.activity.SERVICE_LOCAL";
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/app/src/android/app/stubs/SearchManagerStubActivity.java b/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java
index d6eb968..eee4f09 100644
--- a/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java
+++ b/tests/app/app/src/android/app/stubs/SearchManagerStubActivity.java
@@ -20,12 +20,13 @@
 import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.cts.util.CTSResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CTSResult;
+
 public class SearchManagerStubActivity extends Activity {
 
     private static final String TAG = "SearchManagerStubActivity";
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/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 9049171..8c04dad 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -15,6 +15,9 @@
  */
 package android.app.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
+import android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
@@ -32,12 +35,20 @@
 import android.app.stubs.MockService;
 import android.app.stubs.ScreenOnActivity;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.SystemClock;
 import android.platform.test.annotations.RestrictedBuildTest;
 import android.test.InstrumentationTestCase;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -52,6 +63,7 @@
     private static final String SIMPLE_ACTIVITY = ".SimpleActivity";
     private static final String SIMPLE_ACTIVITY_IMMEDIATE_EXIT = ".SimpleActivityImmediateExit";
     private static final String SIMPLE_ACTIVITY_CHAIN_EXIT = ".SimpleActivityChainExit";
+    private static final String SIMPLE_SERVICE = ".SimpleService";
     // The action sent back by the SIMPLE_APP after a restart.
     private static final String ACTIVITY_LAUNCHED_ACTION =
             "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
@@ -339,13 +351,14 @@
             }
         }
         // start a new process
+        // XXX would be a lot cleaner to bind instead of start.
         mIntent = new Intent("android.app.REMOTESERVICE");
         mIntent.setPackage("android.app.stubs");
         mInstrumentation.getTargetContext().startService(mIntent);
         Thread.sleep(WAITFOR_MSEC);
 
         List<RunningAppProcessInfo> listNew = mActivityManager.getRunningAppProcesses();
-        assertTrue(list.size() <= listNew.size());
+        mInstrumentation.getTargetContext().stopService(mIntent);
 
         for (RunningAppProcessInfo ra : listNew) {
             if (ra.processName.equals("android.app.stubs:remote")) {
@@ -366,7 +379,7 @@
     }
 
     /**
-     * Simple test for {@link ActivityManager.isUserAMonkey()} - verifies its false.
+     * Simple test for {@link ActivityManager#isUserAMonkey()} - verifies its false.
      *
      * TODO: test positive case
      */
@@ -375,7 +388,7 @@
     }
 
     /**
-     * Verify that {@link ActivityManager.isRunningInTestHarness()} is false.
+     * Verify that {@link ActivityManager#isRunningInTestHarness()} is false.
      */
     @RestrictedBuildTest
     public void testIsRunningInTestHarness() {
@@ -395,6 +408,240 @@
         Thread.sleep(WAIT_TIME);
     }
 
+    static final class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
+        final int mUid;
+
+        int mLastValue = -1;
+
+        UidImportanceListener(int uid) {
+            mUid = uid;
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            synchronized (this) {
+                Log.d("XXXXX", "Got importance for uid " + uid + ": " + importance);
+                if (uid == mUid) {
+                    mLastValue = importance;
+                    notifyAll();
+                }
+            }
+        }
+
+        public int waitForValue(int minValue, int maxValue, long timeout) {
+            final long endTime = SystemClock.uptimeMillis()+timeout;
+
+            synchronized (this) {
+                while (mLastValue < minValue || mLastValue > maxValue) {
+                    final long now = SystemClock.uptimeMillis();
+                    if (now >= endTime) {
+                        throw new IllegalStateException("Timed out waiting for importance "
+                                + minValue + "-" + maxValue + ", last was " + mLastValue);
+                    }
+                    try {
+                        wait(endTime-now);
+                    } catch (InterruptedException e) {
+                    }
+                }
+                Log.d("XXXX", "waitForValue " + minValue + "-" + maxValue + ": " + mLastValue);
+                return mLastValue;
+            }
+        }
+    }
+
+    static final class ServiceConnectionHandler implements ServiceConnection {
+        final Context mContext;
+        final Intent mIntent;
+        boolean mBound;
+        IBinder mService;
+
+        final ServiceConnection mMainBinding = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+            }
+        };
+
+        ServiceConnectionHandler(Context context, Intent intent) {
+            mContext = context;
+            mIntent = intent;
+        }
+
+        public void bind(long timeout) {
+            synchronized (this) {
+                if (mBound) {
+                    throw new IllegalStateException("Already bound");
+                }
+                // Here's the trick: the first binding allows us to to see the service come
+                // up and go down but doesn't actually cause it to run or impact process management.
+                // The second binding actually brings it up.
+                if (!mContext.bindService(mIntent, this, Context.BIND_WAIVE_PRIORITY)) {
+                    throw new IllegalStateException("Failed to bind " + mIntent);
+                }
+                if (!mContext.bindService(mIntent, mMainBinding, Context.BIND_AUTO_CREATE)) {
+                    throw new IllegalStateException("Failed to bind " + mIntent);
+                }
+                mBound = true;
+                mService = null;
+
+                final long endTime = SystemClock.uptimeMillis() + timeout;
+
+                while (mService == null) {
+                    final long now = SystemClock.uptimeMillis();
+                    if (now >= endTime) {
+                        throw new IllegalStateException("Timed out binding to " + mIntent);
+                    }
+                    try {
+                        wait(endTime - now);
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+
+        public void unbind(long timeout) {
+            synchronized (this) {
+                if (!mBound) {
+                    throw new IllegalStateException("Not bound");
+                }
+                // This allows the service to go down.  We maintain the second binding to be
+                // able to see the connection go away which is what we want to wait on.
+                mContext.unbindService(mMainBinding);
+                mBound = false;
+
+                try {
+                    final long endTime = SystemClock.uptimeMillis() + timeout;
+
+                    while (mService != null) {
+                        final long now = SystemClock.uptimeMillis();
+                        if (now >= endTime) {
+                            throw new IllegalStateException("Timed out unbinding from " + mIntent);
+                        }
+                        try {
+                            wait(endTime - now);
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                } finally {
+                    mContext.unbindService(this);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (this) {
+                mService = service;
+                notifyAll();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (this) {
+                mService = null;
+                notifyAll();
+            }
+        }
+    }
+
+    public void testUidImportanceListener() throws Exception {
+        Intent serviceIntent = new Intent();
+        Parcel data = Parcel.obtain();
+        serviceIntent.setClassName(SIMPLE_PACKAGE_NAME,
+                SIMPLE_PACKAGE_NAME + SIMPLE_SERVICE);
+        ServiceConnectionHandler conn = new ServiceConnectionHandler(mContext, serviceIntent);
+
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
+
+        ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(
+                SIMPLE_PACKAGE_NAME, 0);
+        UidImportanceListener uidForegroundListener = new UidImportanceListener(appInfo.uid);
+
+        String cmd = "pm revoke " + STUB_PACKAGE_NAME + " "
+                + Manifest.permission.PACKAGE_USAGE_STATS;
+        String result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+        /*
+        Log.d("XXXX", "Invoke: " + cmd);
+        Log.d("XXXX", "Result: " + result);
+        */
+        boolean gotException = false;
+        try {
+            am.addOnUidImportanceListener(uidForegroundListener,
+                    RunningAppProcessInfo.IMPORTANCE_SERVICE);
+        } catch (SecurityException e) {
+            gotException = true;
+        }
+        assertTrue("Expected SecurityException thrown", gotException);
+
+        cmd = "pm grant " + STUB_PACKAGE_NAME + " "
+                + Manifest.permission.PACKAGE_USAGE_STATS;
+        result = SystemUtil.runShellCommand(getInstrumentation(), cmd);
+        /*
+        Log.d("XXXX", "Invoke: " + cmd);
+        Log.d("XXXX", "Result: " + result);
+        Log.d("XXXX", SystemUtil.runShellCommand(getInstrumentation(), "dumpsys package "
+                + STUB_PACKAGE_NAME));
+        */
+        am.addOnUidImportanceListener(uidForegroundListener,
+                RunningAppProcessInfo.IMPORTANCE_SERVICE);
+
+        UidImportanceListener uidGoneListener = new UidImportanceListener(appInfo.uid);
+        am.addOnUidImportanceListener(uidGoneListener,
+                RunningAppProcessInfo.IMPORTANCE_EMPTY);
+
+        // First kill the process to start out in a stable state.
+        conn.bind(WAIT_TIME);
+        try {
+            conn.mService.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
+        } catch (RemoteException e) {
+        }
+        conn.unbind(WAIT_TIME);
+
+        // Wait for uid's process to go away.
+        uidGoneListener.waitForValue(RunningAppProcessInfo.IMPORTANCE_GONE,
+                RunningAppProcessInfo.IMPORTANCE_GONE, WAIT_TIME);
+        assertEquals(RunningAppProcessInfo.IMPORTANCE_GONE,
+                am.getPackageImportance(SIMPLE_PACKAGE_NAME));
+
+        // Now bind and see if we get told about the uid coming in to the foreground.
+        conn.bind(WAIT_TIME);
+        uidForegroundListener.waitForValue(RunningAppProcessInfo.IMPORTANCE_FOREGROUND,
+                RunningAppProcessInfo.IMPORTANCE_VISIBLE, WAIT_TIME);
+        assertEquals(RunningAppProcessInfo.IMPORTANCE_FOREGROUND,
+                am.getPackageImportance(SIMPLE_PACKAGE_NAME));
+
+        // Pull out the service IBinder for a kludy hack...
+        IBinder service = conn.mService;
+
+        // Now unbind and see if we get told about it going to the background.
+        conn.unbind(WAIT_TIME);
+        uidForegroundListener.waitForValue(RunningAppProcessInfo.IMPORTANCE_BACKGROUND,
+                RunningAppProcessInfo.IMPORTANCE_EMPTY, WAIT_TIME);
+        assertEquals(RunningAppProcessInfo.IMPORTANCE_BACKGROUND,
+                am.getPackageImportance(SIMPLE_PACKAGE_NAME));
+
+        // Now kill the process and see if we are told about it being gone.
+        try {
+            service.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
+        } catch (RemoteException e) {
+            // It is okay if it is already gone for some reason.
+        }
+
+        uidGoneListener.waitForValue(RunningAppProcessInfo.IMPORTANCE_GONE,
+                RunningAppProcessInfo.IMPORTANCE_GONE, WAIT_TIME);
+        assertEquals(RunningAppProcessInfo.IMPORTANCE_GONE,
+                am.getPackageImportance(SIMPLE_PACKAGE_NAME));
+
+        data.recycle();
+
+        am.removeOnUidImportanceListener(uidForegroundListener);
+        am.removeOnUidImportanceListener(uidGoneListener);
+    }
+
     /**
      * Verify that the TimeTrackingAPI works properly when starting and ending an activity.
      */
diff --git a/tests/app/src/android/app/cts/AdjustmentTest.java b/tests/app/src/android/app/cts/AdjustmentTest.java
new file mode 100644
index 0000000..00a28d2
--- /dev/null
+++ b/tests/app/src/android/app/cts/AdjustmentTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.NotificationChannel;
+import android.app.NotificationManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.service.notification.Adjustment;
+import android.service.notification.SnoozeCriterion;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+
+public class AdjustmentTest extends AndroidTestCase {
+
+    final String mPkg = "pkg";
+    final String mKey = "key";
+    final Bundle mSignals = new Bundle();
+    final CharSequence mExplanation = "explanation";
+    final int mUser = 0;
+    ArrayList<String> mPeople = new ArrayList<>();
+    ArrayList<SnoozeCriterion> mSnoozeCriteria = new ArrayList<>();
+    NotificationChannel mNotificationChannel = new NotificationChannel("id", "name",
+            NotificationManager.IMPORTANCE_DEFAULT);
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mSnoozeCriteria.add(new SnoozeCriterion("id", "exp", "confirm"));
+        mSnoozeCriteria.add(new SnoozeCriterion("id2", "hello", "goodbye"));
+        mSignals.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, mSnoozeCriteria);
+
+        mPeople.add(new Uri.Builder().scheme("person").build().toString());
+        mSignals.putStringArrayList(Adjustment.KEY_PEOPLE, mPeople);
+
+        mSignals.putParcelable(Adjustment.KEY_CHANNEL_ID, mNotificationChannel);
+    }
+
+    public void testDescribeContents() {
+        final int expected = 0;
+
+        Adjustment adjustment = new Adjustment(mPkg, mKey, mSignals, mExplanation, mUser);
+        assertEquals(expected, adjustment.describeContents());
+    }
+
+    public void testConstructor() {
+        Adjustment adjustment = new Adjustment(mPkg, mKey, mSignals, mExplanation, mUser);
+        assertEquals(mPkg, adjustment.getPackage());
+        assertEquals(mKey, adjustment.getKey());
+        assertEquals(mSignals, adjustment.getSignals());
+        assertEquals(mExplanation, adjustment.getExplanation());
+        assertEquals(mUser, adjustment.getUser());
+    }
+
+    public void testWriteToParcel() {
+        Adjustment adjustment = new Adjustment(mPkg, mKey, mSignals, mExplanation, mUser);
+        Parcel parcel = Parcel.obtain();
+        adjustment.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        Adjustment adjustment1 = Adjustment.CREATOR.createFromParcel(parcel);
+        assertEquals(mPkg, adjustment1.getPackage());
+        assertEquals(mKey, adjustment1.getKey());
+        for (String key : mSignals.keySet()) {
+            assertTrue(adjustment1.getSignals().containsKey(key));
+            assertEquals(mSignals.get(key), adjustment1.getSignals().get(key));
+        }
+        assertEquals(mExplanation, adjustment1.getExplanation());
+        assertEquals(mUser, adjustment1.getUser());
+    }
+}
diff --git a/tests/app/src/android/app/cts/AlarmManagerTest.java b/tests/app/src/android/app/cts/AlarmManagerTest.java
index fabedd9..3ffb061 100644
--- a/tests/app/src/android/app/cts/AlarmManagerTest.java
+++ b/tests/app/src/android/app/cts/AlarmManagerTest.java
@@ -24,13 +24,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.PollingCheck;
 import android.os.Build;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 public class AlarmManagerTest extends AndroidTestCase {
     public static final String MOCKACTION = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER";
     public static final String MOCKACTION2 = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER2";
diff --git a/tests/app/src/android/app/cts/AlertDialogTest.java b/tests/app/src/android/app/cts/AlertDialogTest.java
index e9628a6..b633d46 100644
--- a/tests/app/src/android/app/cts/AlertDialogTest.java
+++ b/tests/app/src/android/app/cts/AlertDialogTest.java
@@ -20,12 +20,13 @@
 import android.app.Instrumentation;
 import android.app.stubs.DialogStubActivity;
 import android.content.DialogInterface;
-import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import android.app.stubs.R;
 /*
  * Test AlertDialog
diff --git a/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java b/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java
index 972afe6..f18ffd4 100644
--- a/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java
+++ b/tests/app/src/android/app/cts/AlertDialog_BuilderCursorTest.java
@@ -25,7 +25,6 @@
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.content.DialogInterface.OnMultiChoiceClickListener;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteCursor;
 import android.database.sqlite.SQLiteDatabase;
@@ -34,6 +33,8 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.File;
 
 import static org.mockito.Mockito.*;
diff --git a/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
index 710c8d6..f0ff28d 100644
--- a/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
+++ b/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
@@ -29,7 +29,6 @@
 import android.content.DialogInterface.OnKeyListener;
 import android.content.DialogInterface.OnMultiChoiceClickListener;
 import android.content.res.TypedArray;
-import android.cts.util.PollingCheck;
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -43,6 +42,8 @@
 import android.widget.ListView;
 import org.mockito.ArgumentCaptor;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import static org.mockito.Mockito.*;
 
 @SmallTest
diff --git a/tests/app/src/android/app/cts/DialogTest.java b/tests/app/src/android/app/cts/DialogTest.java
index fa22ce4..42b1fed 100755
--- a/tests/app/src/android/app/cts/DialogTest.java
+++ b/tests/app/src/android/app/cts/DialogTest.java
@@ -28,7 +28,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.cts.util.PollingCheck;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Rect;
@@ -52,6 +51,8 @@
 
 import android.app.stubs.R;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.lang.ref.WeakReference;
 
 public class DialogTest extends ActivityInstrumentationTestCase2<DialogStubActivity> {
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 1bec983..873647f 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -35,6 +34,7 @@
 import android.webkit.cts.CtsTestServer;
 
 import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.PollingCheck;
 
 import java.io.File;
 import java.util.Arrays;
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/FragmentReplaceTest.java b/tests/app/src/android/app/cts/FragmentReplaceTest.java
deleted file mode 100644
index ad9e3af..0000000
--- a/tests/app/src/android/app/cts/FragmentReplaceTest.java
+++ /dev/null
@@ -1,71 +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.app.cts;
-
-import android.app.stubs.FragmentTestActivity;
-import android.app.stubs.FragmentTestActivity.TestFragment;
-import android.app.stubs.R;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-
-/**
- * Test to prevent regressions in FragmentManager fragment replace method. See b/24693644
- */
-public class FragmentReplaceTest extends
-        ActivityInstrumentationTestCase2<FragmentTestActivity> {
-    private FragmentTestActivity mActivity;
-
-
-    public FragmentReplaceTest() {
-        super(FragmentTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
-    public void testReplaceFragment() throws Throwable {
-        mActivity.getFragmentManager().beginTransaction()
-                .add(R.id.content, new TestFragment(R.layout.fragment_a))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
-
-        mActivity.getFragmentManager().beginTransaction()
-                .add(R.id.content, new TestFragment(R.layout.fragment_b))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNotNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
-
-        mActivity.getFragmentManager().beginTransaction()
-                .replace(R.id.content, new TestFragment(R.layout.fragment_c))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNotNull(mActivity.findViewById(R.id.textC));
-    }
-}
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/FragmentTransitionTest.java b/tests/app/src/android/app/cts/FragmentTransitionTest.java
deleted file mode 100644
index 7270672..0000000
--- a/tests/app/src/android/app/cts/FragmentTransitionTest.java
+++ /dev/null
@@ -1,466 +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 android.app.cts;
-
-import android.app.FragmentManager;
-import android.app.stubs.FragmentTestActivity;
-import android.app.stubs.FragmentTestActivity.OnTransitionListener;
-import android.app.stubs.FragmentTestActivity.TestFragment;
-import android.app.stubs.R;
-import android.os.Debug;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.View;
-
-public class FragmentTransitionTest extends
-        ActivityInstrumentationTestCase2<FragmentTestActivity> {
-    private TestFragment mStartFragment;
-    private TestFragment mMidFragment;
-    private TestFragment mEndFragment;
-    private FragmentTestActivity mActivity;
-
-    public FragmentTransitionTest() {
-        super(FragmentTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mStartFragment = null;
-        mMidFragment = null;
-        mEndFragment = null;
-        mActivity = getActivity();
-    }
-
-    public void testFragmentTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View sharedElement = mActivity.findViewById(R.id.hello);
-                assertEquals("source", sharedElement.getTransitionName());
-
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .addSharedElement(sharedElement, "destination")
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.SHARED_ELEMENT_ENTER));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View textView = mActivity.findViewById(R.id.hello);
-                assertEquals("destination", textView.getTransitionName());
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.REENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-    }
-
-    public void testFirstOutLastInTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        mStartFragment.clearNotifications();
-        mEndFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.RETURN);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testPopTwo() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mMidFragment, TestFragment.ENTER);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertTrue(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        mStartFragment.clearNotifications();
-        mMidFragment.clearNotifications();
-        mEndFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                FragmentManager fm = mActivity.getFragmentManager();
-                int id = fm.getBackStackEntryAt(0).getId();
-                fm.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
-                fm.executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.RETURN);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testNullTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mStartFragment.clearTransitions();
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.ENTER);
-        // No transitions
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mEndFragment.clearTransitions();
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mEndFragment, TestFragment.ENTER);
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mEndFragment, TestFragment.RETURN);
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testRemoveAdded() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .replace(R.id.content, mStartFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.REENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-    }
-
-    public void testAddRemoved() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .replace(R.id.content, mStartFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.ENTER);
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.EXIT));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.REENTER);
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    private boolean waitForStart(TestFragment fragment, int key) throws InterruptedException {
-        final boolean started;
-        WaitForTransition listener = new WaitForTransition(key, true);
-        fragment.setOnTransitionListener(listener);
-        final long endTime = SystemClock.uptimeMillis() + 100;
-        synchronized (listener) {
-            long waitTime;
-            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
-                    !listener.isDone()) {
-                listener.wait(waitTime);
-            }
-            started = listener.isDone();
-        }
-        fragment.setOnTransitionListener(null);
-        getInstrumentation().waitForIdleSync();
-        return started;
-    }
-
-    private boolean waitForEnd(TestFragment fragment, int key) throws InterruptedException {
-        if (!waitForStart(fragment, key)) {
-            return false;
-        }
-        final boolean ended;
-        WaitForTransition listener = new WaitForTransition(key, false);
-        fragment.setOnTransitionListener(listener);
-        final long endTime = SystemClock.uptimeMillis() + 400;
-        synchronized (listener) {
-            long waitTime;
-            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
-                    !listener.isDone()) {
-                listener.wait(waitTime);
-            }
-            ended = listener.isDone();
-        }
-        fragment.setOnTransitionListener(null);
-        getInstrumentation().waitForIdleSync();
-        return ended;
-    }
-
-    private static class WaitForTransition implements OnTransitionListener {
-        final int key;
-        final boolean isStart;
-        boolean isDone;
-
-        public WaitForTransition(int key, boolean isStart) {
-            this.key = key;
-            this.isStart = isStart;
-        }
-
-        protected boolean isComplete(TestFragment fragment) {
-            if (isStart) {
-                return fragment.wasStartCalled(key);
-            } else {
-                return fragment.wasEndCalled(key);
-            }
-        }
-
-        public synchronized boolean isDone() {
-            return isDone;
-        }
-
-        @Override
-        public synchronized void onTransition(TestFragment fragment) {
-            isDone = isComplete(fragment);
-            if (isDone) {
-                notifyAll();
-            }
-        }
-    }
-
-}
diff --git a/tests/app/src/android/app/cts/IntentServiceTest.java b/tests/app/src/android/app/cts/IntentServiceTest.java
index 9d721fe..7df5428 100644
--- a/tests/app/src/android/app/cts/IntentServiceTest.java
+++ b/tests/app/src/android/app/cts/IntentServiceTest.java
@@ -22,9 +22,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.cts.util.PollingCheck;
 import android.os.IBinder;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.concurrent.Callable;
 
 public class IntentServiceTest extends ActivityTestsBase {
diff --git a/tests/app/src/android/app/cts/LocalActivityManagerTest.java b/tests/app/src/android/app/cts/LocalActivityManagerTest.java
index 7f6fd2f..71869a1 100644
--- a/tests/app/src/android/app/cts/LocalActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/LocalActivityManagerTest.java
@@ -21,10 +21,11 @@
 import android.app.LocalActivityManager;
 import android.app.stubs.LocalActivityManagerTestHelper;
 import android.content.Intent;
-import android.cts.util.CTSResult;
 import android.test.InstrumentationTestCase;
 import android.test.UiThreadTest;
 
+import com.android.compatibility.common.util.CTSResult;
+
 public class LocalActivityManagerTest extends InstrumentationTestCase implements CTSResult {
 
     private Instrumentation mInstrumentation;
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/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
new file mode 100644
index 0000000..cf96532
--- /dev/null
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.NotificationChannel;
+import android.app.NotificationManager;
+import android.net.Uri;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+public class NotificationChannelTest extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testDescribeContents() {
+        final int expected = 0;
+        NotificationChannel channel =
+                new NotificationChannel("1", "1", NotificationManager.IMPORTANCE_DEFAULT);
+        assertEquals(expected, channel.describeContents());
+    }
+
+    public void testConstructor() {
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        assertEquals("1", channel.getId());
+        assertEquals("one", channel.getName());
+        assertEquals(false, channel.canBypassDnd());
+        assertEquals(false, channel.shouldShowLights());
+        assertEquals(false, channel.shouldVibrate());
+        assertEquals(NotificationManager.IMPORTANCE_DEFAULT, channel.getImportance());
+        assertEquals(null, channel.getSound());
+    }
+
+    public void testWriteToParcel() {
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        Parcel parcel = Parcel.obtain();
+        channel.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        NotificationChannel channel1 = NotificationChannel.CREATOR.createFromParcel(parcel);
+        assertEquals(channel, channel1);
+    }
+
+    public void testLights() {
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setLights(true);
+        assertTrue(channel.shouldShowLights());
+        channel.setLights(false);
+        assertFalse(channel.shouldShowLights());
+    }
+
+    public void testVibration() {
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.enableVibration(true);
+        assertTrue(channel.shouldVibrate());
+        channel.enableVibration(false);
+        assertFalse(channel.shouldVibrate());
+    }
+
+    public void testVibrationPattern() {
+        final long[] pattern = new long[] {1, 7, 1, 7, 3};
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        assertNull(channel.getVibrationPattern());
+        channel.setVibrationPattern(pattern);
+        assertEquals(pattern, channel.getVibrationPattern());
+    }
+
+    public void testRingtone() {
+        Uri expected = new Uri.Builder().scheme("fruit").appendQueryParameter("favorite", "bananas")
+                .build();
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setSound(expected);
+        assertEquals(expected, channel.getSound());
+    }
+}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index c4cbaee..6e26dd2 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -17,16 +17,20 @@
 package android.app.cts;
 
 import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.stubs.R;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.provider.Telephony.Threads;
 import android.service.notification.StatusBarNotification;
 import android.test.AndroidTestCase;
 import android.util.Log;
+import java.util.concurrent.CountDownLatch;
 
-import android.app.stubs.R;
+import java.util.Arrays;
 
 public class NotificationManagerTest extends AndroidTestCase {
     final String TAG = NotificationManagerTest.class.getSimpleName();
@@ -49,6 +53,108 @@
         mNotificationManager.cancelAll();
     }
 
+    public void testCreateChannel() throws InterruptedException {
+        final NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        channel.enableVibration(true);
+        channel.setVibrationPattern(new long[] {5, 8, 2, 1});
+        channel.setSound(new Uri.Builder().scheme("test").build());
+        channel.setLights(true);
+        channel.setBypassDnd(true);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+        try {
+            final CountDownLatch latch = new CountDownLatch(1);
+            mNotificationManager.createNotificationChannel(
+                    channel,
+                    (createdChannel) -> {
+                        compareChannels(channel, createdChannel);
+                        latch.countDown();
+                    },
+                    null);
+            // Verify that the Listener was executed.
+            latch.await();
+        } finally {
+            mNotificationManager.deleteNotificationChannel(channel.getId());
+        }
+    }
+
+    public void testCreateChannelAlreadyExists() {
+        NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        try {
+            mNotificationManager.createNotificationChannel(channel, (createdChannel) -> {}, null);
+            compareChannels(channel, mNotificationManager.getNotificationChannel(channel.getId()));
+            try {
+                mNotificationManager.createNotificationChannel(channel, (createdChannel) -> {},
+                        null);
+                fail("Created channel with duplicate id");
+            } catch (IllegalArgumentException e) {
+                // success
+            }
+        } finally {
+            mNotificationManager.deleteNotificationChannel(channel.getId());
+        }
+    }
+
+    public void testCreateChannelInvalidImportance() {
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name", NotificationManager.IMPORTANCE_UNSPECIFIED);
+        try {
+            mNotificationManager.createNotificationChannel(channel, (createdChannel) -> {}, null);
+        } catch (IllegalArgumentException e) {
+            //success
+        }
+    }
+
+    public void testDeleteChannel() {
+        NotificationChannel channel =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
+        mNotificationManager.createNotificationChannel(channel, (createdChannel) -> {}, null);
+        compareChannels(channel, mNotificationManager.getNotificationChannel(channel.getId()));
+        mNotificationManager.deleteNotificationChannel(channel.getId());
+        assertNull(mNotificationManager.getNotificationChannel(channel.getId()));
+    }
+
+    public void testCannotDeleteDefaultChannel() {
+        try {
+            mNotificationManager.deleteNotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID);
+            fail("Deleted default channel");
+        } catch (IllegalArgumentException e) {
+            //success
+        }
+    }
+
+    public void testGetChannel() {
+        NotificationChannel channel1 =
+                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        NotificationChannel channel2 =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
+        NotificationChannel channel3 =
+                new NotificationChannel("id3", "name3", NotificationManager.IMPORTANCE_LOW);
+        NotificationChannel channel4 =
+                new NotificationChannel("id4", "name4", NotificationManager.IMPORTANCE_MIN);
+        try {
+            mNotificationManager.createNotificationChannel(channel1, (createdChannel) -> {}, null);
+            mNotificationManager.createNotificationChannel(channel2, (createdChannel) -> {}, null);
+            mNotificationManager.createNotificationChannel(channel3, (createdChannel) -> {}, null);
+            mNotificationManager.createNotificationChannel(channel4, (createdChannel) -> {}, null);
+
+            compareChannels(channel2,
+                    mNotificationManager.getNotificationChannel(channel2.getId()));
+            compareChannels(channel3,
+                    mNotificationManager.getNotificationChannel(channel3.getId()));
+            compareChannels(channel1,
+                    mNotificationManager.getNotificationChannel(channel1.getId()));
+            compareChannels(channel4,
+                    mNotificationManager.getNotificationChannel(channel4.getId()));
+        } finally {
+            mNotificationManager.deleteNotificationChannel(channel1.getId());
+            mNotificationManager.deleteNotificationChannel(channel2.getId());
+            mNotificationManager.deleteNotificationChannel(channel3.getId());
+            mNotificationManager.deleteNotificationChannel(channel4.getId());
+        }
+    }
+
     public void testNotify() {
         mNotificationManager.cancelAll();
 
@@ -121,7 +227,8 @@
     }
 
     private boolean checkNotificationExistence(int id, boolean shouldExist) {
-        // notification is a bit asynchronous so it may take a few ms to appear in getActiveNotifications()
+        // notification is a bit asynchronous so it may take a few ms to appear in
+        // getActiveNotifications()
         // we will check for it for up to 200ms before giving up
         boolean found = false;
         for (int tries=3; tries-->0;) {
@@ -143,4 +250,24 @@
         }
         return found == shouldExist;
     }
+
+    private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
+        if (actual == null) {
+            fail("actual channel is null");
+            return;
+        }
+        if (expected == null) {
+            fail("expected channel is null");
+            return;
+        }
+        assertEquals(expected.getId(), actual.getId());
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
+        assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
+        assertEquals(expected.getImportance(), actual.getImportance());
+        assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
+        assertEquals(expected.getSound(), actual.getSound());
+        assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
+        assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
+    }
 }
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 1d6d23d..40c323c 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -27,7 +27,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.cts.util.IBinderParcelable;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -38,6 +37,8 @@
 import android.util.Log;
 import android.app.stubs.R;
 
+import com.android.compatibility.common.util.IBinderParcelable;
+
 public class ServiceTest extends ActivityTestsBase {
     private static final String TAG = "ServiceTest";
     private static final int STATE_START_1 = 0;
diff --git a/tests/app/src/android/app/cts/SnoozeCriterionTest.java b/tests/app/src/android/app/cts/SnoozeCriterionTest.java
new file mode 100644
index 0000000..a3edd3c
--- /dev/null
+++ b/tests/app/src/android/app/cts/SnoozeCriterionTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.NotificationChannel;
+import android.app.NotificationManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.service.notification.Adjustment;
+import android.service.notification.SnoozeCriterion;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+
+public class SnoozeCriterionTest extends AndroidTestCase {
+
+    final String mId = "id";
+    final String mExplanation = "explanation";
+    final String mConfirmation = "confirmation";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testDescribeContents() {
+        final int expected = 0;
+
+        SnoozeCriterion snooze = new SnoozeCriterion(mId, mExplanation, mConfirmation);
+        assertEquals(expected, snooze.describeContents());
+    }
+
+    public void testConstructor() {
+        SnoozeCriterion snooze = new SnoozeCriterion(mId, mExplanation, mConfirmation);
+        assertEquals(mId, snooze.getId());
+        assertEquals(mExplanation, snooze.getExplanation());
+        assertEquals(mConfirmation, snooze.getConfirmation());
+    }
+
+    public void testWriteToParcel() {
+        SnoozeCriterion snooze = new SnoozeCriterion(mId, mExplanation, mConfirmation);
+        Parcel parcel = Parcel.obtain();
+        snooze.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        SnoozeCriterion snooze1 = SnoozeCriterion.CREATOR.createFromParcel(parcel);
+        assertEquals(mId, snooze1.getId());
+        assertEquals(mExplanation, snooze1.getExplanation());
+        assertEquals(mConfirmation, snooze1.getConfirmation());
+    }
+}
diff --git a/tests/aslr/AndroidTest.xml b/tests/aslr/AndroidTest.xml
index d610519..0149faa 100644
--- a/tests/aslr/AndroidTest.xml
+++ b/tests/aslr/AndroidTest.xml
@@ -22,8 +22,8 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="CtsAslrMallocTestCases" />
-        <option name="runtime-hint" value="3m30s" />
+        <option name="runtime-hint" value="10m30s" />
         <!-- test-timeout unit is ms, value = 10 min -->
         <option name="native-test-timeout" value="600000" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/aslr/src/AslrMallocTest.cpp b/tests/aslr/src/AslrMallocTest.cpp
index 9259841..5fcf968 100644
--- a/tests/aslr/src/AslrMallocTest.cpp
+++ b/tests/aslr/src/AslrMallocTest.cpp
@@ -146,7 +146,9 @@
             return EXIT_FAILURE;
         }
 
-        printf("%p", malloc(size));
+        void* p = malloc(size);
+        printf("%p", p);
+        free(p);
         return EXIT_SUCCESS;
     }
 
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index a2de68b..d791fa6 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/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 := compatibility-device-util ctstestrunner ctstestserver mockito-target-minus-junit4
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/backup/AndroidTest.xml b/tests/backup/AndroidTest.xml
index ce5d261..96417c8 100644
--- a/tests/backup/AndroidTest.xml
+++ b/tests/backup/AndroidTest.xml
@@ -22,5 +22,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.backup.cts" />
+        <option name="runtime-hint" value="8m20s" />
     </test>
 </configuration>
diff --git a/tests/backup/app/Android.mk b/tests/backup/app/Android.mk
index cffb1d2..8d7e3e9 100644
--- a/tests/backup/app/Android.mk
+++ b/tests/backup/app/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_COMPATIBILITY_SUITE := cts
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index 48550f6..200574e 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -23,9 +23,9 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil \
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util \
 	ctstestrunner \
-	mockito-target \
+	mockito-target-minus-junit4 \
 	android-ex-camera2
 
 LOCAL_JNI_SHARED_LIBRARIES := \
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/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
index 5fbc682..de48dd6 100644
--- a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -32,7 +32,6 @@
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Arrays;
 
 public class BurstCaptureTest extends Camera2SurfaceViewTestCase {
     private static final String TAG = "BurstCaptureTest";
@@ -99,31 +98,8 @@
         final long minStillFrameDuration =
                 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, stillSize);
 
-        // Add 0.05 here so Fps like 29.99 evaluated to 30
-        int minBurstFps = (int) Math.floor(1e9 / minStillFrameDuration + 0.05f);
-        boolean foundConstantMaxYUVRange = false;
-        boolean foundYUVStreamingRange = false;
 
-        // Find suitable target FPS range - as high as possible that covers the max YUV rate
-        // Also verify that there's a good preview rate as well
-        List<Range<Integer> > fpsRanges = Arrays.asList(
-                mStaticInfo.getAeAvailableTargetFpsRangesChecked());
-        Range<Integer> targetRange = null;
-        for (Range<Integer> fpsRange : fpsRanges) {
-            if (fpsRange.getLower() == minBurstFps && fpsRange.getUpper() == minBurstFps) {
-                foundConstantMaxYUVRange = true;
-                targetRange = fpsRange;
-            }
-            if (fpsRange.getLower() <= 15 && fpsRange.getUpper() == minBurstFps) {
-                foundYUVStreamingRange = true;
-            }
-        }
-
-        assertTrue(String.format("Cam %s: Target FPS range of (%d, %d) must be supported",
-                cameraId, minBurstFps, minBurstFps), foundConstantMaxYUVRange);
-        assertTrue(String.format(
-                "Cam %s: Target FPS range of (x, %d) where x <= 15 must be supported",
-                cameraId, minBurstFps), foundYUVStreamingRange);
+        Range<Integer> targetRange = getSuitableFpsRangeForDuration(cameraId, minStillFrameDuration);
 
         Log.i(TAG, String.format("Selected frame rate range %d - %d for YUV burst",
                         targetRange.getLower(), targetRange.getUpper()));
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
index afac9a2..05efd6d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -228,16 +228,27 @@
      */
     public static class ImageDropperListener implements ImageReader.OnImageAvailableListener {
         @Override
-        public void onImageAvailable(ImageReader reader) {
+        public synchronized void onImageAvailable(ImageReader reader) {
             Image image = null;
             try {
                 image = reader.acquireNextImage();
             } finally {
                 if (image != null) {
                     image.close();
+                    mImagesDropped++;
                 }
             }
         }
+
+        public synchronized int getImageCount() {
+            return mImagesDropped;
+        }
+
+        public synchronized void resetImageCount() {
+            mImagesDropped = 0;
+        }
+
+        private int mImagesDropped = 0;
     }
 
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 7e28403..b88a80f 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -22,6 +22,7 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
@@ -32,6 +33,7 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.InputConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
@@ -39,6 +41,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 
@@ -338,6 +341,209 @@
     }
 
     /**
+     * Test multiple capture KPI for YUV_420_888 format: the average time duration
+     * between sending out image capture requests and receiving capture results.
+     * <p>
+     * It measures capture latency, which is the time between sending out the capture
+     * request and getting the full capture result, and the frame duration, which is the timestamp
+     * gap between results.
+     * </p>
+     */
+    public void testMultipleCapture() throws Exception {
+        double[] avgResultTimes = new double[mCameraIds.length];
+        double[] avgDurationMs = new double[mCameraIds.length];
+
+        // A simple CaptureSession StateCallback to handle onCaptureQueueEmpty
+        class MultipleCaptureStateCallback extends CameraCaptureSession.StateCallback {
+            private ConditionVariable captureQueueEmptyCond = new ConditionVariable();
+            private int captureQueueEmptied = 0;
+
+            @Override
+            public void onConfigured(CameraCaptureSession session) {
+                // Empty implementation
+            }
+
+            @Override
+            public void onConfigureFailed(CameraCaptureSession session) {
+                // Empty implementation
+            }
+
+            @Override
+            public void onCaptureQueueEmpty(CameraCaptureSession session) {
+                captureQueueEmptied++;
+                if (VERBOSE) {
+                    Log.v(TAG, "onCaptureQueueEmpty received. captureQueueEmptied = "
+                        + captureQueueEmptied);
+                }
+
+                captureQueueEmptyCond.open();
+            }
+
+            /* Wait for onCaptureQueueEmpty, return immediately if an onCaptureQueueEmpty was
+             * already received, otherwise, wait for one to arrive. */
+            public void waitForCaptureQueueEmpty(long timeout) {
+                if (captureQueueEmptied > 0) {
+                    captureQueueEmptied--;
+                    return;
+                }
+
+                if (captureQueueEmptyCond.block(timeout)) {
+                    captureQueueEmptyCond.close();
+                    captureQueueEmptied = 0;
+                } else {
+                    throw new TimeoutRuntimeException("Unable to receive onCaptureQueueEmpty after "
+                        + timeout + "ms");
+                }
+            }
+        }
+
+        final MultipleCaptureStateCallback sessionListener = new MultipleCaptureStateCallback();
+
+        int counter = 0;
+        for (String id : mCameraIds) {
+            // Do NOT move these variables to outer scope
+            // They will be passed to DeviceReportLog and their references will be stored
+            String streamName = "test_multiple_capture";
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
+            long[] startTimes = new long[NUM_MAX_IMAGES];
+            double[] getResultTimes = new double[NUM_MAX_IMAGES];
+            double[] frameDurationMs = new double[NUM_MAX_IMAGES-1];
+            try {
+                openDevice(id);
+
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
+
+                for (int i = 0; i < NUM_TEST_LOOPS; i++) {
+
+                    // setup builders and listeners
+                    CaptureRequest.Builder previewBuilder =
+                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+                    CaptureRequest.Builder captureBuilder =
+                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+                    SimpleCaptureCallback previewResultListener =
+                            new SimpleCaptureCallback();
+                    SimpleTimingResultListener captureResultListener =
+                            new SimpleTimingResultListener();
+                    SimpleImageReaderListener imageListener =
+                            new SimpleImageReaderListener(/*asyncMode*/true, NUM_MAX_IMAGES);
+
+                    Size maxYuvSize = CameraTestUtils.getSortedSizesForFormat(
+                        id, mCameraManager, ImageFormat.YUV_420_888, /*bound*/null).get(0);
+                    // Find minimum frame duration for YUV_420_888
+                    StreamConfigurationMap config = mStaticInfo.getCharacteristics().get(
+                            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+                    final long minStillFrameDuration =
+                            config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
+                    Range<Integer> targetRange = getSuitableFpsRangeForDuration(id,
+                            minStillFrameDuration);
+                    previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                            targetRange);
+                    captureBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                            targetRange);
+
+                    prepareCaptureAndStartPreview(previewBuilder, captureBuilder,
+                            mOrderedPreviewSizes.get(0), maxYuvSize,
+                            ImageFormat.YUV_420_888, previewResultListener,
+                            sessionListener, NUM_MAX_IMAGES, imageListener);
+
+                    // Converge AE
+                    waitForAeStable(previewResultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+
+                    if (mStaticInfo.isAeLockSupported()) {
+                        // Lock AE if possible to improve stability
+                        previewBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
+                        mSession.setRepeatingRequest(previewBuilder.build(), previewResultListener,
+                                mHandler);
+                        if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
+                            // Legacy mode doesn't output AE state
+                            waitForResultValue(previewResultListener, CaptureResult.CONTROL_AE_STATE,
+                                    CaptureResult.CONTROL_AE_STATE_LOCKED, NUM_RESULTS_WAIT_TIMEOUT);
+                        }
+                    }
+
+                    // Capture NUM_MAX_IMAGES images based on onCaptureQueueEmpty callback
+                    for (int j = 0; j < NUM_MAX_IMAGES; j++) {
+
+                        // Capture an image and get image data
+                        startTimes[j] = SystemClock.elapsedRealtime();
+                        CaptureRequest request = captureBuilder.build();
+                        mSession.capture(request, captureResultListener, mHandler);
+
+                        // Wait for capture queue empty for the current request
+                        sessionListener.waitForCaptureQueueEmpty(
+                                CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                    }
+
+                    // Acquire the capture result time and frame duration
+                    long prevTimestamp = -1;
+                    for (int j = 0; j < NUM_MAX_IMAGES; j++) {
+                        Pair<CaptureResult, Long> captureResultNTime =
+                                captureResultListener.getCaptureResultNTime(
+                                        CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
+
+                        getResultTimes[j] +=
+                                (double)(captureResultNTime.second - startTimes[j])/NUM_TEST_LOOPS;
+
+                        // Collect inter-frame timestamp
+                        long timestamp = captureResultNTime.first.get(CaptureResult.SENSOR_TIMESTAMP);
+                        if (prevTimestamp != -1) {
+                            frameDurationMs[j-1] +=
+                                    (double)(timestamp - prevTimestamp)/(NUM_TEST_LOOPS * 1000000.0);
+                        }
+                        prevTimestamp = timestamp;
+                    }
+
+                    // simulate real scenario (preview runs a bit)
+                    waitForNumResults(previewResultListener, NUM_RESULTS_WAIT);
+
+                    stopPreview();
+                }
+
+                for (int i = 0; i < getResultTimes.length; i++) {
+                    Log.v(TAG, "Camera " + id + " result time[" + i + "] is " +
+                            getResultTimes[i] + " ms");
+                }
+                for (int i = 0; i < NUM_MAX_IMAGES-1; i++) {
+                    Log.v(TAG, "Camera " + id + " frame duration time[" + i + "] is " +
+                            frameDurationMs[i] + " ms");
+                }
+
+                mReportLog.addValues("camera_multiple_capture_result_latency", getResultTimes,
+                        ResultType.LOWER_BETTER, ResultUnit.MS);
+                mReportLog.addValues("camera_multiple_capture_frame_duration", frameDurationMs,
+                        ResultType.LOWER_BETTER, ResultUnit.MS);
+
+
+                avgResultTimes[counter] = Stat.getAverage(getResultTimes);
+                avgDurationMs[counter] = Stat.getAverage(frameDurationMs);
+            }
+            finally {
+                closeImageReader();
+                closeDevice();
+            }
+            counter++;
+            mReportLog.submit(getInstrumentation());
+        }
+
+        // Result will not be reported in CTS report if no summary is printed.
+        if (mCameraIds.length != 0) {
+            String streamName = "test_multiple_capture_average";
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.setSummary("camera_multiple_capture_result_average_latency_for_all_cameras",
+                    Stat.getAverage(avgResultTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+            mReportLog.submit(getInstrumentation());
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.setSummary("camera_multiple_capture_frame_duration_average_for_all_cameras",
+                    Stat.getAverage(avgDurationMs), ResultType.LOWER_BETTER, ResultUnit.MS);
+            mReportLog.submit(getInstrumentation());
+        }
+    }
+
+    /**
      * Test reprocessing shot-to-shot latency with default NR and edge options, i.e., from the time
      * a reprocess request is issued to the time the reprocess image is returned.
      */
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index d466662..9302049 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -14,7 +14,6 @@
 import static android.hardware.camera2.cts.CameraTestUtils.*;
 import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
 
-import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraCaptureSession;
@@ -43,6 +42,7 @@
 import android.util.Range;
 import android.view.Surface;
 
+import com.android.compatibility.common.util.MediaUtils;
 import com.android.ex.camera2.blocking.BlockingSessionCallback;
 
 import junit.framework.AssertionFailedError;
diff --git a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index 2a49857..6663201 100644
--- a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -38,6 +38,8 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
@@ -418,6 +420,213 @@
         waitForNumResults(resultListener, SOME_FRAMES);
     }
 
+    /*
+     * Verify creation of deferred surface capture sessions
+     */
+    public void testDeferredSurfaces() throws Exception {
+        for (int i = 0; i < mCameraIds.length; i++) {
+            try {
+                openDevice(mCameraIds[i]);
+                if (mStaticInfo.isHardwareLevelLegacy()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] + " is legacy, skipping");
+                    continue;
+                }
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
+
+                testDeferredSurfacesByCamera(mCameraIds[i]);
+            }
+            finally {
+                closeDevice();
+            }
+        }
+    }
+
+    private void testDeferredSurfacesByCamera(String cameraId) throws Exception {
+        Size maxPreviewSize = m1080pBoundedOrderedPreviewSizes.get(0);
+
+        SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+
+        // Create a SurfaceTexture for a second output
+        SurfaceTexture sharedOutputTexture = new SurfaceTexture(/*random texture ID*/ 5);
+        sharedOutputTexture.setDefaultBufferSize(maxPreviewSize.getWidth(),
+                maxPreviewSize.getHeight());
+        Surface sharedOutputSurface1 = new Surface(sharedOutputTexture);
+
+        class TextureAvailableListener implements SurfaceTexture.OnFrameAvailableListener {
+            @Override
+            public void onFrameAvailable(SurfaceTexture t) {
+                mGotFrame = true;
+            }
+            public boolean gotFrame() { return mGotFrame; }
+
+            private volatile boolean mGotFrame = false;
+        }
+        TextureAvailableListener textureAvailableListener = new TextureAvailableListener();
+
+        sharedOutputTexture.setOnFrameAvailableListener(textureAvailableListener, mHandler);
+
+        updatePreviewSurface(maxPreviewSize);
+
+        // Create deferred outputs for surface view and surface texture
+        OutputConfiguration surfaceViewOutput = new OutputConfiguration(maxPreviewSize,
+                SurfaceHolder.class);
+        OutputConfiguration surfaceTextureOutput = new OutputConfiguration(maxPreviewSize,
+                SurfaceTexture.class);
+
+        List<OutputConfiguration> outputSurfaces = new ArrayList<>();
+        outputSurfaces.add(surfaceViewOutput);
+        outputSurfaces.add(surfaceTextureOutput);
+
+        // Create non-deferred ImageReader output (JPEG for LIMITED-level compatibility)
+        ImageDropperListener imageListener = new ImageDropperListener();
+        createImageReader(mOrderedStillSizes.get(0), ImageFormat.JPEG, /*maxImages*/ 3,
+                imageListener);
+        OutputConfiguration jpegOutput =
+                new OutputConfiguration(OutputConfiguration.SURFACE_GROUP_ID_NONE, mReaderSurface);
+        outputSurfaces.add(jpegOutput);
+
+        // Confirm that other surface types aren't supported for OutputConfiguration
+        Class[] unsupportedClasses =
+                {android.media.ImageReader.class, android.media.MediaCodec.class,
+                 android.renderscript.Allocation.class, android.media.MediaRecorder.class};
+
+        for (Class klass : unsupportedClasses) {
+            try {
+                OutputConfiguration bad = new OutputConfiguration(maxPreviewSize, klass);
+                fail("OutputConfiguration allowed use of unsupported class " + klass);
+            } catch (IllegalArgumentException e) {
+                // expected
+            }
+        }
+
+        // Create session
+
+        BlockingSessionCallback sessionListener =
+                new BlockingSessionCallback();
+
+        mSession = configureCameraSessionWithConfig(mCamera, outputSurfaces, sessionListener,
+                mHandler);
+        sessionListener.getStateWaiter().waitForState(BlockingSessionCallback.SESSION_READY,
+                SESSION_CONFIGURE_TIMEOUT_MS);
+
+        // Submit JPEG requests
+
+        CaptureRequest.Builder request = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        request.addTarget(mReaderSurface);
+
+        final int SOME_FRAMES = 10;
+        for (int i = 0; i < SOME_FRAMES; i++) {
+            mSession.capture(request.build(), resultListener, mHandler);
+        }
+
+        // Wait to get some frames out to ensure we can operate just the one expected surface
+        waitForNumResults(resultListener, SOME_FRAMES);
+        assertTrue("No images received", imageListener.getImageCount() > 0);
+
+        // Ensure we can't use the deferred surfaces yet
+        request.addTarget(sharedOutputSurface1);
+        try {
+            mSession.capture(request.build(), resultListener, mHandler);
+            fail("Should have received IAE for trying to use a deferred target " +
+                    "that's not yet configured");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        // Add deferred surfaces to their configurations
+        surfaceViewOutput.setDeferredSurface(mPreviewSurface);
+        surfaceTextureOutput.setDeferredSurface(sharedOutputSurface1);
+
+        // Verify bad inputs to setDeferredSurface
+        try {
+            surfaceViewOutput.setDeferredSurface(null);
+            fail("No error from setting a null deferred surface");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            surfaceViewOutput.setDeferredSurface(mPreviewSurface);
+            fail("Shouldn't be able to set deferred surface twice");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+
+        // Add first deferred surface to session
+        List<OutputConfiguration> deferredSurfaces = new ArrayList<>();
+        deferredSurfaces.add(surfaceTextureOutput);
+
+        mSession.finishDeferredConfiguration(deferredSurfaces);
+
+        // Try a second time, this should error
+
+        try {
+            mSession.finishDeferredConfiguration(deferredSurfaces);
+            fail("Should have received ISE for trying to finish a deferred output twice");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        // Use new deferred surface for a bit
+        imageListener.resetImageCount();
+        for (int i = 0; i < SOME_FRAMES; i++) {
+            mSession.capture(request.build(), resultListener, mHandler);
+        }
+        waitForNumResults(resultListener, SOME_FRAMES);
+        assertTrue("No images received", imageListener.getImageCount() > 0);
+        assertTrue("No texture update received", textureAvailableListener.gotFrame());
+
+        // Ensure we can't use the last deferred surface yet
+        request.addTarget(mPreviewSurface);
+        try {
+            mSession.capture(request.build(), resultListener, mHandler);
+            fail("Should have received IAE for trying to use a deferred target that's" +
+                    " not yet configured");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        // Add final deferred surface
+        deferredSurfaces.clear();
+        deferredSurfaces.add(surfaceViewOutput);
+
+        mSession.finishDeferredConfiguration(deferredSurfaces);
+
+        // Use final deferred surface for a bit
+        imageListener.resetImageCount();
+        for (int i = 0; i < SOME_FRAMES; i++) {
+            mSession.capture(request.build(), resultListener, mHandler);
+        }
+        waitForNumResults(resultListener, SOME_FRAMES);
+        assertTrue("No images received", imageListener.getImageCount() > 0);
+        // Can't check GL output since we don't have a context to call updateTexImage on, and
+        // the callback only fires once per updateTexImage call.
+        // And there's no way to verify data is going to a SurfaceView
+
+        // Check for invalid output configurations being handed to a session
+        OutputConfiguration badConfig =
+                new OutputConfiguration(maxPreviewSize, SurfaceTexture.class);
+        deferredSurfaces.clear();
+        try {
+            mSession.finishDeferredConfiguration(deferredSurfaces);
+            fail("No error for empty list passed to finishDeferredConfiguration");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        deferredSurfaces.add(badConfig);
+        try {
+            mSession.finishDeferredConfiguration(deferredSurfaces);
+            fail("No error for invalid output config being passed to finishDeferredConfiguration");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+    }
+
     /**
      * Measure the inter-frame interval based on SENSOR_TIMESTAMP for frameCount frames from the
      * provided capture listener.  If prevTimestamp is positive, it is used for the first interval
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index a95f4f3..feb0bc7 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -55,6 +55,7 @@
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -696,6 +697,27 @@
             CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format,
             CaptureCallback resultListener, int maxNumImages,
             ImageReader.OnImageAvailableListener imageListener) throws Exception {
+        prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, captureSz,
+            format, resultListener, null, maxNumImages, imageListener);
+    }
+
+    /**
+     * Setup single capture configuration and start preview.
+     *
+     * @param previewRequest The capture request to be used for preview
+     * @param stillRequest The capture request to be used for still capture
+     * @param previewSz Preview size
+     * @param captureSz Still capture size
+     * @param format The single capture image format
+     * @param resultListener Capture result listener
+     * @param sessionListener Session listener
+     * @param maxNumImages The max number of images set to the image reader
+     * @param imageListener The single capture capture image listener
+     */
+    protected void prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
+            CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format,
+            CaptureCallback resultListener, CameraCaptureSession.StateCallback sessionListener,
+            int maxNumImages, ImageReader.OnImageAvailableListener imageListener) throws Exception {
         if (VERBOSE) {
             Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)",
                     captureSz.toString(), previewSz.toString()));
@@ -711,7 +733,11 @@
         List<Surface> outputSurfaces = new ArrayList<Surface>();
         outputSurfaces.add(mPreviewSurface);
         outputSurfaces.add(mReaderSurface);
-        mSessionListener = new BlockingSessionCallback();
+        if (sessionListener == null) {
+            mSessionListener = new BlockingSessionCallback();
+        } else {
+            mSessionListener = new BlockingSessionCallback(sessionListener);
+        }
         mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
 
         // Configure the requests.
@@ -791,4 +817,33 @@
         }
         return info.isCapabilitySupported(cap);
     }
+
+    protected Range<Integer> getSuitableFpsRangeForDuration(String cameraId, long frameDuration) {
+        // Add 0.05 here so Fps like 29.99 evaluated to 30
+        int minBurstFps = (int) Math.floor(1e9 / frameDuration + 0.05f);
+        boolean foundConstantMaxYUVRange = false;
+        boolean foundYUVStreamingRange = false;
+
+        // Find suitable target FPS range - as high as possible that covers the max YUV rate
+        // Also verify that there's a good preview rate as well
+        List<Range<Integer> > fpsRanges = Arrays.asList(
+                mStaticInfo.getAeAvailableTargetFpsRangesChecked());
+        Range<Integer> targetRange = null;
+        for (Range<Integer> fpsRange : fpsRanges) {
+            if (fpsRange.getLower() == minBurstFps && fpsRange.getUpper() == minBurstFps) {
+                foundConstantMaxYUVRange = true;
+                targetRange = fpsRange;
+            }
+            if (fpsRange.getLower() <= 15 && fpsRange.getUpper() == minBurstFps) {
+                foundYUVStreamingRange = true;
+            }
+        }
+
+        assertTrue(String.format("Cam %s: Target FPS range of (%d, %d) must be supported",
+                cameraId, minBurstFps, minBurstFps), foundConstantMaxYUVRange);
+        assertTrue(String.format(
+                "Cam %s: Target FPS range of (x, %d) where x <= 15 must be supported",
+                cameraId, minBurstFps), foundYUVStreamingRange);
+        return targetRange;
+    }
 }
diff --git a/tests/camera/src/android/hardware/cts/Camera_SizeTest.java b/tests/camera/src/android/hardware/cts/Camera_SizeTest.java
index 2f9c94b..77e75dd 100644
--- a/tests/camera/src/android/hardware/cts/Camera_SizeTest.java
+++ b/tests/camera/src/android/hardware/cts/Camera_SizeTest.java
@@ -16,14 +16,14 @@
 
 package android.hardware.cts;
 
-
-import android.cts.util.CtsAndroidTestCase;
 import android.hardware.Camera;
 import android.hardware.Camera.Parameters;
 import android.hardware.cts.helpers.CameraUtils;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
diff --git a/tests/dram/Android.mk b/tests/dram/Android.mk
index 8997003..e286e8d 100644
--- a/tests/dram/Android.mk
+++ b/tests/dram/Android.mk
@@ -21,7 +21,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsdram_jni
 
diff --git a/tests/dram/AndroidTest.xml b/tests/dram/AndroidTest.xml
index 019c15d..b3a5051 100644
--- a/tests/dram/AndroidTest.xml
+++ b/tests/dram/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.dram.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/dram/src/android/dram/cts/BandwidthTest.java b/tests/dram/src/android/dram/cts/BandwidthTest.java
index fe7e248..8b54d90 100644
--- a/tests/dram/src/android/dram/cts/BandwidthTest.java
+++ b/tests/dram/src/android/dram/cts/BandwidthTest.java
@@ -17,11 +17,11 @@
 package android.dram.cts;
 
 import android.content.Context;
-import android.cts.util.CtsAndroidTestCase;
 import android.graphics.Point;
 import android.util.Log;
 import android.view.WindowManager;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index a6d31b0..3083126 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -244,19 +244,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/filesystem/Android.mk b/tests/filesystem/Android.mk
index bf88148..417d7c4 100644
--- a/tests/filesystem/Android.mk
+++ b/tests/filesystem/Android.mk
@@ -18,7 +18,7 @@
 # don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/filesystem/AndroidTest.xml b/tests/filesystem/AndroidTest.xml
index 2b4a356..40212a2 100644
--- a/tests/filesystem/AndroidTest.xml
+++ b/tests/filesystem/AndroidTest.xml
@@ -20,7 +20,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.filesystem.cts" />
-        <option name="runtime-hint" value="22m48s" />
+        <option name="runtime-hint" value="14m48s" />
         <!-- test-timeout unit is ms, value = 60 min -->
         <option name="test-timeout" value="3600000" />
     </test>
diff --git a/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java b/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java
index 11b150e..3ae2408 100644
--- a/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/AlmostFullTest.java
@@ -18,10 +18,10 @@
 
 import android.util.Log;
 
-import android.cts.util.CtsAndroidTestCase;
-import android.cts.util.SystemUtil;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 
 import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.SystemUtil;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
diff --git a/tests/filesystem/src/android/filesystem/cts/FileUtil.java b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
index 8149105..4cf07ac 100755
--- a/tests/filesystem/src/android/filesystem/cts/FileUtil.java
+++ b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
@@ -17,7 +17,6 @@
 package android.filesystem.cts;
 
 import android.content.Context;
-import android.cts.util.SystemUtil;
 import android.util.Log;
 
 import com.android.compatibility.common.util.DeviceReportLog;
@@ -27,6 +26,7 @@
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
+import com.android.compatibility.common.util.SystemUtil;
 
 import java.io.BufferedReader;
 import java.io.File;
diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
index 7b97f8f..f9abebb 100644
--- a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
@@ -16,9 +16,10 @@
 
 package android.filesystem.cts;
 
-import android.cts.util.CtsAndroidTestCase;
 import android.os.Environment;
+
 import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 
 public class RandomRWTest extends CtsAndroidTestCase {
diff --git a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
index 2db2f24..aabc825 100644
--- a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
@@ -16,7 +16,7 @@
 
 package android.filesystem.cts;
 
-import android.cts.util.CtsAndroidTestCase;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.MeasureRun;
diff --git a/tests/fragment/Android.mk b/tests/fragment/Android.mk
index 2352564..053e668 100644
--- a/tests/fragment/Android.mk
+++ b/tests/fragment/Android.mk
@@ -28,7 +28,14 @@
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target-minus-junit4 \
+    android-common \
+    compatibility-device-util \
+    ctstestrunner \
+    platform-test-annotations
+#LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/fragment/AndroidTest.xml b/tests/fragment/AndroidTest.xml
index f3e302a..2a9faae 100644
--- a/tests/fragment/AndroidTest.xml
+++ b/tests/fragment/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.fragment.cts" />
+        <option name="runtime-hint" value="13m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/fragment/res/animator/slow_fade_out.xml b/tests/fragment/res/animator/slow_fade_out.xml
new file mode 100644
index 0000000..d8d2ad2
--- /dev/null
+++ b/tests/fragment/res/animator/slow_fade_out.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.
+-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+                android:duration="5000"
+                android:propertyName="alpha"
+                android:valueFrom="1.0"
+                android:valueTo="0.0"/>
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/nested_inflated_fragment_child.xml b/tests/fragment/res/layout/nested_inflated_fragment_child.xml
new file mode 100644
index 0000000..9a11bc4
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_child.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test" />
+</LinearLayout>
diff --git a/tests/fragment/res/layout/nested_inflated_fragment_parent.xml b/tests/fragment/res/layout/nested_inflated_fragment_parent.xml
new file mode 100644
index 0000000..026ba45
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_parent.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <fragment android:name="android.fragment.cts.NestedInflatedFragmentTest$InflatedChildFragment"
+              android:id="@+id/child_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/fragment/res/layout/scene1.xml b/tests/fragment/res/layout/scene1.xml
new file mode 100644
index 0000000..d0509c3
--- /dev/null
+++ b/tests/fragment/res/layout/scene1.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:id="@+id/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+    <View android:id="@+id/blueSquare"
+          android:transitionName="blueSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/scene2.xml b/tests/fragment/res/layout/scene2.xml
new file mode 100644
index 0000000..ef809a4
--- /dev/null
+++ b/tests/fragment/res/layout/scene2.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:id="@+id/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/blueSquare"
+          android:transitionName="blueSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/scene3.xml b/tests/fragment/res/layout/scene3.xml
new file mode 100644
index 0000000..15519fd
--- /dev/null
+++ b/tests/fragment/res/layout/scene3.xml
@@ -0,0 +1,35 @@
+<?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/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/redSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#800"/>
+    <View android:id="@+id/blueSquare"
+          android:transitionName="shared"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+</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/res/layout/text_a.xml b/tests/fragment/res/layout/text_a.xml
new file mode 100644
index 0000000..b164469
--- /dev/null
+++ b/tests/fragment/res/layout/text_a.xml
@@ -0,0 +1,19 @@
+<?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="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textA"/>
diff --git a/tests/fragment/res/layout/text_b.xml b/tests/fragment/res/layout/text_b.xml
new file mode 100644
index 0000000..3d307fc
--- /dev/null
+++ b/tests/fragment/res/layout/text_b.xml
@@ -0,0 +1,19 @@
+<?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="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textB"/>
diff --git a/tests/fragment/res/layout/text_c.xml b/tests/fragment/res/layout/text_c.xml
new file mode 100644
index 0000000..e40b5ab
--- /dev/null
+++ b/tests/fragment/res/layout/text_c.xml
@@ -0,0 +1,19 @@
+<?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="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textC"/>
diff --git a/tests/fragment/src/android/fragment/cts/CountCallsFragment.java b/tests/fragment/src/android/fragment/cts/CountCallsFragment.java
new file mode 100644
index 0000000..a262772
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/CountCallsFragment.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 android.fragment.cts;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Counts the number of onCreateView, onHiddenChanged (onHide, onShow), onAttach, and onDetach
+ * calls.
+ */
+public class CountCallsFragment extends StrictViewFragment {
+    public int onCreateViewCount = 0;
+    public int onDestroyViewCount = 0;
+    public int onHideCount = 0;
+    public int onShowCount = 0;
+    public int onAttachCount = 0;
+    public int onDetachCount = 0;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        onCreateViewCount++;
+        return super.onCreateView(inflater, container, savedInstanceState);
+    }
+
+    @Override
+    public void onHiddenChanged(boolean hidden) {
+        if (hidden) {
+            onHideCount++;
+        } else {
+            onShowCount++;
+        }
+        super.onHiddenChanged(hidden);
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        onAttachCount++;
+        super.onAttach(context);
+    }
+
+    @Override
+    public void onDetach() {
+        onDetachCount++;
+        super.onDetach();
+    }
+
+    @Override
+    public void onDestroyView() {
+        onDestroyViewCount++;
+        super.onDestroyView();
+    }
+}
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..f0dac9a
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -0,0 +1,487 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+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.FragmentController;
+import android.app.FragmentManager;
+import android.app.FragmentManagerNonConfig;
+import android.app.Instrumentation;
+import android.os.Debug;
+import android.os.Parcelable;
+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.util.Pair;
+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.waitForExecution(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.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(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.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .show(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(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.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .hide(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(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.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .attach(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(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.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .detach(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(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.waitForExecution(mActivityRule);
+
+        final AnimatorFragment fragment3 = new AnimatorFragment();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertFragmentAnimation(fragment1, 1, false, EXIT);
+        assertFragmentAnimation(fragment2, 1, false, EXIT);
+        assertFragmentAnimation(fragment3, 1, true, ENTER);
+
+        fm.popBackStack();
+        FragmentTestUtil.waitForExecution(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);
+    }
+
+    // Ensure that adding and popping a Fragment uses the enter and popExit animators,
+    // but the animators are delayed when an entering Fragment is postponed.
+    @Test
+    public void postponedAddAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fragment.postponeEnterTransition();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment, 0);
+        fragment.startPostponedEnterTransition();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertEnterPopExit(fragment);
+    }
+
+    // Ensure that removing and popping a Fragment uses the exit and popEnter animators,
+    // but the animators are delayed when an entering Fragment is postponed.
+    @Test
+    public void postponedRemoveAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertExitPostponedPopEnter(fragment);
+    }
+
+    // Ensure that adding and popping a Fragment is postponed in both directions
+    // when the fragments have been marked for postponing.
+    @Test
+    public void postponedAddRemove() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment1 = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final AnimatorFragment fragment2 = new AnimatorFragment();
+        fragment2.postponeEnterTransition();
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment2, 0);
+        assertNotNull(fragment1.getView());
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertTrue(fragment1.getView().isAttachedToWindow());
+
+        fragment2.startPostponedEnterTransition();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertExitPostponedPopEnter(fragment1);
+    }
+
+    // Popping a postponed transaction should result in no animators
+    @Test
+    public void popPostponed() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment1 = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertEquals(0, fragment1.numAnimators);
+
+        final AnimatorFragment fragment2 = new AnimatorFragment();
+        fragment2.postponeEnterTransition();
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment2, 0);
+
+        // Now pop the postponed transaction
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertNotNull(fragment1.getView());
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertTrue(fragment1.getView().isAttachedToWindow());
+        assertTrue(fragment1.isAdded());
+
+        assertNull(fragment2.getView());
+        assertFalse(fragment2.isAdded());
+
+        assertEquals(0, fragment1.numAnimators);
+        assertEquals(0, fragment2.numAnimators);
+        assertNull(fragment1.animator);
+        assertNull(fragment2.animator);
+    }
+
+    // Make sure that if the state was saved while a Fragment was animating that its
+    // state is proper after restoring.
+    @Test
+    public void saveWhileAnimatingAway() throws Throwable {
+        final FragmentController fc1 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc1, null);
+
+        final FragmentManager fm1 = fc1.getFragmentManager();
+
+        StrictViewFragment fragment1 = new StrictViewFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        fm1.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        StrictViewFragment fragment2 = new StrictViewFragment();
+
+        fm1.beginTransaction()
+                .setCustomAnimations(0, 0, 0, R.animator.slow_fade_out)
+                .replace(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack(null)
+                .commit();
+        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm1.popBackStack();
+
+        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        // Now fragment2 should be animating away
+        assertFalse(fragment2.isAdded());
+        assertEquals(fragment2, fm1.findFragmentByTag("2")); // still exists because it is animating
+
+        Pair<Parcelable, FragmentManagerNonConfig> state =
+                FragmentTestUtil.destroy(mActivityRule, fc1);
+
+        final FragmentController fc2 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc2, state);
+
+        final FragmentManager fm2 = fc2.getFragmentManager();
+        Fragment fragment2restored = fm2.findFragmentByTag("2");
+        assertNull(fragment2restored);
+
+        Fragment fragment1restored = fm2.findFragmentByTag("1");
+        assertNotNull(fragment1restored);
+        assertNotNull(fragment1restored.getView());
+    }
+
+    private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, true, ENTER);
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.popBackStack();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertFragmentAnimation(fragment, 2, false, POP_EXIT);
+    }
+
+    private void assertExitPopEnter(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, false, EXIT);
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.popBackStack();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        AnimatorFragment replacement = (AnimatorFragment) fm.findFragmentByTag("1");
+
+        boolean isSameFragment = replacement == fragment;
+        int expectedAnimators = isSameFragment ? 2 : 1;
+        assertFragmentAnimation(replacement, expectedAnimators, true, POP_ENTER);
+    }
+
+    private void assertExitPostponedPopEnter(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, false, EXIT);
+
+        fragment.postponeEnterTransition();
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponed(fragment, 1);
+
+        fragment.startPostponedEnterTransition();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertFragmentAnimation(fragment, 2, 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(200, TimeUnit.MILLISECONDS));
+    }
+
+    private void assertPostponed(AnimatorFragment fragment, int expectedAnimators)
+            throws InterruptedException {
+        assertTrue(fragment.mOnCreateViewCalled);
+        assertEquals(View.INVISIBLE, fragment.getView().getVisibility());
+        assertEquals(expectedAnimators, fragment.numAnimators);
+    }
+
+    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/FragmentExecuteTests.java b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
new file mode 100644
index 0000000..7d65b8c
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
@@ -0,0 +1,274 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+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.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentExecuteTests {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setupContentView() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+    }
+
+    // Test that when executePendingBindings is called after something has been
+    // committed that it returns true and that the transaction was executed.
+    @Test
+    public void executeAndPopNormal() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment, "1")
+                        .addToBackStack(null)
+                        .commit();
+                assertTrue(fm.executePendingTransactions());
+            }
+        });
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment, fm.findFragmentByTag("1"));
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertNull(fm.findFragmentById(R.id.fragmentContainer));
+        assertNull(fm.findFragmentByTag("1"));
+    }
+
+    // Test that when executePendingBindings is called when nothing has been
+    // committed that it returns false and that the fragment manager is unchanged.
+    @Test
+    public void executeAndPopNothing() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertFalse(FragmentTestUtil.executePendingTransactions(mActivityRule));
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+        assertEquals(0, fm.getBackStackEntryCount());
+    }
+
+    // Test that when popBackStackImmediate is called when something is in the queue and
+    // there is a back stack to pop, it will execute both and return true.
+    @Test
+    public void popBackStackImmediateSomething() throws Throwable {
+        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, "1")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertNull(fm.findFragmentById(R.id.fragmentContainer));
+        assertNull(fm.findFragmentByTag("1"));
+    }
+
+    // Test that when popBackStackImmediate is called when something is in the queue and
+    // there is no back stack to pop, it will execute the thing in the queue and
+    // return false.
+    @Test
+    public void popBackStackImmediateNothing() throws Throwable {
+        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, "1")
+                .commit();
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertEquals(fragment, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment, fm.findFragmentByTag("1"));
+    }
+
+    // Test popBackStackImmediate(int, int)
+    @Test
+    public void popBackStackImmediateInt() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+
+        final int commit1 = fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment3, "3")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit1, 0));
+        assertFalse(fragment2.isAdded());
+        assertTrue(fragment2.mCalledOnDestroy || !fragment2.mCalledOnCreate);
+        assertFalse(fragment3.isAdded());
+        assertTrue(fragment3.mCalledOnDestroy || !fragment3.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit1, 0));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        final int commit4 = fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment4, "4")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment5, "5")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit4,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+        assertFalse(fragment4.isAdded());
+        assertTrue(fragment4.mCalledOnDestroy || !fragment4.mCalledOnCreate);
+        assertFalse(fragment5.isAdded());
+        assertTrue(fragment5.mCalledOnDestroy || !fragment5.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit4,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+    }
+
+    // Test popBackStackImmediate(String, int)
+    @Test
+    public void popBackStackImmediateString() throws Throwable {
+        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")
+                .addToBackStack("1")
+                .commit();
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack("2")
+                .commit();
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment3, "3")
+                .addToBackStack("3")
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, "1", 0));
+        assertFalse(fragment2.isAdded());
+        assertTrue(fragment2.mCalledOnDestroy || !fragment2.mCalledOnCreate);
+        assertFalse(fragment3.isAdded());
+        assertTrue(fragment3.mCalledOnDestroy || !fragment3.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, "1", 0));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment4, "4")
+                .addToBackStack("4")
+                .commit();
+
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment5, "5")
+                .addToBackStack("5")
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, "4",
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+        assertFalse(fragment4.isAdded());
+        assertTrue(fragment4.mCalledOnDestroy || !fragment4.mCalledOnCreate);
+        assertFalse(fragment5.isAdded());
+        assertTrue(fragment5.mCalledOnDestroy || !fragment5.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, "4",
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+    }
+
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index 01c4e70..0d71a34 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -17,18 +17,47 @@
 
 package android.fragment.cts;
 
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotSame;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertSame;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
 import android.app.FragmentManager;
+import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.app.FragmentManagerNonConfig;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Pair;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.TextView;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.*;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class FragmentLifecycleTest {
 
@@ -37,7 +66,6 @@
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
     @Test
-    @MediumTest
     public void basicLifecycle() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment strictFragment = new StrictFragment();
@@ -65,7 +93,6 @@
     }
 
     @Test
-    @MediumTest
     public void detachment() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -105,7 +132,6 @@
     }
 
     @Test
-    @MediumTest
     public void basicBackStack() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -136,7 +162,6 @@
     }
 
     @Test
-    @MediumTest
     public void attachBackStack() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -158,7 +183,6 @@
     }
 
     @Test
-    @MediumTest
     public void viewLifecycle() throws Throwable {
         // Test basic lifecycle when the fragment creates a view
 
@@ -183,7 +207,6 @@
     }
 
     @Test
-    @MediumTest
     public void viewReplace() throws Throwable {
         // Replace one view with another, then reverse it with the back stack
 
@@ -223,6 +246,201 @@
         assertTrue("fragment 1's view not attached", newView1.isAttachedToWindow());
     }
 
+    @Test
+    public void viewReplaceMultiple() throws Throwable {
+        // Replace several views with one, then reverse it with the back stack
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment f1 = new StrictViewFragment();
+        final StrictViewFragment f2 = new StrictViewFragment();
+        final StrictViewFragment f3 = new StrictViewFragment();
+
+        fm.beginTransaction().add(android.R.id.content, f1).commit();
+        fm.beginTransaction().add(android.R.id.content, f2).commit();
+        executePendingTransactions(fm);
+
+        assertTrue("fragment 1 is not added", f1.isAdded());
+        assertTrue("fragment 2 is not added", f2.isAdded());
+
+        View origView1 = f1.getView();
+        assertNotNull("fragment 1 returned null view", origView1);
+        assertTrue("fragment 1's view not attached", origView1.isAttachedToWindow());
+        assertSame(origView1, ((ViewGroup)origView1.getParent()).getChildAt(0));
+
+        View origView2 = f2.getView();
+        assertNotNull("fragment 2 returned null view", origView2);
+        assertTrue("fragment 2's view not attached", origView2.isAttachedToWindow());
+        assertSame(origView2, ((ViewGroup)origView1.getParent()).getChildAt(1));
+
+        fm.beginTransaction().replace(android.R.id.content, f3).addToBackStack("stack1").commit();
+        executePendingTransactions(fm);
+
+        assertFalse("fragment 1 is added", f1.isAdded());
+        assertFalse("fragment 2 is added", f2.isAdded());
+        assertTrue("fragment 3 is added", f3.isAdded());
+        assertNull("fragment 1 returned non-null view", f1.getView());
+        assertNull("fragment 2 returned non-null view", f2.getView());
+        assertFalse("fragment 1's old view still attached", origView1.isAttachedToWindow());
+        assertFalse("fragment 2's old view still attached", origView2.isAttachedToWindow());
+        View origView3 = f3.getView();
+        assertNotNull("fragment 3 returned null view", origView3);
+        assertTrue("fragment 3's view not attached", origView3.isAttachedToWindow());
+
+        fm.popBackStack();
+        executePendingTransactions(fm);
+
+        assertTrue("fragment 1 is not added", f1.isAdded());
+        assertTrue("fragment 2 is not added", f2.isAdded());
+        assertFalse("fragment 3 is added", f3.isAdded());
+        assertNull("fragment 3 returned non-null view", f3.getView());
+        assertFalse("fragment 3's view still attached", origView3.isAttachedToWindow());
+        View newView1 = f1.getView();
+        View newView2 = f2.getView();
+        assertNotSame("fragment 1 had same view from last attachment", origView1, newView1);
+        assertNotSame("fragment 2 had same view from last attachment", origView2, newView1);
+        assertTrue("fragment 1's view not attached", newView1.isAttachedToWindow());
+        assertTrue("fragment 2's view not attached", newView2.isAttachedToWindow());
+        assertSame(newView1, ((ViewGroup)newView1.getParent()).getChildAt(0));
+        assertSame(newView2, ((ViewGroup)newView1.getParent()).getChildAt(1));
+    }
+
+    /**
+     * This tests that fragments call onDestroy when the activity finishes.
+     */
+    @Test
+    public void fragmentDestroyedOnFinish() throws Throwable {
+        final FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, null);
+        final StrictViewFragment fragmentA = StrictViewFragment.create(R.layout.text_a);
+        final StrictViewFragment fragmentB = StrictViewFragment.create(R.layout.text_b);
+        mActivityRule.runOnUiThread(() -> {
+            FragmentManager fm = fc.getFragmentManager();
+
+            fm.beginTransaction()
+                    .add(android.R.id.content, fragmentA)
+                    .commit();
+            fm.executePendingTransactions();
+            fm.beginTransaction()
+                    .replace(android.R.id.content, fragmentB)
+                    .addToBackStack(null)
+                    .commit();
+            fm.executePendingTransactions();
+        });
+        FragmentTestUtil.destroy(mActivityRule, fc);
+        assertTrue(fragmentB.mCalledOnDestroy);
+        assertTrue(fragmentA.mCalledOnDestroy);
+    }
+
+    /**
+     * This test confirms that as long as a parent fragment has called super.onCreate,
+     * any child fragments added, committed and with transactions executed will be brought
+     * to at least the CREATED state by the time the parent fragment receives onCreateView.
+     * This means the child fragment will have received onAttach/onCreate.
+     */
+    @Test
+    @MediumTest
+    public void childFragmentManagerAttach() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            public void run() {
+                FragmentController fc = FragmentController.createController(
+                        new HostCallbacks(mActivityRule.getActivity()));
+                fc.attachHost(null);
+                fc.dispatchCreate();
+
+                FragmentLifecycleCallbacks mockLc = mock(FragmentLifecycleCallbacks.class);
+                FragmentLifecycleCallbacks mockRecursiveLc = mock(FragmentLifecycleCallbacks.class);
+
+                FragmentManager fm = fc.getFragmentManager();
+                fm.registerFragmentLifecycleCallbacks(mockLc, false);
+                fm.registerFragmentLifecycleCallbacks(mockRecursiveLc, true);
+
+                ChildFragmentManagerFragment fragment = new ChildFragmentManagerFragment();
+                fm.beginTransaction()
+                        .add(android.R.id.content, fragment)
+                        .commitNow();
+
+                verify(mockLc, times(1)).onFragmentCreated(fm, fragment, null);
+
+                fc.dispatchActivityCreated();
+
+                Fragment childFragment = fragment.getChildFragment();
+
+                verify(mockLc, times(1)).onFragmentActivityCreated(fm, fragment, null);
+                verify(mockRecursiveLc, times(1)).onFragmentActivityCreated(fm, fragment, null);
+                verify(mockRecursiveLc, times(1)).onFragmentActivityCreated(fm, childFragment, null);
+
+                fc.dispatchStart();
+
+                verify(mockLc, times(1)).onFragmentStarted(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStarted(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStarted(fm, childFragment);
+
+                fc.dispatchResume();
+
+                verify(mockLc, times(1)).onFragmentResumed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentResumed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentResumed(fm, childFragment);
+
+                // Confirm that the parent fragment received onAttachFragment
+                assertTrue("parent fragment did not receive onAttachFragment",
+                        fragment.mCalledOnAttachFragment);
+
+                fc.dispatchStop();
+
+                verify(mockLc, times(1)).onFragmentStopped(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStopped(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStopped(fm, childFragment);
+
+                fc.dispatchDestroy();
+
+                verify(mockLc, times(1)).onFragmentDestroyed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentDestroyed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentDestroyed(fm, childFragment);
+            }
+        });
+    }
+
+    /**
+     * Test to ensure that when dispatch* is called that the fragment manager
+     * doesn't cause the contained fragment states to change even if no state changes.
+     */
+    @Test
+    public void noPrematureStateChange() throws Throwable {
+        final FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, null);
+
+        mActivityRule.runOnUiThread(() -> {
+            fc.getFragmentManager().beginTransaction()
+                    .add(new StrictFragment(), "1")
+                    .commitNow();
+        });
+
+        Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                FragmentTestUtil.destroy(mActivityRule, fc);
+
+        final FragmentController fragmentController = FragmentTestUtil.createController(mActivityRule);
+
+        mActivityRule.runOnUiThread(() -> {
+            fragmentController.attachHost(null);
+            fragmentController.dispatchCreate();
+            fragmentController.dispatchActivityCreated();
+            fragmentController.noteStateNotSaved();
+            fragmentController.execPendingActions();
+            fragmentController.dispatchStart();
+            fragmentController.reportLoaderStart();
+            fragmentController.dispatchResume();
+            fragmentController.restoreAllState(savedState.first, savedState.second);
+            fragmentController.dispatchResume();
+        });
+
+        FragmentManager fm = fragmentController.getFragmentManager();
+
+        StrictFragment fragment1 = (StrictFragment) fm.findFragmentByTag("1");
+
+        assertNotNull(fragment1);
+        assertFalse(fragment1.mCalledOnResume);
+    }
+
     private void executePendingTransactions(final FragmentManager fm) throws Throwable {
         mActivityRule.runOnUiThread(new Runnable() {
             @Override
@@ -231,4 +449,135 @@
             }
         });
     }
+
+    /**
+     * This tests a deliberately odd use of a child fragment, added in onCreateView instead
+     * of elsewhere. It simulates creating a UI child fragment added to the view hierarchy
+     * created by this fragment.
+     */
+    public static class ChildFragmentManagerFragment extends StrictFragment {
+        private FragmentManager mSavedChildFragmentManager;
+        private ChildFragmentManagerChildFragment mChildFragment;
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            mSavedChildFragmentManager = getChildFragmentManager();
+        }
+
+
+        @Override
+        public View onCreateView(LayoutInflater inflater,  ViewGroup container,
+                 Bundle savedInstanceState) {
+            assertSame("child FragmentManagers not the same instance", mSavedChildFragmentManager,
+                    getChildFragmentManager());
+            ChildFragmentManagerChildFragment child =
+                    (ChildFragmentManagerChildFragment) mSavedChildFragmentManager
+                            .findFragmentByTag("tag");
+            if (child == null) {
+                child = new ChildFragmentManagerChildFragment("foo");
+                mSavedChildFragmentManager.beginTransaction()
+                        .add(child, "tag")
+                        .commitNow();
+                assertEquals("argument strings don't match", "foo", child.getString());
+            }
+            mChildFragment = child;
+            return new TextView(container.getContext());
+        }
+
+
+        public Fragment getChildFragment() {
+            return mChildFragment;
+        }
+    }
+
+    public static class ChildFragmentManagerChildFragment extends StrictFragment {
+        private String mString;
+
+        public ChildFragmentManagerChildFragment() {
+        }
+
+        public ChildFragmentManagerChildFragment(String arg) {
+            final Bundle b = new Bundle();
+            b.putString("string", arg);
+            setArguments(b);
+        }
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            mString = getArguments().getString("string", "NO VALUE");
+        }
+
+        public String getString() {
+            return mString;
+        }
+    }
+
+    static class HostCallbacks extends FragmentHostCallback<Activity> {
+        private final Activity mActivity;
+
+        public HostCallbacks(Activity activity) {
+            super(activity, null, 0);
+            mActivity = activity;
+        }
+
+        @Override
+        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        }
+
+        @Override
+        public boolean onShouldSaveFragmentState(Fragment fragment) {
+            return !mActivity.isFinishing();
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            return mActivity.getLayoutInflater().cloneInContext(mActivity);
+        }
+
+        @Override
+        public Activity onGetHost() {
+            return mActivity;
+        }
+
+        @Override
+        public void onStartActivityFromFragment(
+                Fragment fragment, Intent intent, int requestCode,  Bundle options) {
+            mActivity.startActivityFromFragment(fragment, intent, requestCode, options);
+        }
+
+        @Override
+        public void onRequestPermissionsFromFragment( Fragment fragment,
+                 String[] permissions, int requestCode) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean onHasWindowAnimations() {
+            return mActivity.getWindow() != null;
+        }
+
+        @Override
+        public int onGetWindowAnimations() {
+            final Window w = mActivity.getWindow();
+            return (w == null) ? 0 : w.getAttributes().windowAnimations;
+        }
+
+        @Override
+        public void onAttachFragment(Fragment fragment) {
+            mActivity.onAttachFragment(fragment);
+        }
+
+        @Override
+        public View onFindViewById(int id) {
+            return mActivity.findViewById(id);
+        }
+
+        @Override
+        public boolean onHasView() {
+            final Window w = mActivity.getWindow();
+            return (w != null && w.peekDecorView() != null);
+        }
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
new file mode 100644
index 0000000..253bbcb
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
@@ -0,0 +1,543 @@
+/*
+ * 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 org.junit.Assert.*;
+
+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.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentOptimizationTest {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private ViewGroup mContainer;
+    private FragmentManager mFM;
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setup() {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        mContainer = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        mFM = mActivityRule.getActivity().getFragmentManager();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    // Test that when you add and replace a fragment that only the replace's add
+    // actually creates a View.
+    @Test
+    public void addReplace() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        assertEquals(0, fragment1.onCreateViewCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.popBackStack();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+    }
+
+    // Test that it is possible to merge a transaction that starts with pop and adds
+    // the same view back again.
+    @Test
+    public void startWithPop() throws Throwable {
+        // Start with a single fragment on the back stack
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // Now pop and add
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.popBackStack();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+    // Popping the back stack in the middle of other operations doesn't fool it.
+    @Test
+    public void middlePop() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.popBackStack();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+        assertEquals(0, fragment1.onAttachCount);
+        assertEquals(1, fragment2.onCreateViewCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(1, fragment2.onDetachCount);
+    }
+
+    // ensure that removing a view after adding it is optimized into no
+    // View being created. Hide still gets notified.
+    @Test
+    public void optimizeRemove() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final int[] id = new int[1];
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                id[0] = mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(0, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(0, fragment1.onAttachCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id[0],
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(0, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(0, fragment1.onAttachCount);
+    }
+
+    // Ensure that removing and adding the same view results in no operation
+    @Test
+    public void optimizeAdd() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .remove(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // should be optimized out
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // optimize out going back, too
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+    // detaching, then attaching results in on change. Hide still functions
+    @Test
+    public void optimizeAttach() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, fragment1.onAttachCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // can optimize out the detach/attach
+        assertEquals(0, fragment1.onDestroyViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // optimized out again, but not the show
+        assertEquals(0, fragment1.onDestroyViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(1, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+    }
+
+    // attaching, then detaching shouldn't result in a View being created
+    @Test
+    public void optimizeDetach() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .detach(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        // the add detach is not fully optimized out
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertTrue(fragment1.isDetached());
+        assertEquals(0, fragment1.onCreateViewCount);
+        FragmentTestUtil.assertChildren(mContainer);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer);
+        // can optimize out the attach/detach, and the hide call
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertTrue(fragment1.isHidden());
+        assertEquals(0, fragment1.onShowCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+
+        // we can optimize out the attach/detach on the way back
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertFalse(fragment1.isHidden());
+    }
+
+    // show, then hide should optimize out
+    @Test
+    public void optimizeHide() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .hide(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .show(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .remove(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .hide(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // optimize out hide/show
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // still optimized out
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        // The show/hide can be optimized out and nothing should change.
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        // the detach/attach should not affect the show/hide, so show/hide should cancel each other
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+    }
+
+    // hiding and showing the same view should optimize out
+    @Test
+    public void optimizeShow() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // can optimize out the show/hide
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+    }
+
+    // The View order shouldn't be messed up by optimization -- a view that
+    // is optimized to not remove/add should be in its correct position after
+    // the transaction completes.
+    @Test
+    public void viewOrder() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2, fragment1);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+    }
+
+    // Popping an added transaction results in no operation
+    @Test
+    public void addPopBackStack() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+
+        // Was never instantiated because it was popped before anything could happen
+        assertEquals(0, fragment1.onCreateViewCount);
+    }
+
+    // A non-back-stack transaction doesn't interfere with back stack add/pop
+    // optimization.
+    @Test
+    public void popNonBackStack() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .commit();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        // It should be optimized with the replace, so no View creation
+        assertEquals(0, fragment1.onCreateViewCount);
+    }
+
+    // When optimization is disabled, the transaction prior to the disabled optimization
+    // transaction should all be run prior to running the non-optimized transaction.
+    @Test
+    public void noOptimization() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .setAllowOptimization(false)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        // No optimization, so fragment1 should have created its View
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+}
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..b4407a0
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -0,0 +1,163 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentManagerNonConfig;
+import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Pair;
+import android.view.ViewGroup;
+
+public class FragmentTestUtil {
+    public static void waitForExecution(final ActivityTestRule<FragmentTestActivity> rule) {
+        // Wait for two cycles. When starting a postponed transition, it will post to
+        // the UI thread and then the execution will be added onto the queue after that.
+        // The two-cycle wait makes sure fragments have the opportunity to complete both
+        // before returning.
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {});
+        instrumentation.runOnMainSync(() -> {});
+    }
+
+    public static boolean executePendingTransactions(
+            final ActivityTestRule<FragmentTestActivity> rule) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().executePendingTransactions();
+            }
+        });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate();
+            }
+        });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule,
+            final int id, final int flags) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate(id, flags);
+            }
+        });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule,
+            final String name, final int flags) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate(name, flags);
+            }
+        });
+        return ret[0];
+    }
+
+    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);
+            }
+        });
+    }
+
+    public static 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());
+        }
+    }
+
+    public static FragmentController createController(ActivityTestRule<FragmentTestActivity> rule) {
+        final FragmentController[] controller = new FragmentController[1];
+        final FragmentTestActivity activity = rule.getActivity();
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            HostCallbacks hostCallbacks = new HostCallbacks(activity, null, 0);
+            controller[0] = FragmentController.createController(hostCallbacks);
+        });
+        return controller[0];
+    }
+
+
+    public static void resume(ActivityTestRule<FragmentTestActivity> rule,
+            FragmentController fragmentController,
+            Pair<Parcelable, FragmentManagerNonConfig> savedState) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            fragmentController.attachHost(null);
+            if (savedState != null) {
+                fragmentController.restoreAllState(savedState.first, savedState.second);
+            }
+            fragmentController.dispatchCreate();
+            fragmentController.dispatchActivityCreated();
+            fragmentController.noteStateNotSaved();
+            fragmentController.execPendingActions();
+            fragmentController.dispatchStart();
+            fragmentController.reportLoaderStart();
+            fragmentController.dispatchResume();
+            fragmentController.execPendingActions();
+        });
+    }
+
+    public static Pair<Parcelable, FragmentManagerNonConfig> destroy(
+            ActivityTestRule<FragmentTestActivity> rule, FragmentController fragmentController) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Pair<Parcelable, FragmentManagerNonConfig>[] result = new Pair[1];
+        instrumentation.runOnMainSync(() -> {
+            fragmentController.dispatchPause();
+            final Parcelable savedState = fragmentController.saveAllState();
+            final FragmentManagerNonConfig nonConfig = fragmentController.retainNestedNonConfig();
+            fragmentController.dispatchStop();
+            fragmentController.doLoaderStop(false);
+            fragmentController.dispatchDestroy();
+            fragmentController.doLoaderDestroy();
+            result[0] = Pair.create(savedState, nonConfig);
+        });
+        return result[0];
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
new file mode 100644
index 0000000..8f3f55b
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -0,0 +1,974 @@
+/*
+ * 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.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import com.android.compatibility.common.util.transition.TargetTracking;
+import com.android.compatibility.common.util.transition.TrackingTransition;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.Instrumentation;
+import android.app.SharedElementCallback;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.transition.TransitionSet;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class FragmentTransitionTest {
+    private final boolean mOptimize;
+
+    @Parameterized.Parameters
+    public static Object[] data() {
+        return new Boolean[] {
+                false, true
+        };
+    }
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+    private FragmentManager mFragmentManager;
+
+    public FragmentTransitionTest(final boolean optimize) {
+        mOptimize = optimize;
+    }
+
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mFragmentManager = mActivityRule.getActivity().getFragmentManager();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+    }
+
+    // Test that normal view transitions (enter, exit, reenter, return) run with
+    // a single fragment.
+    @Test
+    public void enterExitTransitions() throws Throwable {
+        // enter transition
+        TransitionFragment fragment = setupInitialFragment();
+        final View blue = findBlue();
+        final View green = findBlue();
+
+        // exit transition
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+
+        fragment.waitForTransition();
+        verifyAndClearTransition(fragment.exitTransition, null, green, blue);
+        verifyNoOtherTransitions(fragment);
+
+        // reenter transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForTransition();
+        final View green2 = findGreen();
+        final View blue2 = findBlue();
+        verifyAndClearTransition(fragment.reenterTransition, null, green2, blue2);
+        verifyNoOtherTransitions(fragment);
+
+        // return transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForTransition();
+        verifyAndClearTransition(fragment.returnTransition, null, green2, blue2);
+        verifyNoOtherTransitions(fragment);
+    }
+
+    // Test that shared elements transition from one fragment to the next
+    // and back during pop.
+    @Test
+    public void sharedElement() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+
+        // Now pop the back stack
+        verifyPopTransition(1, fragment2, fragment1);
+    }
+
+    // Test that shared element transitions through multiple fragments work together
+    @Test
+    public void intermediateFragment() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        final TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene3);
+
+        verifyTransition(fragment1, fragment2, "shared");
+
+        final TransitionFragment fragment3 = new TransitionFragment();
+        fragment3.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment2, fragment3, "blueSquare");
+
+        // Should transfer backwards when popping multiple:
+        verifyPopTransition(2, fragment3, fragment1, fragment2);
+    }
+
+    // Adding/removing the same fragment multiple times shouldn't mess anything up
+    @Test
+    public void removeAdded() throws Throwable {
+        final TransitionFragment fragment1 = setupInitialFragment();
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        final TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFragmentManager.beginTransaction()
+                        .setAllowOptimization(mOptimize)
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .replace(R.id.fragmentContainer, fragment1)
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // should be a normal transition from fragment1 to fragment2
+        fragment2.waitForTransition();
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+        verifyAndClearTransition(fragment1.exitTransition, null, startBlue, startGreen);
+        verifyAndClearTransition(fragment2.enterTransition, null, endBlue, endGreen);
+        verifyNoOtherTransitions(fragment1);
+        verifyNoOtherTransitions(fragment2);
+
+        // Pop should also do the same thing
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        final View popBlue = findBlue();
+        final View popGreen = findGreen();
+        verifyAndClearTransition(fragment1.reenterTransition, null, popBlue, popGreen);
+        verifyAndClearTransition(fragment2.returnTransition, null, endBlue, endGreen);
+        verifyNoOtherTransitions(fragment1);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Make sure that shared elements on two different fragment containers don't interact
+    @Test
+    public void crossContainer() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+        TransitionFragment fragment1 = new TransitionFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        final View greenSquare1 = findViewById(fragment1, R.id.greenSquare);
+        final View blueSquare1 = findViewById(fragment1, R.id.blueSquare);
+        verifyAndClearTransition(fragment1.enterTransition, null, greenSquare1, blueSquare1);
+        verifyNoOtherTransitions(fragment1);
+        fragment2.waitForTransition();
+        final View greenSquare2 = findViewById(fragment2, R.id.greenSquare);
+        final View blueSquare2 = findViewById(fragment2, R.id.blueSquare);
+        verifyAndClearTransition(fragment2.enterTransition, null, greenSquare2, blueSquare2);
+        verifyNoOtherTransitions(fragment2);
+
+        // Make sure the correct transitions are run when the target names
+        // are different in both shared elements. We may fool the system.
+        verifyCrossTransition(false, fragment1, fragment2);
+
+        // Make sure the correct transitions are run when the source names
+        // are different in both shared elements. We may fool the system.
+        verifyCrossTransition(true, fragment1, fragment2);
+    }
+
+    // Make sure that onSharedElementStart and onSharedElementEnd are called
+    @Test
+    public void callStartEndWithSharedElements() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        SharedElementCallback enterCallback = mock(SharedElementCallback.class);
+        fragment2.setEnterSharedElementCallback(enterCallback);
+
+        final View startBlue = findBlue();
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+
+        ArgumentCaptor<List> names = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List> views = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List> snapshots = ArgumentCaptor.forClass(List.class);
+        verify(enterCallback).onSharedElementStart(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(startBlue, views.getValue().get(0));
+
+        final View endBlue = findBlue();
+
+        verify(enterCallback).onSharedElementEnd(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(endBlue, views.getValue().get(0));
+
+        // Now pop the back stack
+        reset(enterCallback);
+        verifyPopTransition(1, fragment2, fragment1);
+
+        verify(enterCallback).onSharedElementStart(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(endBlue, views.getValue().get(0));
+
+        final View reenterBlue = findBlue();
+
+        verify(enterCallback).onSharedElementEnd(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(reenterBlue, views.getValue().get(0));
+    }
+
+    // Make sure that onMapSharedElement works to change the shared element going out
+    @Test
+    public void onMapSharedElementOut() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        final Rect startGreenBounds = getBoundsOnScreen(startGreen);
+
+        SharedElementCallback mapOut = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                assertEquals(startBlue, sharedElements.get("blueSquare"));
+                sharedElements.put("blueSquare", startGreen);
+            }
+        };
+        fragment1.setExitSharedElementCallback(mapOut);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final Rect endBlueBounds = getBoundsOnScreen(endBlue);
+
+        verifyAndClearTransition(fragment2.sharedElementEnter, startGreenBounds, startGreen,
+                endBlue);
+
+        SharedElementCallback mapBack = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                final View expectedBlue = findViewById(fragment1, R.id.blueSquare);
+                assertEquals(expectedBlue, sharedElements.get("blueSquare"));
+                final View greenSquare = findViewById(fragment1, R.id.greenSquare);
+                sharedElements.put("blueSquare", greenSquare);
+            }
+        };
+        fragment1.setExitSharedElementCallback(mapBack);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterGreen = findGreen();
+        verifyAndClearTransition(fragment2.sharedElementReturn, endBlueBounds, endBlue,
+                reenterGreen);
+    }
+
+    // Make sure that onMapSharedElement works to change the shared element target
+    @Test
+    public void onMapSharedElementIn() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        SharedElementCallback mapIn = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                final View blueSquare = findViewById(fragment2, R.id.blueSquare);
+                assertEquals(blueSquare, sharedElements.get("blueSquare"));
+                final View greenSquare = findViewById(fragment2, R.id.greenSquare);
+                sharedElements.put("blueSquare", greenSquare);
+            }
+        };
+        fragment2.setEnterSharedElementCallback(mapIn);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final Rect endGreenBounds = getBoundsOnScreen(endGreen);
+
+        verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue,
+                endGreen);
+
+        SharedElementCallback mapBack = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                assertEquals(endBlue, sharedElements.get("blueSquare"));
+                sharedElements.put("blueSquare", endGreen);
+            }
+        };
+        fragment2.setEnterSharedElementCallback(mapBack);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterBlue = findBlue();
+        verifyAndClearTransition(fragment2.sharedElementReturn, endGreenBounds, endGreen,
+                reenterBlue);
+    }
+
+    // Ensure that shared element transitions that have targets properly target the views
+    @Test
+    public void complexSharedElementTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        ComplexTransitionFragment fragment2 = new ComplexTransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .addSharedElement(startGreen, "greenSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+        final Rect endBlueBounds = getBoundsOnScreen(endBlue);
+
+        verifyAndClearTransition(fragment2.sharedElementEnterTransition1, startBlueBounds,
+                startBlue, endBlue);
+        verifyAndClearTransition(fragment2.sharedElementEnterTransition2, startBlueBounds,
+                startGreen, endGreen);
+
+        // Now see if it works when popped
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterBlue = findBlue();
+        final View reenterGreen = findGreen();
+
+        verifyAndClearTransition(fragment2.sharedElementReturnTransition1, endBlueBounds,
+                endBlue, reenterBlue);
+        verifyAndClearTransition(fragment2.sharedElementReturnTransition2, endBlueBounds,
+                endGreen, reenterGreen);
+    }
+
+    // Ensure that after transitions have executed that they don't have any targets or other
+    // unfortunate modifications.
+    @Test
+    public void transitionsEndUnchanged() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+        assertEquals(0, fragment1.exitTransition.getTargets().size());
+        assertEquals(0, fragment2.sharedElementEnter.getTargets().size());
+        assertEquals(0, fragment2.enterTransition.getTargets().size());
+        assertNull(fragment1.exitTransition.getEpicenterCallback());
+        assertNull(fragment2.enterTransition.getEpicenterCallback());
+        assertNull(fragment2.sharedElementEnter.getEpicenterCallback());
+
+        // Now pop the back stack
+        verifyPopTransition(1, fragment2, fragment1);
+
+        assertEquals(0, fragment2.returnTransition.getTargets().size());
+        assertEquals(0, fragment2.sharedElementReturn.getTargets().size());
+        assertEquals(0, fragment1.reenterTransition.getTargets().size());
+        assertNull(fragment2.returnTransition.getEpicenterCallback());
+        assertNull(fragment2.sharedElementReturn.getEpicenterCallback());
+        assertNull(fragment2.reenterTransition.getEpicenterCallback());
+    }
+
+    // Ensure that transitions are done when a fragment is shown and hidden
+    @Test
+    public void showHideTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment2)
+                .hide(fragment1)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endGreen = findViewById(fragment2, R.id.greenSquare);
+        final View endBlue = findViewById(fragment2, R.id.blueSquare);
+
+        assertEquals(View.GONE, fragment1.getView().getVisibility());
+        assertEquals(View.VISIBLE, startGreen.getVisibility());
+        assertEquals(View.VISIBLE, startBlue.getVisibility());
+
+        verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        verifyAndClearTransition(fragment1.reenterTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertEquals(View.VISIBLE, startGreen.getVisibility());
+        assertEquals(View.VISIBLE, startBlue.getVisibility());
+
+        verifyAndClearTransition(fragment2.returnTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Ensure that transitions are done when a fragment is attached and detached
+    @Test
+    public void attachDetachTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment2)
+                .detach(fragment1)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View endGreen = findViewById(fragment2, R.id.greenSquare);
+        final View endBlue = findViewById(fragment2, R.id.blueSquare);
+
+        verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View reenterBlue = findBlue();
+        final View reenterGreen = findGreen();
+
+        verifyAndClearTransition(fragment1.reenterTransition, null, reenterGreen, reenterBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.returnTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Ensure that shared element without matching transition name doesn't error out
+    @Test
+    public void sharedElementMismatch() throws Throwable {
+        final TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "fooSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+
+        if (mOptimize) {
+            verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        } else {
+            verifyAndClearTransition(fragment1.exitTransition, startBlueBounds, startGreen);
+            verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue);
+        }
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Ensure that using the same source or target shared element results in an exception.
+    @Test
+    public void sharedDuplicateTargetNames() throws Throwable {
+        setupInitialFragment();
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        FragmentTransaction ft = mFragmentManager.beginTransaction();
+        ft.addSharedElement(startBlue, "blueSquare");
+        try {
+            ft.addSharedElement(startGreen, "blueSquare");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            ft.addSharedElement(startBlue, "greenSquare");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    // Test that invisible fragment views don't participate in transitions
+    @Test
+    public void invisibleNoTransitions() throws Throwable {
+        if (!mOptimize) {
+            return; // only optimized transitions can avoid interaction
+        }
+        // enter transition
+        TransitionFragment fragment = new InvisibleFragment();
+        fragment.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // exit transition
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // reenter transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // return transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+    }
+
+    private TransitionFragment setupInitialFragment() throws Throwable {
+        TransitionFragment fragment1 = new TransitionFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        final View blueSquare1 = findBlue();
+        final View greenSquare1 = findGreen();
+        verifyAndClearTransition(fragment1.enterTransition, null, blueSquare1, greenSquare1);
+        verifyNoOtherTransitions(fragment1);
+        return fragment1;
+    }
+
+    private View findViewById(Fragment fragment, int id) {
+        return fragment.getView().findViewById(id);
+    }
+
+    private View findGreen() {
+        return mActivityRule.getActivity().findViewById(R.id.greenSquare);
+    }
+
+    private View findBlue() {
+        return mActivityRule.getActivity().findViewById(R.id.blueSquare);
+    }
+
+    private View findRed() {
+        return mActivityRule.getActivity().findViewById(R.id.redSquare);
+    }
+
+    private void verifyAndClearTransition(TargetTracking transition, Rect epicenter,
+            View... expected) {
+        if (epicenter == null) {
+            assertNull(transition.getCapturedEpicenter());
+        } else {
+            assertEquals(epicenter, transition.getCapturedEpicenter());
+        }
+        ArrayList<View> targets = transition.getTrackedTargets();
+        String errorMessage = "Expected: [" + expected.length + "] {" +
+                Arrays.stream(expected).map(v -> v.toString()).collect(Collectors.joining(", ")) +
+                "}, but got: [" + targets.size() + "] {" +
+                targets.stream().map(v -> v.toString()).collect(Collectors.joining(", ")) +
+                "}";
+        assertEquals(errorMessage, expected.length, targets.size());
+        for (View view : expected) {
+            assertTrue(errorMessage, targets.contains(view));
+        }
+        transition.clearTargets();
+    }
+
+    private void verifyNoOtherTransitions(TransitionFragment fragment) {
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.exitTransition.targets.size());
+        assertEquals(0, fragment.reenterTransition.targets.size());
+        assertEquals(0, fragment.returnTransition.targets.size());
+        assertEquals(0, fragment.sharedElementEnter.targets.size());
+        assertEquals(0, fragment.sharedElementReturn.targets.size());
+    }
+
+    private void verifyTransition(TransitionFragment from, TransitionFragment to,
+            String sharedElementName) throws Throwable {
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final View startRed = findRed();
+
+        final Rect startBlueRect = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .addSharedElement(startBlue, sharedElementName)
+                .replace(R.id.fragmentContainer, to)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        to.waitForTransition();
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final View endRed = findRed();
+        final Rect endBlueRect = getBoundsOnScreen(endBlue);
+
+        if (startRed != null) {
+            verifyAndClearTransition(from.exitTransition, startBlueRect, startGreen, startRed);
+        } else {
+            verifyAndClearTransition(from.exitTransition, startBlueRect, startGreen);
+        }
+        verifyNoOtherTransitions(from);
+
+        if (endRed != null) {
+            verifyAndClearTransition(to.enterTransition, endBlueRect, endGreen, endRed);
+        } else {
+            verifyAndClearTransition(to.enterTransition, endBlueRect, endGreen);
+        }
+        verifyAndClearTransition(to.sharedElementEnter, startBlueRect, startBlue, endBlue);
+        verifyNoOtherTransitions(to);
+    }
+
+    private void verifyCrossTransition(boolean swapSource,
+            TransitionFragment from1, TransitionFragment from2) throws Throwable {
+
+        final TransitionFragment to1 = new TransitionFragment();
+        to1.setLayoutId(R.layout.scene2);
+        final TransitionFragment to2 = new TransitionFragment();
+        to2.setLayoutId(R.layout.scene2);
+
+        final View fromExit1 = findViewById(from1, R.id.greenSquare);
+        final View fromShared1 = findViewById(from1, R.id.blueSquare);
+        final Rect fromSharedRect1 = getBoundsOnScreen(fromShared1);
+
+        final int fromExitId2 = swapSource ? R.id.blueSquare : R.id.greenSquare;
+        final int fromSharedId2 = swapSource ? R.id.greenSquare : R.id.blueSquare;
+        final View fromExit2 = findViewById(from2, fromExitId2);
+        final View fromShared2 = findViewById(from2, fromSharedId2);
+        final Rect fromSharedRect2 = getBoundsOnScreen(fromShared2);
+
+        final String sharedElementName = swapSource ? "blueSquare" : "greenSquare";
+
+        mActivityRule.runOnUiThread(() -> {
+            mFragmentManager.beginTransaction()
+                    .setAllowOptimization(mOptimize)
+                    .addSharedElement(fromShared1, "blueSquare")
+                    .replace(R.id.fragmentContainer1, to1)
+                    .addToBackStack(null)
+                    .commit();
+            mFragmentManager.beginTransaction()
+                    .setAllowOptimization(mOptimize)
+                    .addSharedElement(fromShared2, sharedElementName)
+                    .replace(R.id.fragmentContainer2, to2)
+                    .addToBackStack(null)
+                    .commit();
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        from1.waitForTransition();
+        from2.waitForTransition();
+        to1.waitForTransition();
+        to2.waitForTransition();
+
+        final View toEnter1 = findViewById(to1, R.id.greenSquare);
+        final View toShared1 = findViewById(to1, R.id.blueSquare);
+        final Rect toSharedRect1 = getBoundsOnScreen(toShared1);
+
+        final View toEnter2 = findViewById(to2, fromSharedId2);
+        final View toShared2 = findViewById(to2, fromExitId2);
+        final Rect toSharedRect2 = getBoundsOnScreen(toShared2);
+
+        verifyAndClearTransition(from1.exitTransition, fromSharedRect1, fromExit1);
+        verifyAndClearTransition(from2.exitTransition, fromSharedRect2, fromExit2);
+        verifyNoOtherTransitions(from1);
+        verifyNoOtherTransitions(from2);
+
+        verifyAndClearTransition(to1.enterTransition, toSharedRect1, toEnter1);
+        verifyAndClearTransition(to2.enterTransition, toSharedRect2, toEnter2);
+        verifyAndClearTransition(to1.sharedElementEnter, fromSharedRect1, fromShared1, toShared1);
+        verifyAndClearTransition(to2.sharedElementEnter, fromSharedRect2, fromShared2, toShared2);
+        verifyNoOtherTransitions(to1);
+        verifyNoOtherTransitions(to2);
+
+        // Now pop it back
+        mActivityRule.runOnUiThread(() -> {
+            mFragmentManager.popBackStack();
+            mFragmentManager.popBackStack();
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        from1.waitForTransition();
+        from2.waitForTransition();
+        to1.waitForTransition();
+        to2.waitForTransition();
+
+        final View returnEnter1 = findViewById(from1, R.id.greenSquare);
+        final View returnShared1 = findViewById(from1, R.id.blueSquare);
+
+        final View returnEnter2 = findViewById(from2, fromExitId2);
+        final View returnShared2 = findViewById(from2, fromSharedId2);
+
+        verifyAndClearTransition(to1.returnTransition, toSharedRect1, toEnter1);
+        verifyAndClearTransition(to2.returnTransition, toSharedRect2, toEnter2);
+        verifyAndClearTransition(to1.sharedElementReturn, toSharedRect1, toShared1, returnShared1);
+        verifyAndClearTransition(to2.sharedElementReturn, toSharedRect2, toShared2, returnShared2);
+        verifyNoOtherTransitions(to1);
+        verifyNoOtherTransitions(to2);
+
+        verifyAndClearTransition(from1.reenterTransition, fromSharedRect1, returnEnter1);
+        verifyAndClearTransition(from2.reenterTransition, fromSharedRect2, returnEnter2);
+        verifyNoOtherTransitions(from1);
+        verifyNoOtherTransitions(from2);
+    }
+
+    private void verifyPopTransition(final int numPops, TransitionFragment from,
+            TransitionFragment to, TransitionFragment... others) throws Throwable {
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final View startRed = findRed();
+        final Rect startSharedRect = getBoundsOnScreen(startBlue);
+
+        mInstrumentation.runOnMainSync(() -> {
+            for (int i = 0; i < numPops; i++) {
+                mFragmentManager.popBackStack();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        to.waitForTransition();
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final View endRed = findRed();
+        final Rect endSharedRect = getBoundsOnScreen(endBlue);
+
+        if (startRed != null) {
+            verifyAndClearTransition(from.returnTransition, startSharedRect, startGreen, startRed);
+        } else {
+            verifyAndClearTransition(from.returnTransition, startSharedRect, startGreen);
+        }
+        verifyAndClearTransition(from.sharedElementReturn, startSharedRect, startBlue, endBlue);
+        verifyNoOtherTransitions(from);
+
+        if (endRed != null) {
+            verifyAndClearTransition(to.reenterTransition, endSharedRect, endGreen, endRed);
+        } else {
+            verifyAndClearTransition(to.reenterTransition, endSharedRect, endGreen);
+        }
+        verifyNoOtherTransitions(to);
+
+        if (others != null) {
+            for (TransitionFragment fragment : others) {
+                verifyNoOtherTransitions(fragment);
+            }
+        }
+    }
+
+    private static Rect getBoundsOnScreen(View view) {
+        final int[] loc = new int[2];
+        view.getLocationOnScreen(loc);
+        return new Rect(loc[0], loc[1], loc[0] + view.getWidth(), loc[1] + view.getHeight());
+    }
+
+    public static class ComplexTransitionFragment extends TransitionFragment {
+        public final TrackingTransition sharedElementEnterTransition1 = new TrackingTransition();
+        public final TrackingTransition sharedElementEnterTransition2 = new TrackingTransition();
+        public final TrackingTransition sharedElementReturnTransition1 = new TrackingTransition();
+        public final TrackingTransition sharedElementReturnTransition2 = new TrackingTransition();
+
+        public final TransitionSet sharedElementEnterTransition = new TransitionSet()
+                .addTransition(sharedElementEnterTransition1)
+                .addTransition(sharedElementEnterTransition2);
+        public final TransitionSet sharedElementReturnTransition = new TransitionSet()
+                .addTransition(sharedElementReturnTransition1)
+                .addTransition(sharedElementReturnTransition2);
+
+        public ComplexTransitionFragment() {
+            sharedElementEnterTransition1.addTarget(R.id.blueSquare);
+            sharedElementEnterTransition2.addTarget(R.id.greenSquare);
+            sharedElementReturnTransition1.addTarget(R.id.blueSquare);
+            sharedElementReturnTransition2.addTarget(R.id.greenSquare);
+            setSharedElementEnterTransition(sharedElementEnterTransition);
+            setSharedElementReturnTransition(sharedElementReturnTransition);
+        }
+    }
+
+    public static class InvisibleFragment extends TransitionFragment {
+        @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            view.setVisibility(View.INVISIBLE);
+            super.onViewCreated(view, savedInstanceState);
+        }
+    }
+}
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..82890df
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -0,0 +1,924 @@
+/*
+ * 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.os.Bundle;
+import android.os.Debug;
+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);
+        FragmentTestUtil.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);
+        FragmentTestUtil.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);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, container.getChildCount());
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.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);
+        FragmentTestUtil.assertChildren(container1, fragment1);
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer2, fragment2).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container1, fragment1, fragment3);
+        FragmentTestUtil.assertChildren(container2, fragment2, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container1, fragment1);
+        FragmentTestUtil.assertChildren(container2, fragment2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container1, fragment1);
+        FragmentTestUtil.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);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+
+        // Remove a view
+        fm.beginTransaction().remove(fragment4).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertEquals(3, container.getChildCount());
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3);
+
+        // remove another one
+        fm.beginTransaction().remove(fragment2).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment3);
+
+        // Now remove the remaining:
+        fm.beginTransaction()
+                .remove(fragment3)
+                .remove(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        final Fragment replacement3 = fm.findFragmentByTag("3");
+        FragmentTestUtil.assertChildren(container, replacement1, replacement3);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement2 = fm.findFragmentByTag("2");
+        FragmentTestUtil.assertChildren(container, replacement1, replacement3, replacement2);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement4 = fm.findFragmentByTag("4");
+        FragmentTestUtil.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);
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertTrue(fragment1.isHidden());
+
+        fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        FragmentTestUtil.assertChildren(container, replacement1);
+        assertTrue(replacement1.isHidden());
+        assertEquals(View.GONE, replacement1.getView().getVisibility());
+    }
+
+    // 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);
+        FragmentTestUtil.assertChildren(container);
+        assertTrue(fragment1.isDetached());
+
+        fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        FragmentTestUtil.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);
+        FragmentTestUtil.assertChildren(container, fragment);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().hide(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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
+    // GONE.
+    @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);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().show(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertFalse(fragment.isHidden());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.beginTransaction().detach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container);
+        assertTrue(fragment.isDetached());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container);
+        assertTrue(fragment.isHidden());
+        assertTrue(fragment.isDetached());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container);
+        assertTrue(fragment.isDetached());
+
+        fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertFalse(fragment.isDetached());
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container);
+        assertTrue(fragment.isDetached());
+        assertTrue(fragment.isHidden());
+
+        fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertTrue(fragment.isHidden());
+        assertFalse(fragment.isDetached());
+        assertEquals(View.GONE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment2);
+        assertEquals(View.VISIBLE, fragment2.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        Fragment replacement1 = fm.findFragmentByTag("1");
+        assertNotNull(replacement1);
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.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);
+        FragmentTestUtil.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);
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container);
+    }
+
+    // Replace a fragment that exists with itself
+    @Test
+    public void replaceExisting() 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")
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
+
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        final Fragment replacement2 = fm.findFragmentByTag("2");
+
+        assertSame(fragment1, replacement1);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement2);
+    }
+
+    // Have two replace operations in the same transaction to ensure that they
+    // don't interfere with each other
+    @Test
+    public void replaceReplace() 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();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .replace(R.id.fragmentContainer1, fragment3)
+                .replace(R.id.fragmentContainer2, fragment4)
+                .replace(R.id.fragmentContainer1, fragment5)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container1, fragment5);
+        assertChildren(container2, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container1);
+        assertChildren(container2);
+    }
+
+    // Test to prevent regressions in FragmentManager fragment replace method. See b/24693644
+    @Test
+    public void testReplaceFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        StrictViewFragment fragmentA = new StrictViewFragment();
+        fragmentA.setLayoutId(R.layout.text_a);
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragmentA)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertNotNull(findViewById(R.id.textA));
+        assertNull(findViewById(R.id.textB));
+        assertNull(findViewById(R.id.textC));
+
+        StrictViewFragment fragmentB = new StrictViewFragment();
+        fragmentB.setLayoutId(R.layout.text_b);
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragmentB)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertNotNull(findViewById(R.id.textA));
+        assertNotNull(findViewById(R.id.textB));
+        assertNull(findViewById(R.id.textC));
+
+        StrictViewFragment fragmentC = new StrictViewFragment();
+        fragmentC.setLayoutId(R.layout.text_c);
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragmentC)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertNull(findViewById(R.id.textA));
+        assertNull(findViewById(R.id.textB));
+        assertNotNull(findViewById(R.id.textC));
+    }
+
+    // Test that adding a fragment with invisible or gone views does not end up with the view
+    // being visible
+    @Test
+    public void addInvisibleAndGoneFragments() 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 InvisibleFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        assertEquals(View.INVISIBLE, fragment1.getView().getVisibility());
+
+        final InvisibleFragment fragment2 = new InvisibleFragment();
+        fragment2.visibility = View.GONE;
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment2);
+
+        assertEquals(View.GONE, fragment2.getView().getVisibility());
+    }
+
+    private View findViewById(int viewId) {
+        return mActivityRule.getActivity().findViewById(viewId);
+    }
+
+    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());
+        }
+    }
+
+    public static class InvisibleFragment extends StrictViewFragment {
+        public int visibility = View.INVISIBLE;
+
+        @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            view.setVisibility(visibility);
+            super.onViewCreated(view, savedInstanceState);
+        }
+    }}
diff --git a/tests/fragment/src/android/fragment/cts/HostCallbacks.java b/tests/fragment/src/android/fragment/cts/HostCallbacks.java
new file mode 100644
index 0000000..fd45aa1
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/HostCallbacks.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.fragment.cts;
+
+import android.app.FragmentHostCallback;
+import android.os.Handler;
+import android.view.View;
+
+class HostCallbacks extends FragmentHostCallback<FragmentTestActivity> {
+    private final FragmentTestActivity mActivity;
+
+    public HostCallbacks(FragmentTestActivity activity, Handler handler, int windowAnimations) {
+        super(activity, handler, windowAnimations);
+        mActivity = activity;
+    }
+
+    @Override
+    public FragmentTestActivity onGetHost() {
+        return mActivity;
+    }
+
+    @Override
+    public View onFindViewById(int id) {
+        return mActivity.findViewById(id);
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
new file mode 100644
index 0000000..e24eb39
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.Fragment;
+import android.app.FragmentManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NestedInflatedFragmentTest {
+    private static final String TAG = "NestedInflatedFragmentTest";
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentTestActivity.class);
+
+    @Test
+    public void inflatedChildFragment() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final FragmentTestActivity activity = mActivityRule.getActivity();
+                final FragmentManager fm = activity.getFragmentManager();
+
+                ParentFragment parentFragment = new ParentFragment();
+                fm.beginTransaction().add(android.R.id.content, parentFragment).commitNow();
+
+                fm.beginTransaction().replace(android.R.id.content, new SimpleFragment())
+                        .addToBackStack(null).commit();
+                fm.executePendingTransactions();
+
+                fm.popBackStackImmediate();
+            }
+        });
+    }
+
+    public static class ParentFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_parent, container, false);
+        }
+    }
+
+    public static class InflatedChildFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_child, container, false);
+        }
+    }
+
+    public static class SimpleFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            TextView textView = new TextView(inflater.getContext());
+            textView.setText("Simple fragment");
+            return textView;
+        }
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
new file mode 100644
index 0000000..29a723b
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
@@ -0,0 +1,809 @@
+/*
+ * 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 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.assertTrue;
+
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentManager;
+import android.app.FragmentManagerNonConfig;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Parcelable;
+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.util.Pair;
+import android.view.LayoutInflater;
+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 PostponedTransitionTest {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+    private PostponedFragment1 mBeginningFragment;
+
+    @Before
+    public void setupContainer() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        mBeginningFragment = new PostponedFragment1();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, mBeginningFragment)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        mBeginningFragment.startPostponedEnterTransition();
+        mBeginningFragment.waitForTransition();
+        clearTargets(mBeginningFragment);
+    }
+
+    // Ensure that replacing with a fragment that has a postponed transition
+    // will properly postpone it, both adding and popping.
+    @Test
+    public void replaceTransition() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment = new PostponedFragment2();
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // should be postponed now
+        assertPostponedTransition(mBeginningFragment, fragment, null);
+
+        // start the postponed transition
+        fragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(mBeginningFragment, fragment);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        // should be postponed going back, too
+        assertPostponedTransition(fragment, mBeginningFragment, null);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment, mBeginningFragment);
+    }
+
+    // Ensure that postponed transition is forced after another has been committed.
+    // This tests when the transactions are executed together
+    @Test
+    public void forcedTransition1() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+        final PostponedFragment1 fragment3 = new PostponedFragment1();
+
+        final int commit[] = new int[1];
+        // Need to run this on the UI thread so that the transaction doesn't start
+        // between the two
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                commit[0] = fm.beginTransaction()
+                        .addSharedElement(startBlue, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+
+                fm.beginTransaction()
+                        .addSharedElement(startBlue, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment3)
+                        .addToBackStack(null)
+                        .commit();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // transition to fragment2 should be started
+        assertForwardTransition(mBeginningFragment, fragment2);
+
+        // fragment3 should be postponed, but fragment2 should be executed with no transition.
+        assertPostponedTransition(fragment2, fragment3, mBeginningFragment);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment3);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, commit[0],
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+
+        assertBackTransition(fragment3, fragment2);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, fragment3);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Ensure that postponed transition is forced after another has been committed.
+    // This tests when the transactions are processed separately.
+    @Test
+    public void forcedTransition2() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment2, null);
+
+        final PostponedFragment1 fragment3 = new PostponedFragment1();
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        // This should cancel the mBeginningFragment -> fragment2 transition
+        // and start fragment2 -> fragment3 transition postponed
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // fragment3 should be postponed, but fragment2 should be executed with no transition.
+        assertPostponedTransition(fragment2, fragment3, mBeginningFragment);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment3);
+
+        // Pop back to fragment2, but it should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment3, fragment2, null);
+
+        // Pop to mBeginningFragment -- should cancel the fragment2 transition and
+        // start the mBeginningFragment transaction postponed
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, fragment3);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Do a bunch of things to one fragment in a transaction and see if it can screw things up.
+    @Test
+    public void crazyTransition() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .hide(mBeginningFragment)
+                .replace(R.id.fragmentContainer, fragment2)
+                .hide(fragment2)
+                .detach(fragment2)
+                .attach(fragment2)
+                .show(fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment2, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(mBeginningFragment, fragment2);
+
+        // Pop back to fragment2, but it should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, null);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Execute transactions on different containers and ensure that they don't conflict
+    @Test
+    public void differentContainers() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+        TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue2, "blueSquare")
+                .replace(R.id.fragmentContainer2, fragment4)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment1, fragment3);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment4);
+
+        // Pop back to fragment2 -- should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // Pop back to fragment1 -- also should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment4, fragment2);
+
+        // but not the postponed one
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment3, fragment1);
+    }
+
+    // Execute transactions on different containers and ensure that they don't conflict.
+    // The postponement can be started out-of-order
+    @Test
+    public void outOfOrderContainers() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+        TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue2, "blueSquare")
+                .replace(R.id.fragmentContainer2, fragment4)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment2, fragment4);
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment1, fragment3);
+
+        // Pop back to fragment2 -- should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // Pop back to fragment1 -- also should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment3, fragment1);
+
+        // but not the postponed one
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment4, fragment2);
+    }
+
+    // Make sure that commitNow for a transaction on a different fragment container doesn't
+    // affect the postponed transaction
+    @Test
+    public void commitNowNoEffect() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        final TransitionFragment fragment1 = new PostponedFragment1();
+        final TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+        final StrictFragment strictFragment1 = new StrictFragment();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .add(strictFragment1, "1")
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+        final StrictFragment strictFragment2 = new StrictFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .addSharedElement(startBlue2, "blueSquare")
+                        .replace(R.id.fragmentContainer2, fragment4)
+                        .remove(strictFragment1)
+                        .add(strictFragment2, "2")
+                        .commitNow();
+            }
+        });
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment2, fragment4);
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment1, fragment3);
+    }
+
+    // Make sure that commitNow for a transaction affecting a postponed fragment in the same
+    // container forces the postponed transition to start.
+    @Test
+    public void commitNowStartsPostponed() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue1 = mBeginningFragment.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment2 = new PostponedFragment2();
+        final TransitionFragment fragment1 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .addSharedElement(startBlue2, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment1)
+                        .commitNow();
+            }
+        });
+
+        assertPostponedTransition(fragment2, fragment1, mBeginningFragment);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        assertForwardTransition(fragment2, fragment1);
+    }
+
+    // Make sure that when a transaction that removes a view is postponed that
+    // another transaction doesn't accidentally remove the view early.
+    @Test
+    public void noAccidentalRemoval() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        clearTargets(fragment1);
+
+        TransitionFragment fragment2 = new PostponedFragment2();
+        // Create a postponed transaction that removes a view
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer1, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertPostponedTransition(fragment1, fragment2, null);
+
+        TransitionFragment fragment3 = new PostponedFragment1();
+        // Create a transaction that doesn't interfere with the previously postponed one
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer2, fragment3)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment2, null);
+
+        fragment3.startPostponedEnterTransition();
+        fragment3.waitForTransition();
+        clearTargets(fragment3);
+
+        assertPostponedTransition(fragment1, fragment2, null);
+    }
+
+    // Ensure that a postponed transaction that is popped runs immediately and that
+    // the transaction results in the original state with no transition.
+    @Test
+    public void popPostponedTransaction() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mBeginningFragment.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment, null);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment.waitForNoTransition();
+        mBeginningFragment.waitForNoTransition();
+
+        assureNoTransition(fragment);
+        assureNoTransition(mBeginningFragment);
+
+        assertFalse(fragment.isAdded());
+        assertNull(fragment.getView());
+        assertNotNull(mBeginningFragment.getView());
+        assertEquals(View.VISIBLE, mBeginningFragment.getView().getVisibility());
+        assertTrue(mBeginningFragment.getView().isAttachedToWindow());
+    }
+
+    // Make sure that when saving the state during a postponed transaction that it saves
+    // the state as if it wasn't postponed.
+    @Test
+    public void saveWhilePostponed() throws Throwable {
+        final FragmentController fc1 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc1, null);
+
+        final FragmentManager fm1 = fc1.getFragmentManager();
+
+        PostponedFragment1 fragment1 = new PostponedFragment1();
+        fm1.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        Pair<Parcelable, FragmentManagerNonConfig> state =
+                FragmentTestUtil.destroy(mActivityRule, fc1);
+
+        final FragmentController fc2 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc2, state);
+
+        final FragmentManager fm2 = fc2.getFragmentManager();
+        Fragment fragment2 = fm2.findFragmentByTag("1");
+        assertNotNull(fragment2);
+        assertNotNull(fragment2.getView());
+        assertEquals(View.VISIBLE, fragment2.getView().getVisibility());
+        assertTrue(fragment2.isResumed());
+        assertTrue(fragment2.isAdded());
+        assertTrue(fragment2.getView().isAttachedToWindow());
+
+        mInstrumentation.runOnMainSync(() -> {
+            assertTrue(fm2.popBackStackImmediate());
+        });
+
+        assertFalse(fragment2.isResumed());
+        assertFalse(fragment2.isAdded());
+        assertNull(fragment2.getView());
+    }
+
+    private void assertPostponedTransition(TransitionFragment fromFragment,
+            TransitionFragment toFragment, TransitionFragment removedFragment)
+            throws InterruptedException {
+        if (removedFragment != null) {
+            assertNull(removedFragment.getView());
+            assureNoTransition(removedFragment);
+        }
+
+        toFragment.waitForNoTransition();
+        assertNotNull(fromFragment.getView());
+        assertNotNull(toFragment.getView());
+        assertTrue(fromFragment.getView().isAttachedToWindow());
+        assertTrue(toFragment.getView().isAttachedToWindow());
+        assertEquals(View.VISIBLE, fromFragment.getView().getVisibility());
+        assertEquals(View.INVISIBLE, toFragment.getView().getVisibility());
+        assureNoTransition(fromFragment);
+        assureNoTransition(toFragment);
+        assertTrue(fromFragment.isResumed());
+        assertFalse(toFragment.isResumed());
+    }
+
+    private void clearTargets(TransitionFragment fragment) {
+        fragment.enterTransition.targets.clear();
+        fragment.reenterTransition.targets.clear();
+        fragment.exitTransition.targets.clear();
+        fragment.returnTransition.targets.clear();
+        fragment.sharedElementEnter.targets.clear();
+        fragment.sharedElementReturn.targets.clear();
+    }
+
+    private void assureNoTransition(TransitionFragment fragment) {
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.reenterTransition.targets.size());
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.returnTransition.targets.size());
+        assertEquals(0, fragment.sharedElementEnter.targets.size());
+        assertEquals(0, fragment.sharedElementReturn.targets.size());
+    }
+
+    private void assertForwardTransition(TransitionFragment start, TransitionFragment end)
+            throws InterruptedException {
+        start.waitForTransition();
+        end.waitForTransition();
+        assertEquals(0, start.enterTransition.targets.size());
+        assertEquals(1, end.enterTransition.targets.size());
+
+        assertEquals(0, start.reenterTransition.targets.size());
+        assertEquals(0, end.reenterTransition.targets.size());
+
+        assertEquals(0, start.returnTransition.targets.size());
+        assertEquals(0, end.returnTransition.targets.size());
+
+        assertEquals(1, start.exitTransition.targets.size());
+        assertEquals(0, end.exitTransition.targets.size());
+
+        assertEquals(0, start.sharedElementEnter.targets.size());
+        assertEquals(2, end.sharedElementEnter.targets.size());
+
+        assertEquals(0, start.sharedElementReturn.targets.size());
+        assertEquals(0, end.sharedElementReturn.targets.size());
+
+        final View blue = end.getView().findViewById(R.id.blueSquare);
+        assertTrue(end.sharedElementEnter.targets.contains(blue));
+        assertEquals("blueSquare", end.sharedElementEnter.targets.get(0).getTransitionName());
+        assertEquals("blueSquare", end.sharedElementEnter.targets.get(1).getTransitionName());
+
+        assertNoTargets(start);
+        assertNoTargets(end);
+
+        clearTargets(start);
+        clearTargets(end);
+    }
+
+    private void assertBackTransition(TransitionFragment start, TransitionFragment end)
+            throws InterruptedException {
+        start.waitForTransition();
+        end.waitForTransition();
+        assertEquals(1, end.reenterTransition.targets.size());
+        assertEquals(0, start.reenterTransition.targets.size());
+
+        assertEquals(0, end.returnTransition.targets.size());
+        assertEquals(1, start.returnTransition.targets.size());
+
+        assertEquals(0, start.enterTransition.targets.size());
+        assertEquals(0, end.enterTransition.targets.size());
+
+        assertEquals(0, start.exitTransition.targets.size());
+        assertEquals(0, end.exitTransition.targets.size());
+
+        assertEquals(0, start.sharedElementEnter.targets.size());
+        assertEquals(0, end.sharedElementEnter.targets.size());
+
+        assertEquals(2, start.sharedElementReturn.targets.size());
+        assertEquals(0, end.sharedElementReturn.targets.size());
+
+        final View blue = end.getView().findViewById(R.id.blueSquare);
+        assertTrue(start.sharedElementReturn.targets.contains(blue));
+        assertEquals("blueSquare", start.sharedElementReturn.targets.get(0).getTransitionName());
+        assertEquals("blueSquare", start.sharedElementReturn.targets.get(1).getTransitionName());
+
+        assertNoTargets(end);
+        assertNoTargets(start);
+
+        clearTargets(start);
+        clearTargets(end);
+    }
+
+    private static void assertNoTargets(TransitionFragment fragment) {
+        assertTrue(fragment.enterTransition.getTargets().isEmpty());
+        assertTrue(fragment.reenterTransition.getTargets().isEmpty());
+        assertTrue(fragment.exitTransition.getTargets().isEmpty());
+        assertTrue(fragment.returnTransition.getTargets().isEmpty());
+        assertTrue(fragment.sharedElementEnter.getTargets().isEmpty());
+        assertTrue(fragment.sharedElementReturn.getTargets().isEmpty());
+    }
+
+    public static class PostponedFragment1 extends TransitionFragment {
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            postponeEnterTransition();
+            return inflater.inflate(R.layout.scene1, container, false);
+        }
+    }
+
+    public static class PostponedFragment2 extends TransitionFragment {
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            postponeEnterTransition();
+            return inflater.inflate(R.layout.scene2, container, false);
+        }
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/StrictFragment.java b/tests/fragment/src/android/fragment/cts/StrictFragment.java
index f0c4a8a..f552eaa 100644
--- a/tests/fragment/src/android/fragment/cts/StrictFragment.java
+++ b/tests/fragment/src/android/fragment/cts/StrictFragment.java
@@ -37,7 +37,8 @@
 
     boolean mCalledOnAttach, mCalledOnCreate, mCalledOnActivityCreated,
             mCalledOnStart, mCalledOnResume, mCalledOnSaveInstanceState,
-            mCalledOnPause, mCalledOnStop, mCalledOnDestroy, mCalledOnDetach;
+            mCalledOnPause, mCalledOnStop, mCalledOnDestroy, mCalledOnDetach,
+            mCalledOnAttachFragment;
 
     static String stateToString(int state) {
         switch (state) {
@@ -82,6 +83,12 @@
     }
 
     @Override
+    public void onAttachFragment(Fragment childFragment) {
+        super.onAttachFragment(childFragment);
+        mCalledOnAttachFragment = true;
+    }
+
+    @Override
     public void onAttach(Context context) {
         super.onAttach(context);
         mCalledOnAttach = true;
@@ -134,7 +141,10 @@
         super.onSaveInstanceState(outState);
         mCalledOnSaveInstanceState = true;
         checkGetActivity();
-        checkStateAtLeast("onSaveInstanceState", STARTED);
+        // FIXME: We should not allow onSaveInstanceState except when STARTED or greater.
+        // But FragmentManager currently does it in saveAllState for fragments on the
+        // back stack, so fragments may be in the CREATED state.
+        checkStateAtLeast("onSaveInstanceState", CREATED);
     }
 
     @Override
diff --git a/tests/fragment/src/android/fragment/cts/StrictViewFragment.java b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
index 8c0ab51..d39cc12 100644
--- a/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
+++ b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
@@ -24,13 +24,24 @@
 
 public class StrictViewFragment extends StrictFragment {
     boolean mOnCreateViewCalled, mOnViewCreatedCalled, mOnDestroyViewCalled;
+    int mLayoutId = R.layout.strict_view_fragment;
+
+    public void setLayoutId(int layoutId) {
+        mLayoutId = layoutId;
+    }
+
+    public static StrictViewFragment create(int layoutId) {
+        StrictViewFragment fragment = new StrictViewFragment();
+        fragment.mLayoutId = layoutId;
+        return fragment;
+    }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         checkGetActivity();
         checkState("onCreateView", CREATED);
-        final View result = inflater.inflate(R.layout.strict_view_fragment, container, false);
+        final View result = inflater.inflate(mLayoutId, container, false);
         mOnCreateViewCalled = true;
         return result;
     }
diff --git a/tests/fragment/src/android/fragment/cts/TransitionFragment.java b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
new file mode 100644
index 0000000..fbe2250
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+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.verify;
+
+import com.android.compatibility.common.util.transition.TrackingTransition;
+import com.android.compatibility.common.util.transition.TrackingVisibility;
+
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.transition.Transition;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A fragment that has transitions that can be tracked.
+ */
+public class TransitionFragment extends StrictViewFragment {
+    public final TrackingVisibility enterTransition = new TrackingVisibility();
+    public final TrackingVisibility reenterTransition = new TrackingVisibility();
+    public final TrackingVisibility exitTransition = new TrackingVisibility();
+    public final TrackingVisibility returnTransition = new TrackingVisibility();
+    public final TrackingTransition sharedElementEnter = new TrackingTransition();
+    public final TrackingTransition sharedElementReturn = new TrackingTransition();
+
+    private Transition.TransitionListener mListener = mock(Transition.TransitionListener.class);
+
+    public TransitionFragment() {
+        setEnterTransition(enterTransition);
+        setReenterTransition(reenterTransition);
+        setExitTransition(exitTransition);
+        setReturnTransition(returnTransition);
+        setSharedElementEnterTransition(sharedElementEnter);
+        setSharedElementReturnTransition(sharedElementReturn);
+        enterTransition.addListener(mListener);
+        sharedElementEnter.addListener(mListener);
+        reenterTransition.addListener(mListener);
+        exitTransition.addListener(mListener);
+        returnTransition.addListener(mListener);
+        sharedElementReturn.addListener(mListener);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        checkGetActivity();
+        checkState("onCreateView", CREATED);
+        mOnCreateViewCalled = true;
+        return super.onCreateView(inflater, container, savedInstanceState);
+    }
+
+    void waitForTransition() throws InterruptedException {
+        verify(mListener, within(300)).onTransitionEnd(any());
+        reset(mListener);
+    }
+
+    void waitForNoTransition() throws InterruptedException {
+        SystemClock.sleep(250);
+        verify(mListener, never()).onTransitionStart(any());
+    }
+}
diff --git a/tests/jank/Android.mk b/tests/jank/Android.mk
index 6d85c70..fe3644a 100644
--- a/tests/jank/Android.mk
+++ b/tests/jank/Android.mk
@@ -27,6 +27,6 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner ub-uiautomator ub-janktesthelper
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator ub-janktesthelper
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/jank/AndroidTest.xml b/tests/jank/AndroidTest.xml
index c7e476a..aeb3d65 100644
--- a/tests/jank/AndroidTest.xml
+++ b/tests/jank/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.jank.cts" />
+        <option name="runtime-hint" value="11m20s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/jdwp/AndroidTest.xml b/tests/jdwp/AndroidTest.xml
index e3205b5..3cd1be2 100644
--- a/tests/jdwp/AndroidTest.xml
+++ b/tests/jdwp/AndroidTest.xml
@@ -35,7 +35,7 @@
         <option name="dalvik-arg" value="-Djpda.settings.waitingTime=10000" />
         <option name="dalvik-arg" value="-Djpda.settings.debuggeeJavaPath='dalvikvm|#ABI#| -XXlib:libart.so -Xcompiler-option --debuggable'" />
         <option name="known-failures" value="/expectations/jdwp-known-failures.txt" />
-        <option name="runtime-hint" value="5m" />
+        <option name="runtime-hint" value="16m" />
 
     </test>
 </configuration>
diff --git a/tests/jdwp/runner/host-side/Android.mk b/tests/jdwp/runner/host-side/Android.mk
index 426663d..7398f69 100644
--- a/tests/jdwp/runner/host-side/Android.mk
+++ b/tests/jdwp/runner/host-side/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE := cts-dalvik-host-test-runner
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
 
diff --git a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
index 3cbdee2..fb86862 100644
--- a/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
+++ b/tests/jdwp/runner/host-side/src/com/android/compatibility/testtype/DalvikTest.java
@@ -17,7 +17,6 @@
 package com.android.compatibility.testtype;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.util.AbiUtils;
 import com.android.ddmlib.IShellOutputReceiver;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
@@ -39,6 +38,7 @@
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFileFilterReceiver;
 import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.ArrayUtil;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.TimeVal;
diff --git a/tests/leanbackjank/Android.mk b/tests/leanbackjank/Android.mk
index e2c2593..b24b1da 100644
--- a/tests/leanbackjank/Android.mk
+++ b/tests/leanbackjank/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_COMPATIBILITY_SUITE := cts
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ub-janktesthelper \
diff --git a/tests/leanbackjank/AndroidTest.xml b/tests/leanbackjank/AndroidTest.xml
index a07c2eb..2828243 100644
--- a/tests/leanbackjank/AndroidTest.xml
+++ b/tests/leanbackjank/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.leanbackjank.cts" />
+        <option name="runtime-hint" value="10m50s" />
     </test>
 </configuration>
diff --git a/tests/leanbackjank/app/Android.mk b/tests/leanbackjank/app/Android.mk
index e2cbf89..0328fdf 100644
--- a/tests/leanbackjank/app/Android.mk
+++ b/tests/leanbackjank/app/Android.mk
@@ -33,7 +33,7 @@
     $(LOCAL_PATH)/res
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ub-janktesthelper \
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 9ba061a..f722f5fe 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -23,7 +23,7 @@
     conscrypt-tests \
     core-tests \
     cts-core-test-runner \
-    mockito-target \
+    mockito-target-minus-junit4 \
     tzdata_update2-tests \
     tzdata_update-tests
 
diff --git a/tests/libcore/ojluni/AndroidTest.xml b/tests/libcore/ojluni/AndroidTest.xml
index 8ab126cf..640d818 100644
--- a/tests/libcore/ojluni/AndroidTest.xml
+++ b/tests/libcore/ojluni/AndroidTest.xml
@@ -37,7 +37,7 @@
         <option name="core-expectation" value="/icebox.txt" />
         <option name="core-expectation" value="/taggedtests.txt" />
         <option name="core-expectation" value="/expectations/cts-runner-specific-failures.txt" />
-        <option name="runtime-hint" value="45m"/>
+        <option name="runtime-hint" value="35m"/>
         <!-- 20x default timeout of 600sec -->
         <option name="shell-timeout" value="12000000"/>
     </test>
diff --git a/tests/libcore/okhttp/AndroidTest.xml b/tests/libcore/okhttp/AndroidTest.xml
index 1969e8c..c6da08f 100644
--- a/tests/libcore/okhttp/AndroidTest.xml
+++ b/tests/libcore/okhttp/AndroidTest.xml
@@ -36,7 +36,7 @@
         <option name="core-expectation" value="/brokentests.txt" />
         <option name="core-expectation" value="/icebox.txt" />
         <option name="core-expectation" value="/taggedtests.txt" />
-        <option name="runtime-hint" value="10m"/>
+        <option name="runtime-hint" value="15m"/>
         <!-- 20x default timeout of 600sec -->
         <option name="shell-timeout" value="12000000"/>
     </test>
diff --git a/tests/netlegacy22.api/AndroidTest.xml b/tests/netlegacy22.api/AndroidTest.xml
index b40f21a..17e71f4 100644
--- a/tests/netlegacy22.api/AndroidTest.xml
+++ b/tests/netlegacy22.api/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.netlegacy22.api.cts" />
+        <option name="runtime-hint" value="10m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/netlegacy22.permission/AndroidTest.xml b/tests/netlegacy22.permission/AndroidTest.xml
index 490e979..5b4ffa0 100644
--- a/tests/netlegacy22.permission/AndroidTest.xml
+++ b/tests/netlegacy22.permission/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.netlegacy22.permission.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
diff --git a/tests/openglperf2/Android.mk b/tests/openglperf2/Android.mk
index f4295ca..f46c7d4 100644
--- a/tests/openglperf2/Android.mk
+++ b/tests/openglperf2/Android.mk
@@ -21,7 +21,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsopengl_jni
 
diff --git a/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java
index 6558786..420b7f9 100644
--- a/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java
+++ b/tests/openglperf2/src/android/opengl2/cts/primitive/GLPrimitiveActivity.java
@@ -13,9 +13,10 @@
  */
 package android.opengl2.cts.primitive;
 
+import com.android.compatibility.common.util.WatchDog;
+
 import android.app.Activity;
 import android.content.Intent;
-import android.cts.util.WatchDog;
 import android.opengl2.cts.GLActivityIntentKeys;
 import android.os.Bundle;
 import android.util.Log;
diff --git a/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java b/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java
index 0bfb38b..d018c06 100644
--- a/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java
+++ b/tests/openglperf2/src/android/opengl2/cts/reference/GLGameActivity.java
@@ -13,10 +13,11 @@
  */
 package android.opengl2.cts.reference;
 
+import com.android.compatibility.common.util.WatchDog;
+
 import android.app.Activity;
 import android.content.Intent;
 import android.content.res.AssetManager;
-import android.cts.util.WatchDog;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.opengl.GLES20;
diff --git a/tests/sensor/Android.mk b/tests/sensor/Android.mk
new file mode 100644
index 0000000..d3e7ce2
--- /dev/null
+++ b/tests/sensor/Android.mk
@@ -0,0 +1,55 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Reusable Sensor test classes and helpers
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-sensors-tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util
+
+LOCAL_JAVA_LIBRARIES := platform-test-annotations
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+# CtsSensorTestCases package
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    cts-sensors-tests \
+
+LOCAL_PACKAGE_NAME := CtsSensorTestCases
+
+LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/sensor/AndroidManifest.xml b/tests/sensor/AndroidManifest.xml
new file mode 100644
index 0000000..0c33e0d
--- /dev/null
+++ b/tests/sensor/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.hardware.sensor.cts">
+
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.BODY_SENSORS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.hardware.sensor.cts"
+                     android:label="CTS sensor tests">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/sensor/AndroidTest.xml b/tests/sensor/AndroidTest.xml
new file mode 100644
index 0000000..8d1207e
--- /dev/null
+++ b/tests/sensor/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<configuration description="Config for CTS Sensor test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSensorTestCases.apk" />
+    </target_preparer>
+    <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
+    sensors -->
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="dumpsys sensorservice restrict .cts." />
+        <option name="teardown-command" value="dumpsys sensorservice enable" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.hardware.sensor.cts" />
+        <option name="runtime-hint" value="47m28s" />
+        <!-- test-timeout unit is ms, value = 60 min -->
+        <option name="test-timeout" value="3600000" />
+    </test>
+
+</configuration>
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorAdditionalInfoTest.java b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorAdditionalInfoTest.java
rename to tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java b/tests/sensor/src/android/hardware/cts/SensorBatchingFifoTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
rename to tests/sensor/src/android/hardware/cts/SensorBatchingFifoTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java b/tests/sensor/src/android/hardware/cts/SensorBatchingTests.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
rename to tests/sensor/src/android/hardware/cts/SensorBatchingTests.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/sensor/src/android/hardware/cts/SensorIntegrationTests.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
rename to tests/sensor/src/android/hardware/cts/SensorIntegrationTests.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorManagerStaticTest.java b/tests/sensor/src/android/hardware/cts/SensorManagerStaticTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorManagerStaticTest.java
rename to tests/sensor/src/android/hardware/cts/SensorManagerStaticTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
rename to tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorSupportTest.java b/tests/sensor/src/android/hardware/cts/SensorSupportTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorSupportTest.java
rename to tests/sensor/src/android/hardware/cts/SensorSupportTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/sensor/src/android/hardware/cts/SensorTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorTest.java
rename to tests/sensor/src/android/hardware/cts/SensorTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java b/tests/sensor/src/android/hardware/cts/SensorTestCase.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
rename to tests/sensor/src/android/hardware/cts/SensorTestCase.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java b/tests/sensor/src/android/hardware/cts/SingleSensorTests.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
rename to tests/sensor/src/android/hardware/cts/SingleSensorTests.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java b/tests/sensor/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
rename to tests/sensor/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/FrameworkUnitTests.java b/tests/sensor/src/android/hardware/cts/helpers/FrameworkUnitTests.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/FrameworkUnitTests.java
rename to tests/sensor/src/android/hardware/cts/helpers/FrameworkUnitTests.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/MovementDetectorHelper.java b/tests/sensor/src/android/hardware/cts/helpers/MovementDetectorHelper.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/MovementDetectorHelper.java
rename to tests/sensor/src/android/hardware/cts/helpers/MovementDetectorHelper.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java b/tests/sensor/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelper.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java b/tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorCtsHelperTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java b/tests/sensor/src/android/hardware/cts/helpers/SensorNotSupportedException.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorNotSupportedException.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/sensor/src/android/hardware/cts/helpers/SensorStats.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorStats.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStatsTest.java b/tests/sensor/src/android/hardware/cts/helpers/SensorStatsTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorStatsTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorStatsTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestPlatformException.java b/tests/sensor/src/android/hardware/cts/helpers/SensorTestPlatformException.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestPlatformException.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorTestPlatformException.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestStateNotSupportedException.java b/tests/sensor/src/android/hardware/cts/helpers/SensorTestStateNotSupportedException.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SensorTestStateNotSupportedException.java
rename to tests/sensor/src/android/hardware/cts/helpers/SensorTestStateNotSupportedException.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SuspendStateMonitor.java b/tests/sensor/src/android/hardware/cts/helpers/SuspendStateMonitor.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/SuspendStateMonitor.java
rename to tests/sensor/src/android/hardware/cts/helpers/SuspendStateMonitor.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEnvironment.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
rename to tests/sensor/src/android/hardware/cts/helpers/TestSensorEnvironment.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEvent.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
rename to tests/sensor/src/android/hardware/cts/helpers/TestSensorEvent.java
diff --git a/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
new file mode 100644
index 0000000..b096987
--- /dev/null
+++ b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cts.helpers;
+
+import junit.framework.Assert;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener2;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
+ * events or for a specific time, or waiting for a flush to complete. This class performs
+ * verifications and will throw {@link AssertionError}s if there are any errors. It may also wrap
+ * another {@link SensorEventListener2}.
+ */
+public class TestSensorEventListener implements SensorEventListener2 {
+    public static final String LOG_TAG = "TestSensorEventListener";
+
+    private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
+    private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
+
+    private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<>();
+    private final ArrayList<Long> mTimeStampFlushCompleteEvents = new ArrayList<>();
+    private final List<CountDownLatch> mEventLatches = new ArrayList<>();
+    private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
+    private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
+
+    private final Handler mHandler;
+    private final TestSensorEnvironment mEnvironment;
+
+    // Wakelock for keeping the system running after terminate criterion is met.
+    // Useful for CtsVerifier test cases in which cpu can sleep if usb is not connected.
+    private final PowerManager.WakeLock mTestSensorEventListenerWakeLock;
+
+    /**
+     * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
+     */
+    @Deprecated
+    public TestSensorEventListener() {
+        this(null /* environment */);
+    }
+
+    /**
+     * Construct a {@link TestSensorEventListener}.
+     */
+    public TestSensorEventListener(TestSensorEnvironment environment) {
+        this(environment, null /* handler */);
+    }
+
+    /**
+     * Construct a {@link TestSensorEventListener}.
+     */
+    public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
+        mEnvironment = environment;
+        mHandler = handler;
+        PowerManager pm = (PowerManager) environment.getContext().getSystemService(
+                Context.POWER_SERVICE);
+        mTestSensorEventListenerWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                                                "TestSensorEventListenerWakeLock");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        long timestampNs = SystemClock.elapsedRealtimeNanos();
+        checkHandler();
+        synchronized (mCollectedEvents) {
+            mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
+        }
+        synchronized (mEventLatches) {
+            for (CountDownLatch latch : mEventLatches) {
+                latch.countDown();
+                if (latch.getCount() == 0 && !mTestSensorEventListenerWakeLock.isHeld()) {
+                    mTestSensorEventListenerWakeLock.acquire();
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        checkHandler();
+    }
+
+    /**
+     * @param eventCount
+     * @return A CountDownLatch initialzed with eventCount and decremented as sensor events arrive
+     * for this listerner.
+     */
+    public CountDownLatch getLatchForSensorEvents(int eventCount) {
+        CountDownLatch latch = new CountDownLatch(eventCount);
+        synchronized (mEventLatches) {
+            mEventLatches.add(latch);
+        }
+        return latch;
+    }
+
+    /**
+     * @return A CountDownLatch initialzed with 1 and decremented as a flush complete arrives
+     * for this listerner.
+     */
+    public CountDownLatch getLatchForFlushCompleteEvent() {
+        CountDownLatch latch = new CountDownLatch(1);
+        synchronized (mFlushLatches) {
+            mFlushLatches.add(latch);
+        }
+        return latch;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFlushCompleted(Sensor sensor) {
+        checkHandler();
+        long timestampNs = SystemClock.elapsedRealtimeNanos();
+        synchronized (mTimeStampFlushCompleteEvents) {
+           mTimeStampFlushCompleteEvents.add(timestampNs);
+        }
+        synchronized (mFlushLatches) {
+            for (CountDownLatch latch : mFlushLatches) {
+                latch.countDown();
+            }
+        }
+    }
+
+    /**
+     * @return The handler (if any) associated with the instance.
+     */
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    /**
+     * @return A list of {@link TestSensorEvent}s collected by the listener.
+     */
+    public List<TestSensorEvent> getCollectedEvents() {
+        synchronized (mCollectedEvents){
+            return Collections.unmodifiableList((List<TestSensorEvent>) mCollectedEvents.clone());
+        }
+    }
+
+    /**
+     * Clears the internal list of collected {@link TestSensorEvent}s.
+     */
+    public void clearEvents() {
+        synchronized (mCollectedEvents) {
+            mCollectedEvents.clear();
+        }
+    }
+
+
+    /**
+     * Utility method to log the collected events to a file.
+     * It will overwrite the file if it already exists, the file is created in a relative directory
+     * named 'events' under the sensor test directory (part of external storage).
+     */
+    public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs,
+            long testStartTimeMs, long testStopTimeMs)
+        throws IOException {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
+        builder.append("SamplingRateOverloaded=")
+                .append(mEnvironment.isSensorSamplingRateOverloaded()).append(", ");
+        builder.append("RequestedSamplingPeriod=")
+                .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
+        builder.append("MaxReportLatency=")
+                .append(mEnvironment.getMaxReportLatencyUs()).append("us, ");
+        builder.append("StartedTimestamp=")
+                .append(testStartTimeMs).append("ms, ");
+        builder.append("StoppedTimestamp=")
+                .append(testStopTimeMs).append("ms");
+        synchronized (mCollectedEvents) {
+            int i = 0, j = 0;
+            while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
+                if (mCollectedEvents.get(i).receivedTimestamp <
+                        mTimeStampFlushCompleteEvents.get(j)) {
+                    TestSensorEvent event = mCollectedEvents.get(i);
+                    if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
+                            event.receivedTimestamp/1000000) {
+                        builder.append("\n");
+                        builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
+                        deviceWakeUpTimeMs = -1;
+                    }
+                    builder.append("\n");
+                    builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+                    builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+                        append("us, ");
+                    builder.append("Accuracy=").append(event.accuracy).append(", ");
+                    builder.append("Values=").append(Arrays.toString(event.values));
+                    ++i;
+                } else {
+                    builder.append("\n");
+                    builder.append("ReceivedTimestamp=")
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+                    .append("us Flush complete Event");
+                    ++j;
+                }
+            }
+            for (;i < mCollectedEvents.size(); ++i) {
+                TestSensorEvent event = mCollectedEvents.get(i);
+                if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
+                        event.receivedTimestamp/1000000) {
+                    builder.append("\n");
+                    builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
+                    deviceWakeUpTimeMs = -1;
+                }
+                builder.append("\n");
+                builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+                    append("us, ");
+                builder.append("Accuracy=").append(event.accuracy).append(", ");
+                builder.append("Values=").append(Arrays.toString(event.values));
+            }
+            for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
+                builder.append("\n");
+                builder.append("ReceivedTimestamp=")
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+                    .append("us Flush complete Event");
+            }
+        }
+
+        File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
+        File logFile = new File(eventsDirectory, fileName);
+        FileWriter fileWriter = new FileWriter(logFile, false /* append */);
+        try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
+            writer.write(builder.toString());
+        }
+    }
+
+    /**
+     * Wait for {@link #onFlushCompleted(Sensor)} to be called.
+     *
+     * A wake lock may be acquired at the return if operation is successful. Do
+     * {@link releaseWakeLock()} if the wakelock is not necessary.
+     *
+     * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
+     */
+    public void waitForFlushComplete(CountDownLatch latch,
+                                      boolean clearCollectedEvents) throws InterruptedException {
+        if (clearCollectedEvents) {
+            clearEvents();
+        }
+        try {
+            String message = SensorCtsHelper.formatAssertionMessage(
+                    "WaitForFlush",
+                    mEnvironment,
+                    "timeout=%dus",
+                    FLUSH_TIMEOUT_US);
+            Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
+        } finally {
+            synchronized (mFlushLatches) {
+                mFlushLatches.remove(latch);
+            }
+        }
+    }
+
+    /**
+     * Collect a specific number of {@link TestSensorEvent}s.
+     *
+     * A wake lock may be acquired at the return if operation is successful. Do
+     * {@link releaseWakeLock()} if the wakelock is not necessary.
+     *
+     * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
+     */
+    public void waitForEvents(CountDownLatch latch, int eventCount,
+                               boolean clearCollectedEvents) throws InterruptedException {
+        if (clearCollectedEvents) {
+            clearEvents();
+        }
+        try {
+            long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
+            // timeout is 2 * event count * expected period + batch timeout + default wait
+            // we multiply by two as not to raise an error in this function even if the events are
+            // streaming at a lower rate than expected, as long as it's not streaming twice as slow
+            // as expected
+            long timeoutUs = (2 * eventCount * samplingPeriodUs)
+                    + mEnvironment.getMaxReportLatencyUs()
+                    + EVENT_TIMEOUT_US;
+            boolean success = latch.await(timeoutUs, TimeUnit.MICROSECONDS);
+            if (!success) {
+                String message = SensorCtsHelper.formatAssertionMessage(
+                        "WaitForEvents",
+                        mEnvironment,
+                        "requested=%d, received=%d, timeout=%dus",
+                        eventCount,
+                        eventCount - latch.getCount(),
+                        timeoutUs);
+                Assert.fail(message);
+            }
+        } finally {
+            synchronized (mEventLatches) {
+                mEventLatches.remove(latch);
+            }
+        }
+    }
+
+    /**
+     * Collect {@link TestSensorEvent} for a specific duration.
+     */
+    public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
+        SensorCtsHelper.sleep(duration, timeUnit);
+    }
+
+    /**
+     * Asserts that sensor events arrived in the proper thread if a {@link Handler} was associated
+     * with the current instance.
+     *
+     * If no events were received this assertion will be evaluated to {@code true}.
+     */
+    public void assertEventsReceivedInHandler() {
+        int eventsOutsideHandler = mEventsReceivedOutsideHandler.get();
+        String message = String.format(
+                "Events arrived outside the associated Looper. Expected=0, Found=%d",
+                eventsOutsideHandler);
+        Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
+    }
+
+    public void releaseWakeLock() {
+        if (mTestSensorEventListenerWakeLock.isHeld()) {
+            mTestSensorEventListenerWakeLock.release();
+        }
+    }
+
+    /**
+     * Keeps track of the number of events that arrived in a different {@link Looper} than the one
+     * associated with the {@link TestSensorEventListener}.
+     */
+    private void checkHandler() {
+        if (mHandler != null && mHandler.getLooper() != Looper.myLooper()) {
+            mEventsReceivedOutsideHandler.incrementAndGet();
+        }
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
rename to tests/sensor/src/android/hardware/cts/helpers/TestSensorManager.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java b/tests/sensor/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
rename to tests/sensor/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/AbstractMeanVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/FrequencyVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/GyroscopeIntegrationVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/GyroscopeIntegrationVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/GyroscopeIntegrationVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/GyroscopeIntegrationVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerification.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerification.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerification.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerificationTest.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerificationTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerificationTest.java
rename to tests/sensor/src/android/hardware/cts/helpers/sensorverification/TimestampClockSourceVerificationTest.java
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/AndroidTest.xml
index 930bcac..038d0d0 100644
--- a/tests/signature/AndroidTest.xml
+++ b/tests/signature/AndroidTest.xml
@@ -36,6 +36,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.signature.cts" />
-        <option name="runtime-hint" value="1m11s" />
+        <option name="runtime-hint" value="7m11s" />
     </test>
 </configuration>
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index d27a83b..3d67cd8 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -18,6 +18,9 @@
 include $(CLEAR_VARS)
 
 # current api, in XML format.
+# NOTE: the output XML file is also used
+# in //cts/hostsidetests/devicepolicy/AndroidTest.xml
+# by com.android.cts.managedprofile.CurrentApiHelper
 # ============================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := cts-current-api
diff --git a/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 0cba3b4..35e97d0 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -31,6 +31,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -759,7 +760,12 @@
                             field.toReadableString(mAbsoluteClassName),
                             "Non-compatible field modifiers found when looking for " +
                             field.toSignatureString());
-                } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
+                } else if (!checkFieldValueCompliance(field, f)) {
+                    mResultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+                            field.toReadableString(mAbsoluteClassName),
+                            "Incorrect field value found when looking for " +
+                            field.toSignatureString());
+                }else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
                     // type name does not match, but this might be a generic
                     String genericTypeName = null;
                     Type type = f.getGenericType();
@@ -787,6 +793,194 @@
     }
 
     /**
+     * Checks whether the field values are compatible.
+     *
+     * @param apiField The field as defined by the platform API.
+     * @param deviceField The field as defined by the device under test.
+     */
+    private boolean checkFieldValueCompliance(JDiffField apiField, Field deviceField)
+            throws IllegalAccessException {
+        if ((apiField.mModifier & Modifier.FINAL) == 0 ||
+                (apiField.mModifier & Modifier.STATIC) == 0) {
+            // Only final static fields can have fixed values.
+            return true;
+        }
+        if (apiField.getValueString() == null) {
+            // If we don't define a constant value for it, then it can be anything.
+            return true;
+        }
+        // Some fields may be protected or package-private
+        deviceField.setAccessible(true);
+        switch(apiField.mFieldType) {
+            case "byte":
+                return Objects.equals(apiField.getValueString(),
+                        Byte.toString(deviceField.getByte(null)));
+            case "char":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getChar(null)));
+            case "short":
+                return Objects.equals(apiField.getValueString(),
+                        Short.toString(deviceField.getShort(null)));
+            case "int":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getInt(null)));
+            case "long":
+                return Objects.equals(apiField.getValueString(),
+                        Long.toString(deviceField.getLong(null)) + "L");
+            case "float":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                            Float.toString(deviceField.getFloat(null)), "f"));
+            case "double":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                            Double.toString(deviceField.getDouble(null)), ""));
+            case "boolean":
+                return Objects.equals(apiField.getValueString(),
+                        Boolean.toString(deviceField.getBoolean(null)));
+            case "java.lang.String":
+                String value = apiField.getValueString();
+                // Remove the quotes the value string is wrapped in
+                value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
+                return Objects.equals(value, deviceField.get(null));
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * Canonicalize the string representation of floating point numbers.
+     *
+     * This needs to be kept in sync with the doclava canonicalization.
+     */
+    private static final String canonicalizeFloatingPoint(String val, String suffix) {
+        if (val.equals("Infinity")) {
+            return "(1.0" + suffix + "/0.0" + suffix + ")";
+        } else if (val.equals("-Infinity")) {
+            return "(-1.0" + suffix + "/0.0" + suffix + ")";
+        } else if (val.equals("NaN")) {
+            return "(0.0" + suffix + "/0.0" + suffix + ")";
+        }
+
+        String str = val.toString();
+        if (str.indexOf('E') != -1) {
+            return str + suffix;
+        }
+
+        // 1.0 is the only case where a trailing "0" is allowed.
+        // 1.00 is canonicalized as 1.0.
+        int i = str.length() - 1;
+        int d = str.indexOf('.');
+        while (i >= d + 2 && str.charAt(i) == '0') {
+            str = str.substring(0, i--);
+        }
+        return str + suffix;
+    }
+
+
+    // This unescapes the string format used by doclava and so needs to be kept in sync with any
+    // changes made to that format.
+    private static String unescapeFieldStringValue(String str) {
+        final int N = str.length();
+
+        // If there's no special encoding strings in the string then just return it.
+        if (str.indexOf('\\') == -1) {
+            return str;
+        }
+
+        final StringBuilder buf = new StringBuilder(str.length());
+        char escaped = 0;
+        final int START = 0;
+        final int CHAR1 = 1;
+        final int CHAR2 = 2;
+        final int CHAR3 = 3;
+        final int CHAR4 = 4;
+        final int ESCAPE = 5;
+        int state = START;
+
+        for (int i=0; i<N; i++) {
+            final char c = str.charAt(i);
+            switch (state) {
+                case START:
+                    if (c == '\\') {
+                        state = ESCAPE;
+                    } else {
+                        buf.append(c);
+                    }
+                    break;
+                case ESCAPE:
+                    switch (c) {
+                        case '\\':
+                            buf.append('\\');
+                            state = START;
+                            break;
+                        case 't':
+                            buf.append('\t');
+                            state = START;
+                            break;
+                        case 'b':
+                            buf.append('\b');
+                            state = START;
+                            break;
+                        case 'r':
+                            buf.append('\r');
+                            state = START;
+                            break;
+                        case 'n':
+                            buf.append('\n');
+                            state = START;
+                            break;
+                        case 'f':
+                            buf.append('\f');
+                            state = START;
+                            break;
+                        case '\'':
+                            buf.append('\'');
+                            state = START;
+                            break;
+                        case '\"':
+                            buf.append('\"');
+                            state = START;
+                            break;
+                        case 'u':
+                            state = CHAR1;
+                            escaped = 0;
+                            break;
+                    }
+                    break;
+                case CHAR1:
+                case CHAR2:
+                case CHAR3:
+                case CHAR4:
+                    escaped <<= 4;
+                    if (c >= '0' && c <= '9') {
+                        escaped |= c - '0';
+                    } else if (c >= 'a' && c <= 'f') {
+                        escaped |= 10 + (c - 'a');
+                    } else if (c >= 'A' && c <= 'F') {
+                        escaped |= 10 + (c - 'A');
+                    } else {
+                        throw new RuntimeException(
+                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
+                                + str + "\"");
+                    }
+                    if (state == CHAR4) {
+                        buf.append(escaped);
+                        state = START;
+                    } else {
+                        state++;
+                    }
+                    break;
+            }
+        }
+        if (state != START) {
+            throw new RuntimeException("unfinished escape sequence: " + str);
+        }
+        return buf.toString();
+    }
+
+
+    /**
      * Finds the reflected field specified by the field description.
      *
      * @param field the field description to find
diff --git a/tests/signature/tests/Android.mk b/tests/signature/tests/Android.mk
index f17ee47..0c9c24c 100644
--- a/tests/signature/tests/Android.mk
+++ b/tests/signature/tests/Android.mk
@@ -21,6 +21,6 @@
 
 LOCAL_MODULE := signature-tests
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed signature-hostside
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed signature-hostside
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/signature/tests/run_unit_tests.sh b/tests/signature/tests/run_unit_tests.sh
index 19ce8d2..02f914c 100755
--- a/tests/signature/tests/run_unit_tests.sh
+++ b/tests/signature/tests/run_unit_tests.sh
@@ -36,7 +36,7 @@
 fi;
 
 JAR_DIR=${ANDROID_BUILD_TOP}/out/host/$OS/framework
-JARS="tradefed-prebuilt.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
+JARS="tradefed.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
 
 for JAR in $JARS; do
     checkFile ${JAR_DIR}/${JAR}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
index 9cd84c7..6e477ae 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
@@ -252,7 +252,7 @@
                 "public transient java.lang.String TRANSIENT_FIELD");
     }
 
-    public void testPacakgeField() {
+    public void testPackageField() {
         JDiffClassDescription clz = createNormalClass();
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "PACAKGE_FIELD", "java.lang.String", 0, VALUE);
@@ -279,6 +279,30 @@
         assertEquals(field.toSignatureString(), "protected java.lang.String PROTECTED_FIELD");
     }
 
+    public void testFieldValue() {
+        JDiffClassDescription clz = createNormalClass();
+        JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+                "VALUE_FIELD", "java.lang.String",
+                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"\\u2708\"");
+        clz.addField(field);
+        clz.checkSignatureCompliance();
+        assertEquals(field.toSignatureString(),
+                "public static final java.lang.String VALUE_FIELD");
+    }
+
+    public void testFieldValueChanged() {
+        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD);
+        JDiffClassDescription clz = createNormalClass(observer);
+        JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+                "VALUE_FIELD", "java.lang.String",
+                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"&#9992;\"");
+        clz.addField(field);
+        clz.checkSignatureCompliance();
+        assertEquals(field.toSignatureString(),
+                "public static final java.lang.String VALUE_FIELD");
+        observer.validate();
+    }
+
     public void testInnerClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
                 "android.signature.cts.tests.data", "NormalClass.InnerClass", new NoFailures());
@@ -311,7 +335,8 @@
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT);
         clz.addMethod(
-                new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+                new JDiffClassDescription.JDiffMethod("doSomething",
+                    Modifier.PUBLIC | Modifier.ABSTRACT, "void"));
         clz.checkSignatureCompliance();
         assertEquals(clz.toSignatureString(), "public interface NormalClass.InnerInterface");
     }
@@ -322,7 +347,8 @@
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
         clz.addMethod(
-                new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+                new JDiffClassDescription.JDiffMethod("doSomething",
+                    Modifier.ABSTRACT| Modifier.PUBLIC, "void"));
         clz.checkSignatureCompliance();
         assertEquals(clz.toSignatureString(), "public interface NormalInterface");
     }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
index 5acd696..db47967 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
@@ -47,6 +47,7 @@
     public static String STATIC_FIELD;
     public volatile String VOLATILE_FIELD;
     public transient String TRANSIENT_FIELD;
+    public final static String VALUE_FIELD = "\u2708";
     String PACAKGE_FIELD;
     private String PRIVATE_FIELD;
     protected String PROTECTED_FIELD;
diff --git a/tests/simplecpu/Android.mk b/tests/simplecpu/Android.mk
index 7183b2c..cb13016 100644
--- a/tests/simplecpu/Android.mk
+++ b/tests/simplecpu/Android.mk
@@ -21,7 +21,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctscpu_jni
 
diff --git a/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java b/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java
index 9f72d31..3e60b6d 100644
--- a/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java
+++ b/tests/simplecpu/src/android/simplecpu/cts/SimpleCpuTest.java
@@ -16,9 +16,9 @@
 
 package android.simplecpu.cts;
 
-import android.cts.util.CtsAndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/tests/systemAppTest/test/Android.mk b/tests/systemAppTest/test/Android.mk
index 9be491c..e15d259 100644
--- a/tests/systemAppTest/test/Android.mk
+++ b/tests/systemAppTest/test/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_APPS_PRIVILEGED)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/accounts/AndroidManifest.xml b/tests/tests/accounts/AndroidManifest.xml
index d882690..a698349 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>
@@ -56,6 +58,8 @@
                        android:value="1" />
 
         </service>
+        <meta-data android:name="android.accounts.SupportedLoginTypes"
+                android:value="com.google;com.facebook;com.twitter" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
index c32f89f..ba398c8 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
@@ -41,6 +41,16 @@
             <meta-data android:name="android.accounts.AccountAuthenticator"
                        android:resource="@xml/standard_authenticator" />
         </service>
+
+        <service
+                android:name=".DefaultAccountAuthService"
+                android:exported="false">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/default_authenticator" />
+        </service>
 <!--
         <service android:name=".CustomAccountAuthService" android:exported="false">
             <intent-filter>
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/default_authenticator.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/default_authenticator.xml
new file mode 100644
index 0000000..d920f49
--- /dev/null
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/default_authenticator.xml
@@ -0,0 +1,28 @@
+<?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.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="android.accounts.test.default"
+    android:icon="@drawable/ic_cts_selected"
+    android:smallIcon="@drawable/ic_cts_minitab_selected"
+    android:label="@string/label"
+/>
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/DefaultAccountAuthService.java b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/DefaultAccountAuthService.java
new file mode 100644
index 0000000..b2dca9d
--- /dev/null
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/DefaultAccountAuthService.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.accounts.cts.unaffiliated;
+
+import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.TestDefaultAuthenticator;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a basic Mock Service for wrapping the TestDefaultAuthenticator
+ */
+public class DefaultAccountAuthService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        TestDefaultAuthenticator auth =
+                new TestDefaultAuthenticator(this, Fixtures.TYPE_DEFAULT);
+        return auth.getIBinder();
+    }
+}
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..dfa5945 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
@@ -28,12 +28,14 @@
 
     public static final String TYPE_CUSTOM = "android.accounts.test.custom";
     public static final String TYPE_STANDARD = "android.accounts.test.standard";
+    public static final String TYPE_DEFAULT = "android.accounts.test.default";
 
     public static final String TYPE_STANDARD_UNAFFILIATED =
             "android.accounts.test.standard.unaffiliated";
 
     public static final String PREFIX_TOKEN = "token:";
     public static final String PREFIX_PASSWORD = "password:";
+    public static final String PREFIX_STATUS_TOKEN = "status_token:";
 
     public static final String SUFFIX_NAME_FIXTURE = "fixture.com";
     public static final String SUFFIX_NAME_TEST = "test.com";
@@ -52,6 +54,10 @@
             PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
             TYPE_STANDARD_UNAFFILIATED);
 
+    public static final Account ACCOUNT_DEFAULT = new Account(
+            PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
+            TYPE_DEFAULT);
+
     public static List<String> getFixtureAccountNames() {
         List<String> accountNames = new ArrayList<>(accountNamePrefixes.length);
         for (String prefix : accountNamePrefixes) {
@@ -70,5 +76,9 @@
     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";
+    public static final String ACCOUNT_STATUS_TOKEN_UNAFFILIATED =
+            "android.accounts.cts.unaffiliated.account.status.token";
+
     private Fixtures() {}
 }
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java b/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java
index 1fac1ea..46da211 100644
--- a/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java
@@ -26,18 +26,22 @@
 import android.accounts.cts.common.tx.GetAuthTokenLabelTx;
 import android.accounts.cts.common.tx.GetAuthTokenTx;
 import android.accounts.cts.common.tx.HasFeaturesTx;
+import android.accounts.cts.common.tx.StartAddAccountSessionTx;
+import android.accounts.cts.common.tx.StartUpdateCredentialsSessionTx;
 import android.accounts.cts.common.tx.UpdateCredentialsTx;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 
 import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class TestAccountAuthenticator extends AbstractAccountAuthenticator {
 
     private final String mAccountType;
     private final Context mContext;
     private volatile int mCounter = 0;
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
 
     public TestAccountAuthenticator(Context context, String accountType) {
         super(context);
@@ -87,14 +91,7 @@
             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);
+            fillDefaultError(result, options);
         }
 
         try {
@@ -140,15 +137,7 @@
             result.putParcelable(AccountManager.KEY_INTENT, intent);
         } else {
             // fill with error
-            // 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);
+            fillDefaultError(result, options);
         }
 
         try {
@@ -204,14 +193,7 @@
 
         } 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);
+            fillDefaultError(result, options);
         }
 
         try {
@@ -264,15 +246,7 @@
             result.putParcelable(AccountManager.KEY_INTENT, intent);
         } else {
             // fill with error
-            // 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);
+            fillDefaultError(result, options);
         }
 
         try {
@@ -322,5 +296,111 @@
             }
         }
     }
+
+    /**
+     * Start add account flow of the specified accountType to authenticate user.
+     * This implementation works with AccountManagerUnaffiliatedAuthenticatorTests
+     * to test that portion of the default implementation of the
+     * {@link AccountManager#finishSession} API when implementers of
+     * {@link android.accounts.AbstractAccountAuthenticator} override only
+     * {@link AccountManager#startAddAccountSession} but not
+     * {@link AccountManager#finishSession}.
+     */
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        AuthenticatorContentProvider.setTx(new StartAddAccountSessionTx(
+                accountType, authTokenType, requiredFeatures, options));
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            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,
+                    Fixtures.ACCOUNT_STATUS_TOKEN_UNAFFILIATED);
+            result.putString(AccountManager.KEY_PASSWORD, "doesn't matter");
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else {
+            // fill with error
+            fillDefaultError(result, options);
+        }
+
+        return result;
+    }
+
+    /**
+     * Start update credentials flow to re-auth user without updating locally stored
+     * credentials for an account.
+     * This implementation works with AccountManagerUnaffiliatedAuthenticatorTests
+     * to test that portion of the default implementation of the
+     * {@link AccountManager#finishSession} API when implementers of
+     * {@link android.accounts.AbstractAccountAuthenticator} override only
+     * {@link AccountManager#startUpdateCredentialsSession} but not
+     * {@link AccountManager#finishSession}.
+     */
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options)
+            throws NetworkErrorException {
+
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        AuthenticatorContentProvider.setTx(new StartUpdateCredentialsSessionTx(
+                account, authTokenType, options));
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            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,
+                    Fixtures.ACCOUNT_STATUS_TOKEN_UNAFFILIATED);
+            result.putString(AccountManager.KEY_PASSWORD, "doesn't matter");
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else {
+            // fill with error
+            fillDefaultError(result, options);
+        }
+        return result;
+    }
+
+    private void fillDefaultError(Bundle result, Bundle options) {
+        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);
+    }
 }
 
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java b/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java
new file mode 100644
index 0000000..15a60d7
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java
@@ -0,0 +1,128 @@
+/*
+ * 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.accounts.cts.common;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.accounts.cts.common.tx.AddAccountTx;
+import android.accounts.cts.common.tx.UpdateCredentialsTx;
+import android.content.Context;
+import android.os.Bundle;
+
+
+/**
+ * This authenticator is to test the default implementation of
+ * AbstractAccountAuthenticator.
+ */
+public class TestDefaultAuthenticator extends AbstractAccountAuthenticator {
+    private final String mAccountType;
+    private final Context mContext;
+
+    public TestDefaultAuthenticator(Context context, String accountType) {
+        super(context);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        throw new UnsupportedOperationException(
+                "editProperties should not be tested using the TestDefaultAuthenticator");
+    }
+
+    @Override
+    public Bundle addAccount(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+        } else {
+            accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                    + Fixtures.SUFFIX_NAME_FIXTURE;
+        }
+
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+        AuthenticatorContentProvider.setTx(
+                new AddAccountTx(accountType, authTokenType, requiredFeatures, options, result));
+        return result;
+    }
+
+    @Override
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "confirmCredentials should not be tested using the TestDefaultAuthenticator");
+    }
+
+    @Override
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "getAuthToken should not be tested using the TestDefaultAuthenticator");
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        throw new UnsupportedOperationException(
+                "getAuthTokenLabel should not be tested using the TestDefaultAuthenticator");
+    }
+
+    @Override
+    public Bundle updateCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+        AuthenticatorContentProvider.setTx(
+                new UpdateCredentialsTx(account, authTokenType, options, result));
+        return result;
+    }
+
+    @Override
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String[] features) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "hasFeatures should not be tested using the TestDefaultAuthenticator");
+    }
+}
+
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
new file mode 100644
index 0000000..11e30b9
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
@@ -0,0 +1,3 @@
+package android.accounts.cts.common.tx;
+
+parcelable StartAddAccountSessionTx;
\ No newline at end of file
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
new file mode 100644
index 0000000..4077fae
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
@@ -0,0 +1,65 @@
+package android.accounts.cts.common.tx;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StartAddAccountSessionTx implements Parcelable {
+
+    public static final Parcelable.Creator<StartAddAccountSessionTx> CREATOR =
+            new Parcelable.Creator<StartAddAccountSessionTx>() {
+
+        @Override
+        public StartAddAccountSessionTx createFromParcel(Parcel in) {
+            return new StartAddAccountSessionTx(in);
+        }
+
+        @Override
+        public StartAddAccountSessionTx[] newArray(int size) {
+            return new StartAddAccountSessionTx[size];
+        }
+    };
+
+    public final String accountType;
+    public final String authTokenType;
+    public final List<String> requiredFeatures = new ArrayList<>();
+    public final Bundle options;
+
+    private StartAddAccountSessionTx(Parcel in) {
+        accountType = in.readString();
+        authTokenType = in.readString();
+        in.readStringList(requiredFeatures);
+        options = in.readBundle();
+    }
+
+    public StartAddAccountSessionTx(
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) {
+        this.accountType = accountType;
+        this.authTokenType = authTokenType;
+        if (requiredFeatures != null) {
+            for (String feature : requiredFeatures) {
+                this.requiredFeatures.add(feature);
+            }
+        }
+        this.options = options;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(accountType);
+        out.writeString(authTokenType);
+        out.writeStringList(requiredFeatures);
+        out.writeBundle(options);
+    }
+}
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.aidl b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.aidl
new file mode 100644
index 0000000..a9bedb2
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.aidl
@@ -0,0 +1,3 @@
+package android.accounts.cts.common.tx;
+
+parcelable StartUpdateCredentialsSessionTx;
\ No newline at end of file
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.java b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.java
new file mode 100644
index 0000000..a7574d1
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.java
@@ -0,0 +1,54 @@
+package android.accounts.cts.common.tx;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class StartUpdateCredentialsSessionTx implements Parcelable {
+
+    public static final Parcelable.Creator<StartUpdateCredentialsSessionTx> CREATOR =
+            new Parcelable.Creator<StartUpdateCredentialsSessionTx>() {
+
+                @Override
+                public StartUpdateCredentialsSessionTx createFromParcel(Parcel in) {
+                    return new StartUpdateCredentialsSessionTx(in);
+                }
+
+                @Override
+                public StartUpdateCredentialsSessionTx[] newArray(int size) {
+                    return new StartUpdateCredentialsSessionTx[size];
+                }
+            };
+
+    public final Account account;
+    public final String authTokenType;
+    public final Bundle options;
+
+    private StartUpdateCredentialsSessionTx(Parcel in) {
+        account = in.readParcelable(null);
+        authTokenType = in.readString();
+        options = in.readBundle();
+    }
+
+    public StartUpdateCredentialsSessionTx(
+            Account account,
+            String authTokenType,
+            Bundle options) {
+        this.account = account;
+        this.authTokenType = authTokenType;
+        this.options = options;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(account, flags);
+        out.writeString(authTokenType);
+        out.writeBundle(options);
+    }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AbstractAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AbstractAuthenticatorTests.java
new file mode 100644
index 0000000..725e7a5
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AbstractAuthenticatorTests.java
@@ -0,0 +1,304 @@
+/*
+ * 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.accounts.cts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.AuthenticatorContentProvider;
+import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.tx.AddAccountTx;
+import android.accounts.cts.common.tx.UpdateCredentialsTx;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests for AccountManager and AbstractAccountAuthenticator. This is to test
+ * default implementation of account session api in
+ * {@link android.accounts.AbstractAccountAuthenticator}.
+ * <p>
+ * You can run those unit tests with the following command line:
+ * <p>
+ *  adb shell am instrument
+ *   -e debug false -w
+ *   -e class android.accounts.cts.AbstractAuthenticatorTests
+ * android.accounts.cts/android.support.test.runner.AndroidJUnitRunner
+ */
+public class AbstractAuthenticatorTests extends AndroidTestCase {
+
+    private AccountManager mAccountManager;
+    private ContentProviderClient mProviderClient;
+
+    @Override
+    public void setUp() throws Exception {
+        // bind to the diagnostic service and set it up.
+        mAccountManager = AccountManager.get(getContext());
+        ContentResolver resolver = getContext().getContentResolver();
+        mProviderClient = resolver.acquireContentProviderClient(
+                AuthenticatorContentProvider.AUTHORITY);
+    }
+
+    public void tearDown() throws RemoteException {
+        mProviderClient.release();
+    }
+
+    /**
+     * 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_DEFAULT,
+                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));
+    }
+
+
+    /**
+     * Tests startUpdateCredentialsSession default implementation. An encrypted session
+     * bundle should always be returned without password or status token.
+     */
+    public void testStartUpdateCredentialsSessionDefaultImpl()
+            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.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_DEFAULT,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate no auth token in 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(Fixtures.KEY_ACCOUNT_NAME));
+    }
+
+    /**
+     * Tests finishSession default implementation with default startAddAccountSession.
+     * Only account name and account type should be returned as a bundle.
+     */
+    public void testFinishSessionAndStartAddAccountSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException,
+            RemoteException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        // First obtain an encrypted session bundle from startAddAccountSession(...) default
+        // implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_DEFAULT,
+                null /* authTokenType */,
+                null /* requiredFeatures */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Assert that result contains a non-null session bundle.
+        Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(escrowBundle);
+
+        // Now call finishSession(...) with the session bundle we just obtained.
+        future = mAccountManager.finishSession(
+                escrowBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate that parameters are passed to addAccount(...) correctly in default finishSession
+        // implementation.
+        Bundle providerBundle = mProviderClient.call(
+                AuthenticatorContentProvider.METHOD_GET,
+                null /* arg */,
+                null /* extras */);
+        providerBundle.setClassLoader(AddAccountTx.class.getClassLoader());
+        AddAccountTx addAccountTx = providerBundle
+                .getParcelable(AuthenticatorContentProvider.KEY_TX);
+        assertNotNull(addAccountTx);
+
+        // Assert parameters has been passed to addAccount(...) correctly
+        assertEquals(Fixtures.TYPE_DEFAULT, addAccountTx.accountType);
+        assertNull(addAccountTx.authTokenType);
+
+        validateSystemOptions(addAccountTx.options);
+        // Validate options
+        assertNotNull(addAccountTx.options);
+        assertEquals(accountName, addAccountTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+        // Validate features.
+        assertEquals(0, addAccountTx.requiredFeatures.size());
+
+        // Assert returned result contains correct account name, account type and null auth token.
+        assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(Fixtures.TYPE_DEFAULT, result.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests finishSession default implementation with default startUpdateCredentialsSession.
+     * Only account name and account type should be returned as a bundle.
+     */
+    public void testFinishSessionAndStartUpdateCredentialsSessionDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException,
+            RemoteException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+        // First obtain an encrypted session bundle from startUpdateCredentialsSession(...) default
+        // implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_DEFAULT,
+                null /* authTokenTYpe */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Assert that result contains a non-null session bundle.
+        Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(escrowBundle);
+
+        // Now call finishSession(...) with the session bundle we just obtained.
+        future = mAccountManager.finishSession(
+                escrowBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        // Validate that parameters are passed to updateCredentials(...) correctly in default
+        // finishSession implementation.
+        Bundle providerBundle = mProviderClient.call(
+                AuthenticatorContentProvider.METHOD_GET,
+                null /* arg */,
+                null /* extras */);
+        providerBundle.setClassLoader(UpdateCredentialsTx.class.getClassLoader());
+        UpdateCredentialsTx updateCredentialsTx = providerBundle
+                .getParcelable(AuthenticatorContentProvider.KEY_TX);
+        assertNotNull(updateCredentialsTx);
+
+        // Assert parameters has been passed to updateCredentials(...) correctly
+        assertEquals(Fixtures.ACCOUNT_DEFAULT, updateCredentialsTx.account);
+        assertNull(updateCredentialsTx.authTokenType);
+
+        validateSystemOptions(updateCredentialsTx.options);
+        // Validate options
+        assertNotNull(updateCredentialsTx.options);
+        assertEquals(accountName, updateCredentialsTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        // Assert returned result contains correct account name, account type and null auth token.
+        assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(Fixtures.TYPE_DEFAULT, result.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    private void validateSystemOptions(Bundle options) {
+        assertNotNull(options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME));
+        assertTrue(options.containsKey(AccountManager.KEY_CALLER_UID));
+        assertTrue(options.containsKey(AccountManager.KEY_CALLER_PID));
+    }
+
+    private void validateNullPasswordAndStatusToken(Bundle result) {
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested default implementation.
+     * A bundle with boolean false should be returned.
+     */
+    public void testIsCredentialsUpdateSuggestedDefaultImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException,
+            RemoteException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Account account = new Account(accountName, Fixtures.TYPE_DEFAULT);
+        String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName;
+
+        AccountManagerFuture<Boolean> future = mAccountManager.isCredentialsUpdateSuggested(
+                account,
+                statusToken,
+                null /* callback */,
+                null /* handler */);
+
+        assertFalse(future.getResult());
+        assertTrue(future.isDone());
+    }
+}
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..698189a 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -24,12 +24,15 @@
 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;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.StrictMode;
 import android.platform.test.annotations.Presubmit;
@@ -62,6 +65,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 +103,15 @@
     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";
+
+    public static final String KEY_CIPHER = "cipher";
+    public static final String KEY_MAC = "mac";
+
     private static MockAccountAuthenticator mockAuthenticator;
     private static final int LATCH_TIMEOUT_MS = 500;
     private static AccountManager am;
@@ -127,6 +141,9 @@
 
         USERDATA_BUNDLE.putString(USERDATA_NAME_1, USERDATA_VALUE_1);
 
+        SESSION_BUNDLE.putString(SESSION_DATA_NAME_1, SESSION_DATA_VALUE_1);
+        SESSION_BUNDLE.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+
         getMockAuthenticator(mContext);
 
         am = AccountManager.get(mContext);
@@ -673,19 +690,18 @@
     public void testAccountRenameAndGetPreviousName()
             throws OperationCanceledException, AuthenticatorException, IOException {
         // Add a first account
-        boolean result = am.addAccountExplicitly(ACCOUNT,
-                                ACCOUNT_PASSWORD,
-                                USERDATA_BUNDLE);
+
+        boolean result = am.addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, USERDATA_BUNDLE);
+
         assertTrue(result);
 
-        // Prior to a renmae, the previous name should be null.
+        // Prior to a rename, the previous name should be null.
         String nullName = am.getPreviousName(ACCOUNT);
         assertNull(nullName);
 
         final int expectedAccountsCount = getAccountsCount();
 
         Account renamedAccount = renameAccount(am, ACCOUNT, ACCOUNT_NEW_NAME);
-
         /*
          *  Make sure that the resultant renamed account has the correct name
          *  and is associated with the correct account type.
@@ -708,9 +724,10 @@
 
         assertEquals(ACCOUNT.name, am.getPreviousName(renamedAccount));
 
-       // Need to clean up
+        // Need to clean up
         assertTrue(removeAccount(am, renamedAccount, mActivity, null /* callback */).getBoolean(
                 AccountManager.KEY_BOOLEAN_RESULT));
+
     }
 
     /**
@@ -959,6 +976,27 @@
         assertEquals(mockAuthenticator.getLastTokenServed(), token);
     }
 
+    /*
+     * Test registration of visibility and then test subsequent visibility checks:
+     */
+    public void testRegisterVisibility()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        // TODO test visibility
+        am.addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */);
+
+        removeAccount(am, ACCOUNT, mActivity, null /* callback */);
+
+    }
+
+
+    /*
+     * Test Case for adding accounts explicitly with visibility
+     */
+    public void testAddAccountExplicitlyWithVisibility()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        // TODO update tests
+    }
+
     private static class BlockingGetAuthTokenFetcher implements TokenFetcher {
         private final Account mAccount;
 
@@ -2040,4 +2078,1960 @@
         }
     }
 
+    /**
+     * 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));
+        assertNull(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 = createOptionsWithAccountNameAndError(accountName);
+
+        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 provided 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 handled is provided 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 provided 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, // activity
+                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 = createOptionsWithAccountNameAndError(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) {
+                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);
+    }
+
+    /**
+     * Test a basic startUpdateCredentialsSession() which returns a bundle containing
+     * encrypted session bundle, account password and status token.
+     */
+    public void testStartUpdateCredentialsSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        validateStartUpdateCredentialsSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() with null session bundle. Only account
+     * password and status token should be included in the result as session
+     * bundle is not inspected.
+     */
+    public void testStartUpdateCredentialsSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putAll(OPTIONS_BUNDLE);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        validateStartUpdateCredentialsSessionParametersAndOptions(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));
+        assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(ACCOUNT_STATUS_TOKEN,
+                resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() 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 testStartUpdateCredentialsSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle options = new Bundle();
+        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 = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        validateStartUpdateCredentialsSessionParametersAndOptions(accountName, options);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession 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 testStartUpdateCredentialsSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        validateStartUpdateCredentialsSessionParametersAndOptions(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 startUpdateCredentialsSession 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 testStartUpdateCredentialsSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        validateStartUpdateCredentialsSessionParametersAndOptions(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 startUpdateCredentialsSession error case. AuthenticatorException is
+     * expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartUpdateCredentialsSessionError()
+            throws IOException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountNameAndError(accountName);
+
+        try {
+            startUpdateCredentialsSession(
+                    am,
+                    ACCOUNT,
+                    AUTH_TOKEN_TYPE,
+                    options,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("startUpdateCredentialsSession should throw AuthenticatorException in error.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() 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 provided or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandler(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() 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 provided or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() 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 provided or not.
+     */
+    public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession() error case with callback and
+     * handler. AuthenticatorException is expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException {
+        testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(null /* handler */);
+        testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartUpdateCredentialsSessionParametersAndOptions(accountName, options);
+
+                // Assert returned result
+                // Assert that auth token was stripped.
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+                validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        waitForLatch(latch);
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartUpdateCredentialsSessionParametersAndOptions(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();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                mActivity,
+                callback,
+                handler);
+
+        waitForLatch(latch);
+    }
+
+    private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountName(accountName);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                validateStartUpdateCredentialsSessionParametersAndOptions(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();
+            }
+        };
+
+        startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null,
+                callback,
+                handler);
+
+        waitForLatch(latch);
+    }
+
+    private void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Bundle options = createOptionsWithAccountNameAndError(accountName);
+
+        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 {
+            startUpdateCredentialsSession(
+                    am,
+                    ACCOUNT,
+                    AUTH_TOKEN_TYPE,
+                    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 startUpdateCredentialsSession(AccountManager am,
+            Account account,
+            String authTokenType,
+            Bundle options,
+            Activity activity,
+            AccountManagerCallback<Bundle> callback,
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Bundle> futureBundle = am.startUpdateCredentialsSession(
+                account,
+                authTokenType,
+                options,
+                activity,
+                callback,
+                handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    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) {
+        SESSION_BUNDLE.putString(Fixtures.KEY_ACCOUNT_NAME, 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 Bundle createOptionsWithAccountNameAndError(final String accountName) {
+        Bundle options = createOptionsWithAccountName(accountName);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+        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);
+        validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        validateOptions(null, mockAuthenticator.mOptionsFinishSession);
+    }
+
+    private void validateStartUpdateCredentialsSessionParametersAndOptions(
+            String accountName, Bundle options) {
+        // Assert parameters has been passed correctly
+        assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+        assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+        // Validate options
+        validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+                .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        // Validate system options
+        assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession
+                .getString(AccountManager.KEY_ANDROID_PACKAGE_NAME));
+
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsFinishSession);
+    }
+
+    private void validateIsCredentialsUpdateSuggestedParametersAndOptions(Account account) {
+        assertEquals(account, mockAuthenticator.getAccount());
+        assertEquals(ACCOUNT_STATUS_TOKEN, mockAuthenticator.getStatusToken());
+
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+        validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+    }
+
+    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));
+        // Assert password is not returned since cts test is not signed with system key
+        assertNull(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;
+    }
+
+    /**
+     * Tests a basic finishSession() with session bundle created by
+     * startAddAccountSession(...). A bundle containing account name and account
+     * type is expected.
+     */
+    public void testFinishSessionWithStartAddAccountSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a basic finishSession() with session bundle created by
+     * startUpdateCredentialsSession(...). A bundle containing account name and account
+     * type is expected.
+     */
+    public void testFinishSessionWithStartUpdateCredentialsSession()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startUpdateCredentialsSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession() with null session bundle. IllegalArgumentException
+     * is expected as session bundle cannot be null.
+     */
+    public void testFinishSessionWithNullSessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        try {
+            finishSession(
+                    am,
+                    null /* sessionBundle */,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentException when sessionBundle is null");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with empty session bundle. IllegalArgumentException
+     * is expected as session bundle would always contain something if it was
+     * processed properly by AccountManagerService.
+     */
+    public void testFinishSessionWithEmptySessionBundle()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        try {
+            finishSession(am,
+                    new Bundle(),
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentException when sessionBundle is empty");
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with sessionBundle not encrypted by the right key.
+     * AuthenticatorException is expected if AccountManagerService failed to
+     * decrypt the session bundle because of wrong key or crypto data was
+     * tampered.
+     */
+    public void testFinishSessionWithDecryptionError()
+            throws IOException, OperationCanceledException {
+        byte[] mac = new byte[] {
+                1, 1, 0, 0
+        };
+        byte[] cipher = new byte[] {
+                1, 0, 0, 1, 1
+        };
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putByteArray(KEY_MAC, mac);
+        sessionBundle.putByteArray(KEY_CIPHER, cipher);
+
+        try {
+            finishSession(am,
+                    sessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+        } catch (AuthenticatorException e) {
+
+        }
+    }
+
+    /**
+     * Tests finishSession() with sessionBundle invalid contents.
+     * AuthenticatorException is expected if AccountManagerService failed to
+     * decrypt the session bundle because of wrong key or crypto data was
+     * tampered.
+     */
+    public void testFinishSessionWithInvalidEncryptedContent()
+            throws IOException, OperationCanceledException {
+        byte[] mac = new byte[] {};
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putByteArray(KEY_MAC, mac);
+
+        try {
+            finishSession(am,
+                    sessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests a finishSession() when account type is not added to session bundle
+     * by startAddAccount(...) of authenticator. A bundle containing account
+     * name and account type should still be returned as AccountManagerSerivce
+     * will always add account type to the session bundle before encrypting it.
+     */
+    public void testFinishSessionFromStartAddAccountWithoutAccountType()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Create a session bundle without account type for MockAccountAuthenticator to return
+        SESSION_BUNDLE.remove(AccountManager.KEY_ACCOUNT_TYPE);
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when account type is not added to session bundle
+     * by startUpdateCredentialsSession(...) of authenticator. A bundle
+     * containing account name and account type should still be returned as
+     * AccountManagerSerivce will always add account type to the session bundle
+     * before encrypting it.
+     */
+    public void testFinishSessionFromStartUpdateCredentialsSessionWithoutAccountType()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Create a session bundle without account type for MockAccountAuthenticator to return
+        SESSION_BUNDLE.remove(AccountManager.KEY_ACCOUNT_TYPE);
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when a different account type is added to session bundle
+     * by startAddAccount(...) of authenticator. A bundle containing account
+     * name and the correct account type should be returned as AccountManagerSerivce
+     * will always overrides account type to the session bundle before encrypting it.
+     */
+    public void testFinishSessionFromStartAddAccountAccountTypeOverriden()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        SESSION_BUNDLE.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, correct type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests a finishSession() when a different account type is added to session bundle
+     * by startUpdateCredentialsSession(...) of authenticator. A bundle
+     * containing account name and the correct account type should be returned as
+     * AccountManagerSerivce will always override account type to the session bundle
+     * before encrypting it.
+     */
+    public void testFinishSessionFromStartUpdateCredentialsSessionAccountTypeOverriden()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // MockAccountAuthenticator to return
+        SESSION_BUNDLE.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startUpdateCredentialsSession(
+                am,
+                ACCOUNT,
+                AUTH_TOKEN_TYPE,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result containing account name, correct type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession with authenticator activity started. When additional
+     * info is needed from user for finishing the session and an Activity was
+     * provided by caller, the resolution intent will be started automatically.
+     * A bundle containing account name and type will be returned.
+     */
+    public void testFinishSessionIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert returned result containing account name, type but not auth token type.
+        validateAccountAndNoAuthTokenResult(resultBundle);
+    }
+
+    /**
+     * Tests finishSession with KEY_INTENT returned but not started
+     * automatically. When additional info is needed from user for finishing the
+     * session and no Activity was provided by caller, the resolution intent
+     * will not be started automatically. A bundle containing KEY_INTENT will be
+     * returned instead.
+     */
+    public void testFinishSessionWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        resultBundle = finishSession(
+                am,
+                encryptedSessionBundle,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+        validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+        // Assert returned result
+        Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(returnIntent);
+        assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+        assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+        assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+    }
+
+    /**
+     * Tests finishSession error case. AuthenticatorException is expected when
+     * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+     */
+    public void testFinishSessionError()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        Bundle sessionBundle = new Bundle();
+        String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+        sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+                AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        try {
+            finishSession(
+                    am,
+                    encryptedSessionBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("finishSession should throw AuthenticatorException in error case.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests finishSession() with callback and handler. A bundle containing
+     * account name and type should be returned via the callback regardless of
+     * whether a handler is provided.
+     */
+    public void testFinishSessionWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testFinishSessionWithCallbackAndHandler(null /* handler */);
+        testFinishSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() with callback and handler and activity started.
+     * When additional info is needed from user for finishing the session and an
+     * Activity was provided by caller, the resolution intent will be started
+     * automatically. A bundle containing account name and type will be returned
+     * via the callback regardless of if handler is provided or now.
+     */
+    public void testFinishSessionWithCallbackAndHandlerWithIntervene()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testFinishSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+        testFinishSessionWithCallbackAndHandlerWithIntervene(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() with callback and handler with KEY_INTENT
+     * returned. When additional info is needed from user for finishing the
+     * session and no Activity was provided by caller, the resolution intent
+     * will not be started automatically. A bundle containing KEY_INTENT will be
+     * returned instead via callback regardless of if handler is provided or not.
+     */
+    public void testFinishSessionWithCallbackAndHandlerWithReturnIntent()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testFinishSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+        testFinishSessionWithCallbackAndHandlerWithReturnIntent(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests finishSession() error case with callback and handler.
+     * AuthenticatorException is expected when
+     * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+     */
+    public void testFinishSessionErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException, AuthenticatorException {
+        testFinishSessionErrorWithCallbackAndHandler(null /* handler */);
+        testFinishSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+    }
+
+    private void testFinishSessionWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+                // Assert returned result containing account name, type but not auth token type.
+                validateAccountAndNoAuthTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private void testFinishSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+                // Assert returned result
+                assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+                // Assert returned result containing account name, type but not auth token type.
+                validateAccountAndNoAuthTokenResult(resultBundle);
+
+                latch.countDown();
+            }
+        };
+
+        finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private void testFinishSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+            @Override
+            public void run(AccountManagerFuture<Bundle> bundleFuture) {
+                Bundle resultBundle = getResultExpectNoException(bundleFuture);
+
+                // Assert parameters has been passed correctly
+                assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+                validateFinishSessionOptions(accountName, SESSION_BUNDLE);
+
+                // Assert returned result
+                Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+                assertNotNull(returnIntent);
+                assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+                assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+                assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+                assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+                latch.countDown();
+            }
+        };
+
+        finishSession(am, encryptedSessionBundle, null, callback, handler);
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private void testFinishSessionErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException, AuthenticatorException {
+        Bundle sessionBundle = new Bundle();
+        String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+                + Fixtures.SUFFIX_NAME_FIXTURE;
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+        sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+                AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+        Bundle options = new Bundle();
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+        options.putAll(OPTIONS_BUNDLE);
+
+        // First get an encrypted session bundle from startAddAccountSession(...)
+        Bundle resultBundle = startAddAccountSession(
+                am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert returned result
+        // Assert that auth token was stripped.
+        assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+        validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+        Bundle encryptedSessionBundle = resultBundle
+                .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+        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 {
+            finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+            fail("should have thrown an AuthenticatorException");
+        } catch (AuthenticatorException e1) {
+        }
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private Bundle finishSession(AccountManager am, Bundle sessionBundle, Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+        // Cleanup before calling finishSession(...) with the encrypted session bundle.
+        mockAuthenticator.clearData();
+
+        AccountManagerFuture<Bundle> futureBundle = am.finishSession(
+                sessionBundle,
+                activity,
+                callback,
+                handler);
+
+        Bundle resultBundle = futureBundle.getResult();
+        assertTrue(futureBundle.isDone());
+        assertNotNull(resultBundle);
+
+        return resultBundle;
+    }
+
+    private void validateFinishSessionOptions(String accountName, Bundle options) {
+        validateOptions(options, mockAuthenticator.mOptionsFinishSession);
+        assertNotNull(mockAuthenticator.mOptionsFinishSession);
+        assertEquals(ACCOUNT_TYPE, mockAuthenticator.mOptionsFinishSession
+                .getString(AccountManager.KEY_ACCOUNT_TYPE));
+        assertEquals(accountName,
+                mockAuthenticator.mOptionsFinishSession.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+        validateSystemOptions(mockAuthenticator.mOptionsFinishSession);
+        validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+        validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+        validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+        validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+        validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+    }
+
+    /**
+     * Tests a basic isCredentialsUpdateSuggested() which returns a bundle containing boolean true.
+     */
+    public void testIsCredentialsUpdateSuggested_Success()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Account account = new Account(accountName, ACCOUNT_TYPE);
+
+        Boolean result = isCredentialsUpdateSuggested(
+                am,
+                account,
+                ACCOUNT_STATUS_TOKEN,
+                null /* callback */,
+                null /* handler */);
+
+        // Assert parameters has been passed correctly
+        validateIsCredentialsUpdateSuggestedParametersAndOptions(account);
+
+        // Assert returned result
+        assertTrue(result);
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested() when account is null.
+     * It should throw IllegalArgumentationException.
+     */
+    public void testIsCredentialsUpdateSuggestedNullAccount_IllegalArgumentationException()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        try {
+            isCredentialsUpdateSuggested(
+                    am,
+                    null /* account */,
+                    ACCOUNT_STATUS_TOKEN,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentation when calling with null account!");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested() when statusToken is empty.
+     * It should throw IllegalArgumentationException.
+     */
+    public void testIsCredentialsUpdateSuggestedEmptyToken_IllegalArgumentationException()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Account account = new Account(accountName, ACCOUNT_TYPE);
+        try {
+            isCredentialsUpdateSuggested(
+                    am,
+                    account,
+                    "" /* statusToken */,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown IllegalArgumentation when calling with empty statusToken!");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested() error case. AuthenticatorException is expected when
+     * authenticator return {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testIsCredentialsUpdateSuggested_Error()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Account account = new Account(accountName, ACCOUNT_TYPE);
+
+        try {
+            isCredentialsUpdateSuggested(
+                    am,
+                    account,
+                    ACCOUNT_STATUS_TOKEN,
+                    null /* callback */,
+                    null /* handler */);
+            fail("Should have thrown AuthenticatorException in error case.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested() with callback and handler. A boolean should be included
+     * in the result. Callback should be triggered with the result regardless of a handler is
+     * provided or not.
+     */
+    public void testIsCredentialsUpdateSuggestedWithCallbackAndHandler()
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        testIsCredentialsUpdateSuggestedWithCallbackAndHandler(null /* handler */);
+        testIsCredentialsUpdateSuggestedWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Tests isCredentialsUpdateSuggested() error case with callback and handler.
+     * AuthenticatorException is expected when authenticator return
+     * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+     */
+    public void testIsCredentialsUpdateSuggestedErrorWithCallbackAndHandler()
+            throws IOException, OperationCanceledException, AuthenticatorException {
+        testIsCredentialsUpdateSuggestedErrorWithCallbackAndHandler(null /* handler */);
+        testIsCredentialsUpdateSuggestedErrorWithCallbackAndHandler(
+                new Handler(Looper.getMainLooper()));
+    }
+
+    private void testIsCredentialsUpdateSuggestedWithCallbackAndHandler(Handler handler)
+            throws IOException, AuthenticatorException, OperationCanceledException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Account account = new Account(accountName, ACCOUNT_TYPE);
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Boolean> callback = new AccountManagerCallback<Boolean>() {
+            @Override
+            public void run(AccountManagerFuture<Boolean> booleanFuture) {
+                Boolean result = false;
+                try {
+                    result = booleanFuture.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");
+                }
+
+                // Assert parameters has been passed correctly
+                validateIsCredentialsUpdateSuggestedParametersAndOptions(account);
+
+                // Assert returned result
+                assertTrue(result);
+
+                latch.countDown();
+            }
+        };
+
+        isCredentialsUpdateSuggested(
+                am,
+                account,
+                ACCOUNT_STATUS_TOKEN,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private void testIsCredentialsUpdateSuggestedErrorWithCallbackAndHandler(Handler handler)
+            throws IOException, OperationCanceledException, AuthenticatorException {
+        String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        final Account account = new Account(accountName, ACCOUNT_TYPE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        AccountManagerCallback<Boolean> callback = new AccountManagerCallback<Boolean>() {
+            @Override
+            public void run(AccountManagerFuture<Boolean> booleanFuture) {
+                try {
+                    booleanFuture.getResult();
+                    // AuthenticatorException should be thrown when authenticator
+                    // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+                    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) {
+                    // Test passed as AuthenticatorException is expected.
+                } finally {
+                    latch.countDown();
+                }
+            }
+        };
+
+        isCredentialsUpdateSuggested(
+                am,
+                account,
+                ACCOUNT_STATUS_TOKEN,
+                callback,
+                handler);
+
+        // Wait with timeout for the callback to do its work
+        waitForLatch(latch);
+    }
+
+    private Boolean isCredentialsUpdateSuggested(
+            AccountManager am,
+            Account account,
+            String statusToken,
+            AccountManagerCallback<Boolean> callback,
+            Handler handler)
+                    throws IOException, AuthenticatorException, OperationCanceledException {
+
+        AccountManagerFuture<Boolean> booleanFuture = am.isCredentialsUpdateSuggested(
+                account,
+                statusToken,
+                callback,
+                handler);
+
+        Boolean result = false;
+        if (callback == null) {
+            result = booleanFuture.getResult();
+            assertTrue(booleanFuture.isDone());
+        }
+
+        return result;
+    }
 }
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
index 2068f4c..705729a 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
@@ -23,8 +23,11 @@
 import android.accounts.OperationCanceledException;
 import android.accounts.cts.common.AuthenticatorContentProvider;
 import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.tx.StartAddAccountSessionTx;
+import android.accounts.cts.common.tx.StartUpdateCredentialsSessionTx;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.test.AndroidTestCase;
 
@@ -45,11 +48,17 @@
  */
 public class AccountManagerUnaffiliatedAuthenticatorTests extends AndroidTestCase {
 
+    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";
+
     private AccountManager mAccountManager;
     private ContentProviderClient mProviderClient;
 
     @Override
     public void setUp() throws Exception {
+        SESSION_BUNDLE.putString(SESSION_DATA_NAME_1, SESSION_DATA_VALUE_1);
+
         // bind to the diagnostic service and set it up.
         mAccountManager = AccountManager.get(getContext());
         ContentResolver resolver = getContext().getContentResolver();
@@ -222,5 +231,210 @@
                 getContext().getPackageName());
         assertEquals(0, accounts.length);
     }
+
+    /**
+     * Tests startAddAccountSession when calling package doesn't have the same sig as the
+     * authenticator.
+     * An encrypted session bundle should always be returned without password.
+     */
+    public void testStartAddAccountSession() throws
+            OperationCanceledException, AuthenticatorException, IOException, RemoteException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(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();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        validateStartAddAccountSessionParameters(options);
+
+        // Validate that auth token was stripped from result.
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+        // Validate returned data
+        validateSessionBundleAndPasswordAndStatusTokenResult(result);
+    }
+
+    /**
+     * Tests startUpdateCredentialsSession when calling package doesn't have the same sig as
+     * the authenticator.
+     * An encrypted session bundle should always be returned without password.
+     */
+    public void testStartUpdateCredentialsSession() throws
+            OperationCanceledException, AuthenticatorException, IOException, RemoteException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        Bundle options = createOptionsWithAccountName(accountName);
+
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        validateStartUpdateCredentialsSessionParameters(options);
+
+        // Validate no auth token in result.
+        assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+        // Validate returned data
+        validateSessionBundleAndPasswordAndStatusTokenResult(result);
+    }
+
+    /**
+     * Tests finishSession default implementation with overridden startAddAccountSession
+     * implementation. AuthenticatorException is expected because default AbstractAuthenticator
+     * implementation cannot understand customized session bundle.
+     */
+    public void testDefaultFinishSessiontWithStartAddAccountSessionImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Creates session bundle to be returned by custom implementation of
+        // startAddAccountSession of authenticator.
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                Fixtures.TYPE_STANDARD_UNAFFILIATED);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+        // First get an encrypted session bundle from custom startAddAccountSession implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+                Fixtures.TYPE_STANDARD_UNAFFILIATED,
+                null /* authTokenType */,
+                null /* requiredFeatures */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(decryptedBundle);
+
+        try {
+            // Call default implementation of finishSession of authenticator
+            // with encrypted session bundle.
+            future = mAccountManager.finishSession(
+                    decryptedBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            future.getResult();
+
+            fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    /**
+     * Tests finishSession default implementation with overridden startUpdateCredentialsSession
+     * implementation. AuthenticatorException is expected because default implementation cannot
+     * understand custom session bundle.
+     */
+    public void testDefaultFinishSessionWithCustomStartUpdateCredentialsSessionImpl()
+            throws OperationCanceledException, AuthenticatorException, IOException {
+        String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+        // Creates session bundle to be returned by custom implementation of
+        // startUpdateCredentialsSession of authenticator.
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                Fixtures.TYPE_STANDARD_UNAFFILIATED);
+        Bundle options = new Bundle();
+        options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+        // First get an encrypted session bundle from custom
+        // startUpdateCredentialsSession implementation.
+        AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+                Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+                null /* authTokenType */,
+                options,
+                null /* activity */,
+                null /* callback */,
+                null /* handler */);
+
+        Bundle result = future.getResult();
+        assertTrue(future.isDone());
+        assertNotNull(result);
+
+        Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(decryptedBundle);
+
+        try {
+            // Call default implementation of finishSession of authenticator
+            // with encrypted session bundle.
+            future = mAccountManager.finishSession(
+                    decryptedBundle,
+                    null /* activity */,
+                    null /* callback */,
+                    null /* handler */);
+            future.getResult();
+
+            fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+        } catch (AuthenticatorException e) {
+        }
+    }
+
+    private void validateStartAddAccountSessionParameters(Bundle inOpt)
+            throws RemoteException {
+        Bundle params = mProviderClient.call(AuthenticatorContentProvider.METHOD_GET, null, null);
+        params.setClassLoader(StartAddAccountSessionTx.class.getClassLoader());
+        StartAddAccountSessionTx tx = params.<StartAddAccountSessionTx>getParcelable(
+                AuthenticatorContentProvider.KEY_TX);
+        assertEquals(tx.accountType, Fixtures.TYPE_STANDARD_UNAFFILIATED);
+        assertEquals(tx.options.getString(Fixtures.KEY_ACCOUNT_NAME),
+                inOpt.getString(Fixtures.KEY_ACCOUNT_NAME));
+    }
+
+    private void validateStartUpdateCredentialsSessionParameters(Bundle inOpt)
+            throws RemoteException {
+        Bundle params = mProviderClient.call(AuthenticatorContentProvider.METHOD_GET, null, null);
+        params.setClassLoader(StartUpdateCredentialsSessionTx.class.getClassLoader());
+        StartUpdateCredentialsSessionTx tx =
+                params.<StartUpdateCredentialsSessionTx>getParcelable(
+                        AuthenticatorContentProvider.KEY_TX);
+        assertEquals(tx.account, Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS);
+        assertEquals(tx.options.getString(Fixtures.KEY_ACCOUNT_NAME),
+                inOpt.getString(Fixtures.KEY_ACCOUNT_NAME));
+    }
+
+    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);
+        return options;
+    }
+
+    private void validateSessionBundleAndPasswordAndStatusTokenResult(Bundle result)
+        throws RemoteException {
+        Bundle sessionBundle = result.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));
+        // Validate that no password is returned in the result for unaffiliated package.
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertEquals(Fixtures.ACCOUNT_STATUS_TOKEN_UNAFFILIATED,
+                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..68bd5cd 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,8 +57,12 @@
     public Bundle mOptionsConfirmCredentials;
     public Bundle mOptionsAddAccount;
     public Bundle mOptionsGetAuthToken;
+    public Bundle mOptionsStartAddAccountSession;
+    public Bundle mOptionsStartUpdateCredentialsSession;
+    public Bundle mOptionsFinishSession;
     Account mAccount;
     String[] mFeatures;
+    String mStatusToken;
 
     final ArrayList<String> mockFeatureList = new ArrayList<String>();
     private final long mTokenDurationMillis = 1000; // 1 second
@@ -107,6 +112,10 @@
         return mFeatures;
     }
 
+    public String getStatusToken() {
+        return mStatusToken;
+    }
+
     public void clearData() {
         mResponse = null;
         mAccountType = null;
@@ -116,8 +125,12 @@
         mOptionsAddAccount = null;
         mOptionsGetAuthToken = null;
         mOptionsConfirmCredentials = null;
+        mOptionsStartAddAccountSession = null;
+        mOptionsStartUpdateCredentialsSession = null;
+        mOptionsFinishSession = null;
         mAccount = null;
         mFeatures = null;
+        mStatusToken = null;
     }
 
     public void callAccountAuthenticated() {
@@ -312,4 +325,199 @@
         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;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            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
+            fillResultWithError(result, options);
+        }
+        return result;
+    }
+
+    /**
+     * Start update credentials flow to re-auth user without updating locally stored credentials
+     * for an account.
+     */
+    @Override
+    public Bundle startUpdateCredentialsSession(AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        mResponse = response;
+        mAccount = account;
+        mAuthTokenType = authTokenType;
+        mOptionsStartUpdateCredentialsSession = options;
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+            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
+            fillResultWithError(result, options);
+        }
+        return result;
+    }
+
+    /**
+     * Finishes account session started by adding the account to device or updating the local
+     * credentials.
+     */
+    @Override
+    public Bundle finishSession(AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+        this.mResponse = response;
+        this.mAccountType = accountType;
+        this.mOptionsFinishSession = sessionBundle;
+
+        String accountName = null;
+        if (sessionBundle != null) {
+            accountName = sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, AccountManagerTest.ACCOUNT_NAME);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountManagerTest.ACCOUNT_TYPE);
+            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_ACCOUNT_NAME,
+                    AccountManagerTest.ACCOUNT_NAME);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerTest.ACCOUNT_TYPE);
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+
+            // 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
+            fillResultWithError(result, sessionBundle);
+        }
+        return result;
+    }
+
+    private void fillResultWithError(Bundle result, Bundle options) {
+        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);
+    }
+
+    /**
+     * Checks if the credentials of the account should be updated.
+     */
+    @Override
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+        this.mResponse = response;
+        this.mAccount = account;
+        this.mStatusToken = statusToken;
+
+        Bundle result = new Bundle();
+        if (account.name.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        } else {
+            // fill with error
+            int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+            String errorMsg = "Default Error Message";
+            result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+            result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        response.onResult(result);
+        return null;
+    }
 }
diff --git a/tests/tests/alarmclock/Android.mk b/tests/tests/alarmclock/Android.mk
index 77cb183..6c74c5c 100644
--- a/tests/tests/alarmclock/Android.mk
+++ b/tests/tests/alarmclock/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 := CtsAlarmClockCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAlarmClockCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/alarmclock/service/Android.mk b/tests/tests/alarmclock/service/Android.mk
index 8f0b185..14fdd5d 100644
--- a/tests/tests/alarmclock/service/Android.mk
+++ b/tests/tests/alarmclock/service/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 := CtsAlarmClockCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAlarmClockCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/animation/Android.mk b/tests/tests/animation/Android.mk
index 205adda..2aeac88 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-minus-junit4 \
+    android-common \
+    compatibility-device-util \
+    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/AndroidManifest.xml b/tests/tests/animation/AndroidManifest.xml
index 3744a2a..8c599b7 100644
--- a/tests/tests/animation/AndroidManifest.xml
+++ b/tests/tests/animation/AndroidManifest.xml
@@ -16,8 +16,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.animation.cts">
-    <uses-sdk android:minSdkVersion="11" />
-    <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <activity android:name="android.animation.cts.AnimationActivity"
diff --git a/tests/tests/animation/AndroidTest.xml b/tests/tests/animation/AndroidTest.xml
index b4a0ad5..680256c 100644
--- a/tests/tests/animation/AndroidTest.xml
+++ b/tests/tests/animation/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.animation.cts" />
+        <option name="runtime-hint" value="14m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
index 598048e..da52d30 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimationActivity.java
@@ -37,9 +37,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
-import java.util.ArrayList;
 
-import android.animation.cts.R;
+import java.util.ArrayList;
 
 public class AnimationActivity extends Activity {
     private static final String BALL_HEIGHT = "ballwidth";
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..cb87f29
--- /dev/null
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorListenerAdapterTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+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() {
+        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..385f62f 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
@@ -15,14 +15,10 @@
  */
 package android.animation.cts;
 
-import java.lang.Override;
-import java.lang.Runnable;
-import java.lang.Thread;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+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 android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -30,52 +26,71 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.test.ActivityInstrumentationTestCase2;
+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.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 
-public class AnimatorSetTest extends
-        ActivityInstrumentationTestCase2<AnimationActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatorSetTest {
     private AnimationActivity mActivity;
     private AnimatorSet mAnimatorSet;
     private long mDuration = 1000;
     private Object object;
     private ObjectAnimator yAnimator;
     private ObjectAnimator xAnimator;
-    Set<Integer> identityHashes = new HashSet<Integer>();
+    Set<Integer> identityHashes = new HashSet<>();
 
-    public AnimatorSetTest() {
-        super(AnimationActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<AnimationActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
         object = mActivity.view.newBall;
         yAnimator = getYAnimator(object);
         xAnimator = getXAnimator(object);
     }
 
-     public void testPlaySequentially() throws Throwable {
-         xAnimator.setRepeatCount(0);
-         yAnimator.setRepeatCount(0);
-         xAnimator.setDuration(50);
-         yAnimator.setDuration(50);
-         Animator[] animatorArray = {xAnimator, yAnimator};
-         mAnimatorSet = new AnimatorSet();
-         mAnimatorSet.playSequentially(animatorArray);
-         verifySequentialPlayOrder(mAnimatorSet, animatorArray);
+    @Test
+    public void testPlaySequentially() throws Throwable {
+        xAnimator.setRepeatCount(0);
+        yAnimator.setRepeatCount(0);
+        xAnimator.setDuration(50);
+        yAnimator.setDuration(50);
+        List<Animator> animators = new ArrayList<Animator>();
+        animators.add(xAnimator);
+        animators.add(yAnimator);
+        mAnimatorSet = new AnimatorSet();
+        mAnimatorSet.playSequentially(animators);
+        verifySequentialPlayOrder(mAnimatorSet, new Animator[] {xAnimator, yAnimator});
 
-         ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f);
-         ValueAnimator anim2 = ValueAnimator.ofInt(0, 100);
-         anim1.setDuration(50);
-         anim2.setDuration(50);
-         AnimatorSet set = new AnimatorSet();
-         set.playSequentially(anim1, anim2);
-         verifySequentialPlayOrder(set, new Animator[] {anim1, anim2});
+        ValueAnimator anim1 = ValueAnimator.ofFloat(0f, 1f);
+        ValueAnimator anim2 = ValueAnimator.ofInt(0, 100);
+        anim1.setDuration(50);
+        anim2.setDuration(50);
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(anim1, anim2);
+        verifySequentialPlayOrder(set, new Animator[] {anim1, anim2});
     }
 
     /**
@@ -118,12 +133,9 @@
 
         long totalDuration = set.getTotalDuration();
         assertFalse(set.isRunning());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                set.start();
-                startLatch.countDown();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            set.start();
+            startLatch.countDown();
         });
 
         // Set timeout to 100ms, if current count reaches 0 before the timeout, startLatch.await(...)
@@ -137,6 +149,7 @@
         }
     }
 
+    @Test
     public void testPlayTogether() throws Throwable {
         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
         Animator[] animatorArray = {xAnimator, yAnimator};
@@ -148,7 +161,7 @@
         assertFalse(xAnimator.isRunning());
         assertFalse(yAnimator.isRunning());
         startAnimation(mAnimatorSet);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertTrue(mAnimatorSet.isRunning());
         assertTrue(xAnimator.isRunning());
         assertTrue(yAnimator.isRunning());
@@ -163,12 +176,13 @@
         assertFalse(anim1.isRunning());
         assertFalse(anim2.isRunning());
         startAnimation(set);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertTrue(set.isRunning());
         assertTrue(anim1.isRunning());
         assertTrue(anim2.isRunning());
     }
 
+    @Test
     public void testPlayBeforeAfter() throws Throwable {
         xAnimator.setRepeatCount(0);
         yAnimator.setRepeatCount(0);
@@ -184,6 +198,39 @@
         verifySequentialPlayOrder(set, new Animator[] {xAnimator, yAnimator, zAnimator});
     }
 
+    @Test
+    public void testListenerCallbackOnEmptySet() throws Throwable {
+        // Create an AnimatorSet that only contains one empty AnimatorSet, and checks the callback
+        // sequence by checking the time stamps of the callbacks.
+        final AnimatorSet emptySet = new AnimatorSet();
+        final AnimatorSet set = new AnimatorSet();
+        set.play(emptySet);
+        MyListener listener = new MyListener() {
+            long startTime = 0;
+            long endTime = 0;
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                startTime = SystemClock.currentThreadTimeMillis();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                endTime = SystemClock.currentThreadTimeMillis();
+                assertTrue(endTime >= startTime);
+                assertTrue(startTime != 0);
+            }
+        };
+        set.addListener(listener);
+        mActivityRule.runOnUiThread(() -> {
+            set.start();
+        });
+        assertTrue(listener.mStartIsCalled);
+        assertTrue(listener.mEndIsCalled);
+    }
+
+    @Test
     public void testPauseAndResume() throws Throwable {
         final AnimatorSet set = new AnimatorSet();
         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
@@ -212,20 +259,17 @@
         set.addListener(l1);
         delayedSet.addListener(l2);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                set.start();
-                delayedSet.start();
+        mActivityRule.runOnUiThread(() -> {
+            set.start();
+            delayedSet.start();
 
-                // Pause the delayed set during start delay
-                delayedSet.pause();
-            }
+            // Pause the delayed set during start delay
+            delayedSet.pause();
         });
 
         // Sleep long enough so that if the sets are not properly paused, they would have
         // finished.
-        Thread.sleep(300);
+        SystemClock.sleep(300);
         // Verify that both sets have been paused and *not* finished.
         assertTrue(set.isPaused());
         assertTrue(delayedSet.isPaused());
@@ -234,14 +278,11 @@
         assertFalse(l1.mEndIsCalled);
         assertFalse(l2.mEndIsCalled);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                set.resume();
-                delayedSet.resume();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            set.resume();
+            delayedSet.resume();
         });
-        Thread.sleep(300);
+        SystemClock.sleep(300);
 
         assertFalse(set.isPaused());
         assertFalse(delayedSet.isPaused());
@@ -249,6 +290,7 @@
         assertTrue(l2.mEndIsCalled);
     }
 
+    @Test
     public void testPauseBeforeStart() throws Throwable {
         final AnimatorSet set = new AnimatorSet();
         ValueAnimator a1 = ValueAnimator.ofFloat(0f, 100f);
@@ -261,23 +303,21 @@
         final MyListener listener = new MyListener();
         set.addListener(listener);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Pause animator set before calling start()
-                set.pause();
-                // Verify that pause should have no effect on a not-yet-started animator.
-                assertFalse(set.isPaused());
-                set.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            // Pause animator set before calling start()
+            set.pause();
+            // Verify that pause should have no effect on a not-yet-started animator.
+            assertFalse(set.isPaused());
+            set.start();
         });
-        Thread.sleep(300);
+        SystemClock.sleep(300);
 
         // Animator set should finish running by now since it's not paused.
         assertTrue(listener.mStartIsCalled);
         assertTrue(listener.mEndIsCalled);
     }
 
+    @Test
     public void testDuration() throws Throwable {
         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
         Animator[] animatorArray = { xAnimator, yAnimator };
@@ -287,10 +327,11 @@
         mAnimatorSet.setDuration(1000);
 
         startAnimation(mAnimatorSet);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertEquals(mAnimatorSet.getDuration(), 1000);
     }
 
+    @Test
     public void testStartDelay() throws Throwable {
         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
         Animator[] animatorArray = { xAnimator, yAnimator };
@@ -300,20 +341,22 @@
         mAnimatorSet.setStartDelay(10);
 
         startAnimation(mAnimatorSet);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertEquals(mAnimatorSet.getStartDelay(), 10);
     }
 
-    public void testgetChildAnimations() throws Throwable {
+    @Test
+    public void testGetChildAnimations() throws Throwable {
         Animator[] animatorArray = { xAnimator, yAnimator };
 
         mAnimatorSet = new AnimatorSet();
-        ArrayList<Animator> childAnimations = mAnimatorSet.getChildAnimations();
+        mAnimatorSet.getChildAnimations();
         assertEquals(0, mAnimatorSet.getChildAnimations().size());
         mAnimatorSet.playSequentially(animatorArray);
         assertEquals(2, mAnimatorSet.getChildAnimations().size());
     }
 
+    @Test
     public void testSetInterpolator() throws Throwable {
         xAnimator.setRepeatCount(ValueAnimator.INFINITE);
         Animator[] animatorArray = {xAnimator, yAnimator};
@@ -324,14 +367,14 @@
 
         assertFalse(mAnimatorSet.isRunning());
         startAnimation(mAnimatorSet);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
 
         ArrayList<Animator> animatorList = mAnimatorSet.getChildAnimations();
-        assertEquals(interpolator, ((ObjectAnimator)animatorList.get(0)).getInterpolator());
-        assertEquals(interpolator, ((ObjectAnimator)animatorList.get(1)).getInterpolator());
+        assertEquals(interpolator, animatorList.get(0).getInterpolator());
+        assertEquals(interpolator, animatorList.get(1).getInterpolator());
     }
 
-    public ObjectAnimator getXAnimator(Object object) {
+    private ObjectAnimator getXAnimator(Object object) {
         String propertyX = "x";
         float startX = mActivity.mStartX;
         float endX = mActivity.mStartX + mActivity.mDeltaX;
@@ -343,7 +386,7 @@
         return xAnimator;
     }
 
-    public ObjectAnimator getYAnimator(Object object) {
+    private ObjectAnimator getYAnimator(Object object) {
          String property = "y";
          float startY = mActivity.mStartY;
          float endY = mActivity.mStartY + mActivity.mDeltaY;
@@ -356,11 +399,7 @@
     }
 
     private void startAnimation(final AnimatorSet animatorSet) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.startAnimatorSet(animatorSet);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimatorSet(animatorSet));
     }
 
     private void assertUnique(Object object) {
@@ -373,6 +412,7 @@
 
     }
 
+    @Test
     public void testClone() throws Throwable {
         final AnimatorSet set1 = new AnimatorSet();
         final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {};
@@ -397,12 +437,7 @@
 
         AnimateObject target = new AnimateObject();
         set1.setTarget(target);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                set1.start();
-            }
-        });
+        mActivityRule.runOnUiThread(set1::start);
         assertTrue(set1.isStarted());
 
         animator1.getListeners();
@@ -438,6 +473,43 @@
         assertSame(animator2.getInterpolator(), clone2.getInterpolator());
     }
 
+    @Test
+    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);
+        mActivityRule.runOnUiThread(() -> {
+            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/AnimatorTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
index a08a5eb..655eb1c 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorTest.java
@@ -15,41 +15,63 @@
  */
 package android.animation.cts;
 
+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.assertTrue;
+
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.AccelerateInterpolator;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.List;
 
-public class AnimatorTest extends ActivityInstrumentationTestCase2<AnimationActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatorTest {
     private AnimationActivity mActivity;
     private Animator mAnimator;
     private long mDuration = 1000;
-    public AnimatorTest() {
-        super(AnimationActivity.class);
-    }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Rule
+    public ActivityTestRule<AnimationActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationActivity.class);
+
+    @Before
+    public void setup() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
         mAnimator = mActivity.createAnimatorWithDuration(mDuration);
     }
 
+    @Test
     public void testConstructor() {
         mAnimator = new ValueAnimator();
         assertNotNull(mAnimator);
     }
 
+    @Test
     public void testClone() {
         Animator animatorClone = mAnimator.clone();
         assertEquals(mAnimator.getDuration(), animatorClone.getDuration());
     }
 
+    @Test
     public void testStartDelay() {
         long startDelay = 1000;
         mAnimator.setStartDelay(startDelay);
@@ -57,12 +79,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testStart() throws Exception {
         mAnimator.start();
         assertTrue(mAnimator.isRunning());
         assertTrue(mAnimator.isStarted());
     }
 
+    @Test
     public void testGetDuration() throws Throwable {
         final long duration = 2000;
         Animator animatorLocal = mActivity.createAnimatorWithDuration(duration);
@@ -70,12 +94,14 @@
         assertEquals(duration, animatorLocal.getDuration());
     }
 
+    @Test
     public void testIsRunning() throws Throwable {
         assertFalse(mAnimator.isRunning());
         startAnimation(mAnimator);
         assertTrue(mAnimator.isRunning());
     }
 
+    @Test
     public void testIsStarted() throws Throwable {
         assertFalse(mAnimator.isRunning());
         assertFalse(mAnimator.isStarted());
@@ -86,6 +112,7 @@
         assertTrue(mAnimator.isStarted());
     }
 
+    @Test
     public void testSetInterpolator() throws Throwable {
         AccelerateInterpolator interpolator = new AccelerateInterpolator();
         ValueAnimator mValueAnimator = mActivity.createAnimatorWithInterpolator(interpolator);
@@ -93,17 +120,15 @@
         assertTrue(interpolator.equals(mValueAnimator.getInterpolator()));
     }
 
+    @Test
     public void testCancel() throws Throwable {
         startAnimation(mAnimator);
-        Thread.sleep(100);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimator.cancel();
-            }
-        });
+        SystemClock.sleep(100);
+        mActivityRule.runOnUiThread(mAnimator::cancel);
         assertFalse(mAnimator.isRunning());
     }
 
+    @Test
     public void testEnd() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -115,13 +140,15 @@
         animator.setInterpolator(new AccelerateInterpolator());
         ((ObjectAnimator)animator).setRepeatMode(ValueAnimator.REVERSE);
         startAnimation(animator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         endAnimation(animator);
         float y = mActivity.view.newBall.getY();
-        assertEquals(y, endY);
+        assertEquals(y, endY, 0.0f);
     }
 
+    @Test
     public void testSetListener() throws Throwable {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         List<Animator.AnimatorListener> listListeners = mAnimator.getListeners();
         assertNull(listListeners);
         MyListener listener = new MyListener();
@@ -131,29 +158,22 @@
         mAnimator.addListener(listener);
         mAnimator.setDuration(100l);
         startAnimation(mAnimator);
-        Thread.sleep(200);
+        SystemClock.sleep(200);
 
         assertTrue(listener.mStart);
         assertFalse(listener.mEnd);
         assertTrue(listener.mRepeat >= 0);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mAnimator.cancel();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(mAnimator::cancel);
+        instrumentation.waitForIdleSync();
         assertTrue(listener.mCancel);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mAnimator.end();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(mAnimator::end);
+        instrumentation.waitForIdleSync();
         assertTrue(listener.mEnd);
     }
 
+    @Test
     public void testRemoveListener() throws Throwable {
         List<Animator.AnimatorListener> listListenersOne = mAnimator.getListeners();
         assertNull(listListenersOne);
@@ -168,6 +188,7 @@
         assertNull(listListenersThree);
     }
 
+    @Test
     public void testRemoveAllListenerers() throws Throwable {
         MyListener listener1 = new MyListener();
         MyListener listener2 = new MyListener();
@@ -182,7 +203,8 @@
         assertNull(listListenersTwo);
     }
 
-    public void testNullObjectAnimator()  throws Throwable {
+    @Test
+    public void testNullObjectAnimator() throws Throwable {
         Object object = mActivity.view.newBall;
         final ObjectAnimator animator = ObjectAnimator.ofFloat(object, "y", 0, 100);
         MyListener listener = new MyListener();
@@ -191,15 +213,10 @@
         startAnimation(animator);
         int sleepCount = 0;
         while (mActivity.view.newBall.getY() == 0 && sleepCount++ < 50) {
-            Thread.sleep(1);
+            SystemClock.sleep(1);
         }
         assertNotSame(0, mActivity.view.newBall.getY());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                animator.setTarget(null);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> animator.setTarget(null));
         assertTrue(listener.mCancel);
     }
 
@@ -226,20 +243,11 @@
         }
     }
     private void startAnimation(final Animator animator) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.startAnimation(animator);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
     }
 
     private void endAnimation(final Animator animator) throws Throwable {
-        Thread animationRunnable = new Thread() {
-            public void run() {
-                animator.end();
-            }
-        };
-        this.runTestOnUiThread(animationRunnable);
+        mActivityRule.runOnUiThread(animator::end);
     }
 }
 
diff --git a/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java b/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java
index fe66951..6d288c6 100644
--- a/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java
+++ b/tests/tests/animation/src/android/animation/cts/ButtonViewActivity.java
@@ -19,8 +19,6 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-import android.animation.cts.R;
-
 public class ButtonViewActivity extends Activity {
 
     @Override
diff --git a/tests/tests/animation/src/android/animation/cts/CreationTest.java b/tests/tests/animation/src/android/animation/cts/CreationTest.java
index f45f64b..5bdd2a6 100644
--- a/tests/tests/animation/src/android/animation/cts/CreationTest.java
+++ b/tests/tests/animation/src/android/animation/cts/CreationTest.java
@@ -16,38 +16,48 @@
 
 package android.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.animation.AnimatorInflater;
 import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
-import android.os.Debug;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 
-import android.animation.cts.R;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class CreationTest extends ActivityInstrumentationTestCase2<ButtonViewActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CreationTest {
+    private static final float EPSILON = 0.0001f;
 
     private ButtonViewActivity mActivity;
 
-    public CreationTest() {
-        super(ButtonViewActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ButtonViewActivity> mActivityRule =
+            new ActivityTestRule<>(ButtonViewActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorCreation() {
         ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
         verifyValues(animator, 0, 1);
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorResourceCreation() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator);
@@ -55,6 +65,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvh1() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh1);
@@ -62,6 +73,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvh2() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh2);
@@ -69,6 +81,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvhKf1() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf1);
@@ -76,6 +89,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvhKf2() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf2);
@@ -83,6 +97,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvhKf3() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf3);
@@ -90,6 +105,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testValueAnimatorPvhKf4() {
         ValueAnimator animator = (ValueAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.value_animator_pvh_kf4);
@@ -97,6 +113,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testObjectAnimator() {
         ObjectAnimator animator = (ObjectAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator);
@@ -105,6 +122,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testObjectAnimatorPvh1() {
         ObjectAnimator animator = (ObjectAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator_pvh1);
@@ -114,6 +132,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testObjectAnimatorPvhKf1() {
         ObjectAnimator animator = (ObjectAnimator)
                 AnimatorInflater.loadAnimator(mActivity, R.animator.object_animator_pvh_kf1);
@@ -138,32 +157,26 @@
         }
     }
 
-    private void assertRoughlyEqual(float checkValue, float correctValue) {
-        // use epsilon for float compares
-        final float epsilon = .0001f;
-        assertTrue(checkValue > correctValue - epsilon && checkValue < correctValue + epsilon);
-    }
-
     private void verifyValues(ValueAnimator animator, float... values) {
         animator.setCurrentFraction(0);
-        assertRoughlyEqual((Float) animator.getAnimatedValue(), values[0]);
+        assertEquals((Float) animator.getAnimatedValue(), values[0], EPSILON);
         for (int i = 1; i < values.length - 1; ++i) {
             animator.setCurrentFraction((float) i / (values.length - 1));
-            assertRoughlyEqual((Float) animator.getAnimatedValue(), values[i]);
+            assertEquals((Float) animator.getAnimatedValue(), values[i], EPSILON);
         }
         animator.setCurrentFraction(1);
-        assertRoughlyEqual((Float) animator.getAnimatedValue(), values[values.length - 1]);
+        assertEquals((Float) animator.getAnimatedValue(), values[values.length - 1], EPSILON);
     }
 
     private void verifyValues(ObjectAnimator animator, String propertyName, float... values) {
         animator.setCurrentFraction(0);
-        assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName), values[0]);
+        assertEquals((Float) animator.getAnimatedValue(propertyName), values[0], EPSILON);
         for (int i = 1; i < values.length - 1; ++i) {
             animator.setCurrentFraction((float) i / (values.length - 1));
-            assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName), values[i]);
+            assertEquals((Float) animator.getAnimatedValue(propertyName), values[i], EPSILON);
         }
         animator.setCurrentFraction(1);
-        assertRoughlyEqual((Float) animator.getAnimatedValue(propertyName),
-                values[values.length - 1]);
+        assertEquals((Float) animator.getAnimatedValue(propertyName), values[values.length - 1],
+                EPSILON);
     }
 }
diff --git a/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java b/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
index 0812351..0e9a462 100644
--- a/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/EvaluatorTest.java
@@ -16,6 +16,9 @@
 
 package android.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.animation.ArgbEvaluator;
 import android.animation.FloatArrayEvaluator;
 import android.animation.FloatEvaluator;
@@ -26,13 +29,21 @@
 import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the various Evaluator classes in android.animation
  */
-public class EvaluatorTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EvaluatorTest {
+    private static final float EPSILON = 0.001f;
 
+    @Test
     public void testFloatEvaluator() {
         float start = 0.0f;
         float end = 1.0f;
@@ -40,79 +51,102 @@
         FloatEvaluator floatEvaluator = new FloatEvaluator();
 
         float result = floatEvaluator.evaluate(0, start, end);
-        assertEquals(start, result, .001f);
+        assertEquals(start, result, EPSILON);
 
         result = floatEvaluator.evaluate(fraction, start, end);
-        assertEquals(.5f, result, .001f);
+        assertEquals(.5f, result, EPSILON);
 
         result = floatEvaluator.evaluate(1, start, end);
-        assertEquals(end, result, .001f);
+        assertEquals(end, result, EPSILON);
     }
 
+    @Test
     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);
-        assertEquals(start[1], result[1], .001f);
+        assertEquals(start[0], result[0], EPSILON);
+        assertEquals(start[1], result[1], EPSILON);
 
         result = evaluator.evaluate(fraction, start, end);
-        assertEquals(.4f, result[0], .001f);
-        assertEquals(.5f, result[1], .001f);
+        assertEquals(.4f, result[0], EPSILON);
+        assertEquals(.5f, result[1], EPSILON);
 
         result = evaluator.evaluate(1, start, end);
-        assertEquals(end[0], result[0], .001f);
-        assertEquals(end[1], result[1], .001f);
+        assertEquals(end[0], result[0], EPSILON);
+        assertEquals(end[1], result[1], EPSILON);
+
+        if (reusedArray != null) {
+            assertEquals(reusedArray, result);
+        }
     }
 
+    @Test
     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);
     }
 
+    @Test
     public void testIntEvaluator() throws Throwable {
         final int start = 0;
         final int end = 100;
@@ -129,11 +163,20 @@
         assertEquals(end, result);
     }
 
+    @Test
     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,62 +189,79 @@
         result = evaluator.evaluate(1, start, end);
         assertEquals(end[0], result[0]);
         assertEquals(end[1], result[1]);
+
+        if (reusedArray != null) {
+            assertEquals(reusedArray, result);
+        }
     }
 
+    @Test
     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;
 
         Rect result = evaluator.evaluate(0, start, end);
-        assertEquals(start.left, result.left, .001f);
-        assertEquals(start.top, result.top, .001f);
-        assertEquals(start.right, result.right, .001f);
+        assertEquals(start.left, result.left, EPSILON);
+        assertEquals(start.top, result.top, EPSILON);
+        assertEquals(start.right, result.right, EPSILON);
         assertEquals(start.bottom, result.bottom, 001f);
 
         result = evaluator.evaluate(fraction, start, end);
-        assertEquals(50, result.left, .001f);
-        assertEquals(100, result.top, .001f);
-        assertEquals(150, result.right, .001f);
-        assertEquals(200, result.bottom, .001f);
+        assertEquals(50, result.left, EPSILON);
+        assertEquals(100, result.top, EPSILON);
+        assertEquals(150, result.right, EPSILON);
+        assertEquals(200, result.bottom, EPSILON);
 
         result = evaluator.evaluate(1, start, end);
-        assertEquals(end.left, result.left, .001f);
-        assertEquals(end.top, result.top, .001f);
-        assertEquals(end.right, result.right, .001f);
-        assertEquals(end.bottom, result.bottom, .001f);
+        assertEquals(end.left, result.left, EPSILON);
+        assertEquals(end.top, result.top, EPSILON);
+        assertEquals(end.right, result.right, EPSILON);
+        assertEquals(end.bottom, result.bottom, EPSILON);
+
+        if (reusedRect != null) {
+            assertEquals(reusedRect, result);
+        }
     }
 
+    @Test
     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;
 
         PointF result = evaluator.evaluate(0, start, end);
-        assertEquals(start.x, result.x, .001f);
-        assertEquals(start.y, result.y, .001f);
+        assertEquals(start.x, result.x, EPSILON);
+        assertEquals(start.y, result.y, EPSILON);
 
         result = evaluator.evaluate(fraction, start, end);
-        assertEquals(50, result.x, .001f);
-        assertEquals(100, result.y, .001f);
+        assertEquals(50, result.x, EPSILON);
+        assertEquals(100, result.y, EPSILON);
 
         result = evaluator.evaluate(1, start, end);
-        assertEquals(end.x, result.x, .001f);
-        assertEquals(end.y, result.y, .001f);
-    }
+        assertEquals(end.x, result.x, EPSILON);
+        assertEquals(end.y, result.y, EPSILON);
 
-    /**
-     * Utility method to compare float values. Exact equality is error-prone
-     * with floating point values, so we ensure that the actual value is at least
-     * within some epsilon of the expected value.
-     */
-    private void assertEquals(float expected, float actual) {
-        if (expected != actual) {
-            final float epsilon = .001f;
-            assertTrue(actual <= expected + epsilon);
-            assertTrue(actual >= expected - epsilon);
+        if (reusedPoint != null) {
+            assertEquals(reusedPoint, result);
         }
     }
 }
diff --git a/tests/tests/animation/src/android/animation/cts/KeyframeTest.java b/tests/tests/animation/src/android/animation/cts/KeyframeTest.java
index 7366920..1072487 100644
--- a/tests/tests/animation/src/android/animation/cts/KeyframeTest.java
+++ b/tests/tests/animation/src/android/animation/cts/KeyframeTest.java
@@ -16,49 +16,65 @@
 
 package android.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.animation.Keyframe;
 import android.animation.TimeInterpolator;
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.AccelerateInterpolator;
 
-public class KeyframeTest extends InstrumentationTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyframeTest {
+    @Test
     public void testGetFraction() {
         Keyframe keyFrame = Keyframe.ofInt(0.0f);
         float fraction = keyFrame.getFraction();
-        assertTrue(fraction == 0.0f);
+        assertEquals(0.0f, fraction, 0.0f);
     }
 
+    @Test
     public void testSetFraction() {
         Keyframe keyFrame = Keyframe.ofInt(0.0f);
         keyFrame.setFraction(0.5f);
         float fraction = keyFrame.getFraction();
-        assertTrue(fraction == 0.5f);
+        assertEquals(0.5f, fraction, 0.0f);
     }
 
+    @Test
     public void testOfFloat() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f);
         float fraction = keyFrame.getFraction();
-        assertEquals(fraction, 0.0f);
+        assertEquals(0.0f, fraction, 0.0f);
     }
 
+    @Test
     public void testOfIntValue() {
         Keyframe keyFrame = Keyframe.ofInt(0.0f,10);
         assertTrue(keyFrame.hasValue());
         assertEquals(keyFrame.getValue(),10);
     }
 
+    @Test
     public void testOfFloatValue() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f,9.0f);
         assertTrue(keyFrame.hasValue());
-        assertEquals(keyFrame.getValue(),9.0f);
+        assertEquals(9.0f, (float) keyFrame.getValue(), 0.0f);
     }
 
+    @Test
     public void testOfObject() {
         Keyframe keyFrame = Keyframe.ofObject(0.0f);
         float fraction = keyFrame.getFraction();
-        assertEquals(fraction, 0.0f);
+        assertEquals(0.0f, fraction, 0.0f);
     }
 
+    @Test
     public void testOfObjectValue() {
         String value = "test";
         Keyframe keyFrame = Keyframe.ofObject(0.0f, value);
@@ -66,6 +82,7 @@
         assertEquals(keyFrame.getValue(), value);
     }
 
+    @Test
     public void testGetType() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f);
         Class typeClass = keyFrame.getType();
@@ -73,12 +90,14 @@
         assertEquals(typeName, "float");
     }
 
+    @Test
     public void testClone() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f);
         Keyframe clone = keyFrame.clone();
-        assertEquals(keyFrame.getFraction(), clone.getFraction());
+        assertEquals(keyFrame.getFraction(), clone.getFraction(), 0.0f);
     }
 
+    @Test
     public void testSetInterpolator() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f);
         TimeInterpolator interpolator = new AccelerateInterpolator();
@@ -86,11 +105,12 @@
         assertEquals(interpolator, keyFrame.getInterpolator());
     }
 
+    @Test
     public void testSetValue() {
         Keyframe keyFrame = Keyframe.ofFloat(0.0f);
         Float value = new Float(100.0f);
         keyFrame.setValue(value);
-        Float actualValue = (Float)keyFrame.getValue();
+        Float actualValue = (Float) keyFrame.getValue();
         assertEquals(value, actualValue);
     }
 }
diff --git a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
index f39fe505..da08929 100644
--- a/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
+++ b/tests/tests/animation/src/android/animation/cts/LayoutAnimationTest.java
@@ -15,11 +15,10 @@
  */
 package android.animation.cts;
 
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import android.animation.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.assertTrue;
 
 import android.animation.Animator;
 import android.animation.LayoutTransition;
@@ -27,33 +26,48 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
-import android.test.ActivityInstrumentationTestCase2;
+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 android.view.animation.AccelerateInterpolator;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
-public class LayoutAnimationTest extends
-        ActivityInstrumentationTestCase2<LayoutAnimationActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LayoutAnimationTest {
     private LayoutAnimationActivity mActivity;
-    private MyLayoutTransition mLayoutTransition;
+    private LayoutTransition mLayoutTransition;
     private LinearLayout mView;
     private Button mButton;
 
-    public LayoutAnimationTest() {
-        super(LayoutAnimationActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<LayoutAnimationActivity> mActivityRule =
+            new ActivityTestRule<>(LayoutAnimationActivity.class);
 
-    public void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(true);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
+        mActivity = mActivityRule.getActivity();
         mView = (LinearLayout) mActivity.findViewById(R.id.container);
         mButton = (Button)mActivity.findViewById(R.id.button1);
-        mLayoutTransition = new MyLayoutTransition();
+        mLayoutTransition = new LayoutTransition();
     }
 
+    @Test
     public void testAddTransitionListener() throws Throwable {
         MyTransitionListener listener = new MyTransitionListener();
         assertNull(mLayoutTransition.getTransitionListeners());
@@ -65,6 +79,7 @@
         assertEquals(listener, actualListener);
     }
 
+    @Test
     public void testIsRunning() throws Throwable {
         setDefaultTransition();
         assertFalse(mLayoutTransition.isRunning());
@@ -72,6 +87,7 @@
         assertTrue(mLayoutTransition.isRunning());
     }
 
+    @Test
     public void testIsChangingLayout() throws Throwable {
         long duration = 2000l;
         mView.setLayoutTransition(mLayoutTransition);
@@ -84,6 +100,7 @@
         assertTrue(mLayoutTransition.isChangingLayout());
     }
 
+    @Test
     public void testSetDuration() {
         long duration = 1000l;
         mLayoutTransition.setDuration(duration);
@@ -95,12 +112,14 @@
         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.DISAPPEARING));
     }
 
+    @Test
     public void testSetDurationForTransitionType() {
         long duration = 1000l;
         mLayoutTransition.setDuration(LayoutTransition.APPEARING, duration);
         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.APPEARING));
     }
 
+    @Test
     public void testSetInterpolator() {
         TimeInterpolator interpolator = new AccelerateInterpolator();
         mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, interpolator);
@@ -108,18 +127,20 @@
                 LayoutTransition.APPEARING));
     }
 
+    @Test
     public void testSetAnimator() {
         float startAlpha = 0.0f;
         float endAlpha = 0.5f;
         PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", startAlpha,
                 endAlpha);
-        ObjectAnimator appearingAnimator =  (ObjectAnimator) ObjectAnimator.ofPropertyValuesHolder(
-                (Object)null, pvhAlpha);
+        ObjectAnimator appearingAnimator = ObjectAnimator.ofPropertyValuesHolder(
+                (Object) null, pvhAlpha);
         appearingAnimator.setInterpolator(new AccelerateInterpolator());
         mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
         assertEquals(appearingAnimator, mLayoutTransition.getAnimator(LayoutTransition.APPEARING));
     }
 
+    @Test
     public void testAnimationWithAnimator() throws Throwable {
         MyTransitionListener listener = new MyTransitionListener();
         mLayoutTransition.addTransitionListener(listener);
@@ -131,18 +152,18 @@
         float endAlpha = 0.5f;
         PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", startAlpha,
                 endAlpha);
-        ObjectAnimator appearingAnimator =  (ObjectAnimator) ObjectAnimator.ofPropertyValuesHolder(
-                (Object)null, pvhAlpha);
+        ObjectAnimator appearingAnimator = ObjectAnimator.ofPropertyValuesHolder(
+                (Object) null, pvhAlpha);
         appearingAnimator.setInterpolator(new AccelerateInterpolator());
 
         mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
 
-        List<Float> alphaList = new LinkedList<Float>();
+        List<Float> alphaList = new LinkedList<>();
         clickButton();
-        while(listener.mTransition) {
+        while (listener.mTransition) {
             float alpha = mActivity.getLastButton().getAlpha();
             alphaList.add(alpha);
-            Thread.sleep(200);
+            SystemClock.sleep(200);
         }
         Iterator<Float> iterator = alphaList.iterator();
         float lastValue = 0.0f;
@@ -155,6 +176,7 @@
         }
     }
 
+    @Test
     public void testStartDelay() {
         long delay = 100l;
         int transitionType = LayoutTransition.APPEARING;
@@ -162,6 +184,7 @@
         assertEquals(delay, mLayoutTransition.getStartDelay(transitionType));
     }
 
+    @Test
     public void testSetStagger() {
         long duration = 100;
         int transitionType = LayoutTransition.CHANGE_APPEARING;
@@ -178,12 +201,8 @@
     }
 
     private void clickButton() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mButton.callOnClick();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(mButton::callOnClick);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
     class MyTransitionListener implements LayoutTransition.TransitionListener {
diff --git a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
index 6ff1cf9..4939f3f 100644
--- a/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ObjectAnimatorTest.java
@@ -16,40 +16,87 @@
 
 package android.animation.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+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.test.ActivityInstrumentationTestCase2;
+import android.app.Instrumentation;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.PointF;
+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.util.Property;
+import android.view.View;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
 
-public class ObjectAnimatorTest extends
-        ActivityInstrumentationTestCase2<AnimationActivity> {
+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 ObjectAnimatorTest {
+    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 static final float EPSILON = .001f;
+
+    private Instrumentation mInstrumentation;
     private AnimationActivity mActivity;
     private ObjectAnimator mObjectAnimator;
     private long mDuration = 1000;
 
-    public ObjectAnimatorTest() {
-        super(AnimationActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<AnimationActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mInstrumentation.setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
         mObjectAnimator = (ObjectAnimator) mActivity.createAnimatorWithDuration(mDuration);
     }
 
+    @Test
     public void testDuration() throws Throwable {
         final long duration = 2000;
-        ObjectAnimator objectAnimatorLocal = (ObjectAnimator)mActivity.createAnimatorWithDuration(
+        ObjectAnimator objectAnimatorLocal = (ObjectAnimator) mActivity.createAnimatorWithDuration(
             duration);
         startAnimation(objectAnimatorLocal);
         assertEquals(duration, objectAnimatorLocal.getDuration());
     }
+
+    @Test
     public void testOfFloat() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -63,13 +110,14 @@
         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
         startAnimation(objAnimator);
         assertTrue(objAnimator != null);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         float x = mActivity.view.newBall.getX();
         float y = mActivity.view.newBall.getY();
         assertTrue( y >= startY);
         assertTrue( y <= endY);
     }
 
+    @Test
     public void testOfFloatBase() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -83,6 +131,7 @@
         assertEquals(animator.getPropertyName(), objAnimator.getPropertyName());
     }
 
+    @Test
     public void testOfInt() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "backgroundColor";
@@ -95,20 +144,17 @@
         colorAnimator.setEvaluator(new ArgbEvaluator());
         colorAnimator.setRepeatCount(1);
         colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                colorAnimator.start();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(colorAnimator::start);
+        mInstrumentation.waitForIdleSync();
         startAnimation(mObjectAnimator, colorAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         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());
     }
 
+    @Test
     public void testOfObject() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "backgroundColor";
@@ -121,20 +167,17 @@
         colorAnimator.setDuration(1000);
         colorAnimator.setRepeatCount(1);
         colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                colorAnimator.start();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(colorAnimator::start);
+        mInstrumentation.waitForIdleSync();
         startAnimation(mObjectAnimator, colorAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         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());
     }
 
+    @Test
     public void testOfPropertyValuesHolder() throws Throwable {
         Object object = mActivity.view.newBall;
         String propertyName = "backgroundColor";
@@ -148,20 +191,77 @@
         colorAnimator.setDuration(1000);
         colorAnimator.setRepeatCount(1);
         colorAnimator.setRepeatMode(ValueAnimator.REVERSE);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                colorAnimator.start();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(colorAnimator::start);
+        mInstrumentation.waitForIdleSync();
         startAnimation(mObjectAnimator, colorAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         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());
     }
 
+    @Test
+    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((ValueAnimator animation) -> {
+            if (animation.getAnimatedFraction() > .05f) {
+                latch.countDown();
+            }
+        });
+
+        mActivityRule.runOnUiThread(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);
+
+        mActivityRule.runOnUiThread(animator::cancel);
+    }
+
+    @Test
+    public void testNullObject() throws Throwable {
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(null, "dummyValue", 0f, 1f);
+        anim.setDuration(300);
+        final ValueAnimator.AnimatorUpdateListener updateListener =
+                mock(ValueAnimator.AnimatorUpdateListener.class);
+        anim.addUpdateListener(updateListener);
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(500)).onAnimationEnd(anim);
+        // Verify that null target ObjectAnimator didn't get canceled.
+        verify(listener, times(0)).onAnimationCancel(anim);
+        // Verify that the update listeners gets called a few times.
+        verify(updateListener, atLeast(8)).onAnimationUpdate(anim);
+    }
+
+    @Test
     public void testGetPropertyName() throws Throwable {
         Object object = mActivity.view.newBall;
         String propertyName = "backgroundColor";
@@ -175,6 +275,7 @@
         assertEquals(propertyName, actualPropertyName);
     }
 
+    @Test
     public void testSetFloatValues() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -190,12 +291,13 @@
         objAnimator.setInterpolator(new AccelerateInterpolator());
         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
         startAnimation(objAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         float y = mActivity.view.newBall.getY();
         assertTrue( y >= startY);
         assertTrue( y <= endY);
     }
 
+    @Test
     public void testGetTarget() throws Throwable {
         Object object = mActivity.view.newBall;
         String propertyName = "backgroundColor";
@@ -209,6 +311,7 @@
         assertEquals(object, target);
     }
 
+    @Test
     public void testClone() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -230,6 +333,418 @@
         assertEquals(interpolator, cloneAnimator.getInterpolator());
     }
 
+    @Test
+    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 ObjectAnimator anim = ObjectAnimator.ofFloat(target, "x", "y", path);
+        anim.setDuration(200);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.addUpdateListener((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, 0.0f);
+
+                // 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, 0.0f);
+
+                // Check that the time animation stays on the second segment is proportional to
+                // the length of the second line segment.
+                assertTrue(fraction > firstSegEndFraction - delta);
+            }
+        });
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(400)).onAnimationEnd(anim);
+    }
+
+    @Test
+    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((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();
+            }
+        });
+        mActivityRule.runOnUiThread(anim::start);
+        assertTrue(endLatch.await(400, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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 ObjectAnimator anim = ObjectAnimator.ofMultiFloat(target, "position", path);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        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;
+            }
+        });
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(400)).onAnimationEnd(anim);
+    }
+
+    @Test
+    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((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], EPSILON);
+            assertEquals(expectedX * 2, values[1], EPSILON);
+            assertEquals(0f, values[2], 0.0f);
+        });
+
+        mActivityRule.runOnUiThread(anim::start);
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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 ObjectAnimator anim = ObjectAnimator.ofMultiInt(target, "position", path);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        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;
+            }
+        });
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(400)).onAnimationEnd(anim);
+    }
+
+    @Test
+    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((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]);
+        });
+
+        mActivityRule.runOnUiThread(anim::start);
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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(), 0.0f);
+                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;
+            }
+        });
+
+        mActivityRule.runOnUiThread(() -> {
+            anim1.start();
+            anim2.start();
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
     public void testIsStarted() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -242,11 +757,12 @@
         objAnimator.setInterpolator(interpolator);
         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
         startAnimation(objAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         assertTrue(objAnimator.isStarted());
-        Thread.sleep(100);
+        SystemClock.sleep(100);
     }
 
+    @Test
     public void testSetStartEndValues() throws Throwable {
         final float startValue = 100, endValue = 500;
         final AnimTarget target = new AnimTarget();
@@ -255,15 +771,12 @@
         anim1.setupStartValues();
         target.setTestValue(endValue);
         anim1.setupEndValues();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim1.start();
-                assertEquals(startValue, (Float) anim1.getAnimatedValue());
-                anim1.setCurrentFraction(1);
-                assertEquals(endValue, (Float) anim1.getAnimatedValue());
-                anim1.cancel();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            anim1.start();
+            assertEquals(startValue, (float) anim1.getAnimatedValue(), 0.0f);
+            anim1.setCurrentFraction(1);
+            assertEquals(endValue, (float) anim1.getAnimatedValue(), 0.0f);
+            anim1.cancel();
         });
 
         final Property property = AnimTarget.TEST_VALUE;
@@ -274,15 +787,12 @@
         target.setTestValue(endValue);
         final float endValueExpected = (Float) property.get(target);
         anim2.setupEndValues();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim2.start();
-                assertEquals(startValueExpected, (Float) anim2.getAnimatedValue());
-                anim2.setCurrentFraction(1);
-                assertEquals(endValueExpected, (Float) anim2.getAnimatedValue());
-                anim2.cancel();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            anim2.start();
+            assertEquals(startValueExpected, (float) anim2.getAnimatedValue(), 0.0f);
+            anim2.setCurrentFraction(1);
+            assertEquals(endValueExpected, (float) anim2.getAnimatedValue(), 0.0f);
+            anim2.cancel();
         });
 
         // This is a test that ensures that the values set on a Property-based animator
@@ -296,15 +806,47 @@
         target.setTestValue(endValue);
         final float endValueExpected3 = (Float) doubler.get(target);
         anim3.setupEndValues();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim3.start();
-                assertEquals(startValueExpected3, (Float) anim3.getAnimatedValue());
-                anim3.setCurrentFraction(1);
-                assertEquals(endValueExpected3, (Float) anim3.getAnimatedValue());
-                anim3.cancel();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            anim3.start();
+            assertEquals(startValueExpected3, (float) anim3.getAnimatedValue(), 0.0f);
+            anim3.setCurrentFraction(1);
+            assertEquals(endValueExpected3, (float) anim3.getAnimatedValue(), 0.0f);
+            anim3.cancel();
+        });
+    }
+
+    @Test
+    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);
+        mActivityRule.runOnUiThread(() -> {
+            anim.start();
+            final View decor = mActivity.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));
+
+        mActivityRule.runOnUiThread(() -> {
+            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();
         });
     }
 
@@ -348,20 +890,11 @@
     }
 
     private void startAnimation(final ObjectAnimator mObjectAnimator) throws Throwable {
-        Thread mAnimationRunnable = new Thread() {
-            public void run() {
-                mActivity.startAnimation(mObjectAnimator);
-            }
-        };
-        this.runTestOnUiThread(mAnimationRunnable);
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(mObjectAnimator));
     }
+
     private void startAnimation(final ObjectAnimator mObjectAnimator, final
             ObjectAnimator colorAnimator) throws Throwable {
-        Thread mAnimationRunnable = new Thread() {
-            public void run() {
-                mActivity.startAnimation(mObjectAnimator, colorAnimator);
-            }
-        };
-        this.runTestOnUiThread(mAnimationRunnable);
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(mObjectAnimator, colorAnimator));
     }
 }
diff --git a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
index 200ebce..3cbbbb2 100644
--- a/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
+++ b/tests/tests/animation/src/android/animation/cts/PropertyValuesHolderTest.java
@@ -15,53 +15,91 @@
  */
 package android.animation.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ArgbEvaluator;
 import android.animation.Keyframe;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.animation.TypeConverter;
 import android.animation.ValueAnimator;
+import android.app.Instrumentation;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.PointF;
 import android.graphics.drawable.ShapeDrawable;
-import android.test.ActivityInstrumentationTestCase2;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.FloatProperty;
 import android.util.Property;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
 
+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;
 
-public class PropertyValuesHolderTest extends
-        ActivityInstrumentationTestCase2<AnimationActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class PropertyValuesHolderTest {
+    private static final float LINE1_START = -32f;
+    private static final float LINE1_END = -2f;
+    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 static final float EPSILON = .001f;
+
+    private Instrumentation mInstrumentation;
     private AnimationActivity mActivity;
-    private Animator mAnimator;
     private long mDuration = 1000;
     private float mStartY;
     private float mEndY;
     private Object mObject;
     private String mProperty;
 
-    public PropertyValuesHolderTest() {
-        super(AnimationActivity.class);
+    @Rule
+    public ActivityTestRule<AnimationActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mInstrumentation.setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
+        mProperty = "y";
+        mStartY = mActivity.mStartY;
+        mEndY = mActivity.mStartY + mActivity.mDeltaY;
+        mObject = mActivity.view.newBall;
     }
 
-    public void setUp() throws Exception {
-         super.setUp();
-         setActivityInitialTouchMode(false);
-         mActivity = getActivity();
-         mAnimator = mActivity.createAnimatorWithDuration(mDuration);
-         mProperty = "y";
-         mStartY = mActivity.mStartY;
-         mEndY = mActivity.mStartY + mActivity.mDeltaY;
-         mObject = mActivity.view.newBall;
-    }
-
+    @Test
     public void testGetPropertyName() {
         float[] values = {mStartY, mEndY};
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat(mProperty, values);
         assertEquals(mProperty, pVHolder.getPropertyName());
     }
 
+    @Test
     public void testSetPropertyName() {
         float[] values = {mStartY, mEndY};
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat("", values);
@@ -69,6 +107,7 @@
         assertEquals(mProperty, pVHolder.getPropertyName());
     }
 
+    @Test
     public void testClone() {
         float[] values = {mStartY, mEndY};
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat(mProperty, values);
@@ -76,6 +115,7 @@
         assertEquals(pVHolder.getPropertyName(), cloneHolder.getPropertyName());
     }
 
+    @Test
     public void testSetValues() throws Throwable {
         float[] dummyValues = {100, 150};
         float[] values = {mStartY, mEndY};
@@ -102,46 +142,31 @@
 
     private void waitUntilFinished(ObjectAnimator objectAnimator, long timeoutMilliseconds)
             throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(1);
-        objectAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                latch.countDown();
-            }
-        });
-        latch.await(timeoutMilliseconds, TimeUnit.MILLISECONDS);
-        getInstrumentation().waitForIdleSync();
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        objectAnimator.addListener(listener);
+        verify(listener, within(timeoutMilliseconds)).onAnimationEnd(objectAnimator);
+        mInstrumentation.waitForIdleSync();
     }
 
     private void setTarget(final Animator animator, final Object target) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                animator.setTarget(target);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> animator.setTarget(target));
     }
 
     private void startSingleAnimation(final Animator animator) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.startSingleAnimation(animator);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.startSingleAnimation(animator));
     }
 
+    @Test
     public void testResetValues() throws Throwable {
         final float initialY = mActivity.view.newBall.getY();
         Keyframe emptyKeyframe1 = Keyframe.ofFloat(.0f);
         ObjectAnimator objAnimator1 = createAnimator(emptyKeyframe1, Keyframe.ofFloat(1f, 100f));
         startSingleAnimation(objAnimator1);
         assertTrue("Keyframe should be assigned a value", emptyKeyframe1.hasValue());
-        assertEquals("Keyframe should get the value from the target", emptyKeyframe1.getValue(),
-                initialY);
+        assertEquals("Keyframe should get the value from the target",
+                (float) emptyKeyframe1.getValue(), initialY, 0.0f);
         waitUntilFinished(objAnimator1, mDuration * 2);
-        assertEquals(100f, mActivity.view.newBall.getY());
+        assertEquals(100f, mActivity.view.newBall.getY(), 0.0f);
         startSingleAnimation(objAnimator1);
         waitUntilFinished(objAnimator1, mDuration * 2);
 
@@ -150,21 +175,22 @@
         ObjectAnimator objAnimator2 = createAnimator(emptyKeyframe2, Keyframe.ofFloat(1f, 200f));
         startSingleAnimation(objAnimator2);
         assertTrue("Keyframe should be assigned a value", emptyKeyframe2.hasValue());
-        assertEquals("Keyframe should get the value from the target", emptyKeyframe2.getValue(), 100f);
+        assertEquals("Keyframe should get the value from the target",
+                (float) emptyKeyframe2.getValue(), 100f, 0.0f);
         waitUntilFinished(objAnimator2, mDuration * 2);
-        assertEquals(200f, mActivity.view.newBall.getY());
+        assertEquals(200f, mActivity.view.newBall.getY(), 0.0f);
 
         // re-run first object animator. since its target did not change, it should have the same
         // start value for kf1
         startSingleAnimation(objAnimator1);
-        assertEquals(emptyKeyframe1.getValue(), initialY);
+        assertEquals((float) emptyKeyframe1.getValue(), initialY, 0.0f);
         waitUntilFinished(objAnimator1, mDuration * 2);
 
         Keyframe fullKeyframe = Keyframe.ofFloat(.0f, 333f);
         ObjectAnimator objAnimator3 = createAnimator(fullKeyframe, Keyframe.ofFloat(1f, 500f));
         startSingleAnimation(objAnimator3);
         assertEquals("When keyframe has value, should not be assigned from the target object",
-                fullKeyframe.getValue(), 333f);
+                (float) fullKeyframe.getValue(), 333f, 0.0f);
         waitUntilFinished(objAnimator3, mDuration * 2);
 
         // now, null out the target of the first animator
@@ -172,15 +198,16 @@
         setTarget(objAnimator1, null);
         startSingleAnimation(objAnimator1);
         assertTrue("Keyframe should get a value", emptyKeyframe1.hasValue());
-        assertEquals("Keyframe should get the updated Y value", emptyKeyframe1.getValue(), updatedY);
+        assertEquals("Keyframe should get the updated Y value",
+                (float) emptyKeyframe1.getValue(), updatedY, 0.0f);
         waitUntilFinished(objAnimator1, mDuration * 2);
-        assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY());
+        assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY(), 0.0f);
 
         // now, reset the target of the fully defined animation.
         setTarget(objAnimator3, null);
         startSingleAnimation(objAnimator3);
         assertEquals("When keyframe is fully defined, its value should not change when target is"
-                + " reset", fullKeyframe.getValue(), 333f);
+                + " reset", (float) fullKeyframe.getValue(), 333f, 0.0f);
         waitUntilFinished(objAnimator3, mDuration * 2);
 
         // run the other one to change Y value
@@ -194,12 +221,13 @@
         assertTrue("Keyframe should get a value when target is set to another view of the same"
                 + " class", emptyKeyframe1.hasValue());
         assertEquals("Keyframe should get the updated Y value when target is set to another view"
-                + " of the same class", emptyKeyframe1.getValue(), updatedY);
+                + " of the same class", (float) emptyKeyframe1.getValue(), updatedY, 0.0f);
         waitUntilFinished(objAnimator1, mDuration * 2);
-        assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY());
+        assertEquals("Animation should run as expected", 100f, mActivity.view.newBall.getY(), 0.0f);
     }
 
-    public void testOffloat() throws Throwable {
+    @Test
+    public void testOfFloat() throws Throwable {
         float[] values = {mStartY, mEndY};
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat(mProperty, values);
         assertNotNull(pVHolder);
@@ -213,9 +241,10 @@
         assertResults(yArray, mStartY, mEndY);
     }
 
+    @Test
     public void testOfFloat_Property() throws Throwable {
         float[] values = {mStartY, mEndY};
-        ShapeHolderYProperty property=new ShapeHolderYProperty(ShapeHolder.class.getClass(),"y");
+        ShapeHolderYProperty property=new ShapeHolderYProperty(ShapeHolder.class,"y");
         property.setObject(mObject);
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat(property, values);
         assertNotNull(pVHolder);
@@ -229,6 +258,7 @@
         assertResults(yArray, mStartY, mEndY);
     }
 
+    @Test
     public void testOfInt() throws Throwable {
         int start = 0;
         int end = 10;
@@ -238,18 +268,15 @@
         final ObjectAnimator objAnimator = ObjectAnimator.ofPropertyValuesHolder(mObject,pVHolder);
         assertTrue(objAnimator != null);
         setAnimatorProperties(objAnimator);
-        this.runTestOnUiThread(new Runnable(){
-            public void run() {
-                objAnimator.start();
-            }
-        });
-        Thread.sleep(1000);
+        mActivityRule.runOnUiThread(objAnimator::start);
+        SystemClock.sleep(1000);
         assertTrue(objAnimator.isRunning());
         Integer animatedValue = (Integer) objAnimator.getAnimatedValue();
         assertTrue(animatedValue >= start);
         assertTrue(animatedValue <= end);
     }
 
+    @Test
     public void testOfInt_Property() throws Throwable{
         Object object = mActivity.view;
         String property = "backgroundColor";
@@ -257,7 +284,7 @@
         int endColor = mActivity.view.BLUE;
         int values[] = {startColor, endColor};
 
-        ViewColorProperty colorProperty=new ViewColorProperty(Integer.class.getClass(),property);
+        ViewColorProperty colorProperty=new ViewColorProperty(Integer.class,property);
         colorProperty.setObject(object);
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofInt(colorProperty, values);
         assertNotNull(pVHolder);
@@ -271,16 +298,391 @@
         ObjectAnimator objectAnimator = (ObjectAnimator) mActivity.createAnimatorWithDuration(
             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());
+        SystemClock.sleep(1000);
+        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);
     }
 
+    @Test
+    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);
+
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        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;
+            }
+        });
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(400)).onAnimationEnd(anim);
+    }
+
+    @Test
+    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((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], EPSILON);
+            assertEquals(expectedX * 2, values[1], EPSILON);
+            assertEquals(0.0f, values[2], 0.0f);
+        });
+
+        mActivityRule.runOnUiThread(anim::start);
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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 PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt("position", path);
+        final ValueAnimator anim = ValueAnimator.ofPropertyValuesHolder(pvh);
+        // Linear interpolator
+        anim.setInterpolator(null);
+        anim.setDuration(200);
+
+        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;
+            }
+        });
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(anim::start);
+        verify(listener, within(400)).onAnimationEnd(anim);
+    }
+
+    @Test
+    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((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]);
+        });
+
+        mActivityRule.runOnUiThread(anim::start);
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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(), 0.0f);
+                assertEquals(fraction, anim3.getAnimatedFraction(), 0.0f);
+                float distance = (Float) anim1.getAnimatedValue();
+                PointF position = (PointF) anim2.getAnimatedValue();
+                PointF positionReverseSign = (PointF) anim3.getAnimatedValue();
+                assertEquals(position.x, -positionReverseSign.x, 0.0f);
+                assertEquals(position.y, -positionReverseSign.y, 0.0f);
+
+                // 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;
+            }
+        });
+
+        mActivityRule.runOnUiThread(() -> {
+            anim1.start();
+            anim2.start();
+            anim3.start();
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    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((ValueAnimator animation) -> {
+            assertEquals(anim1.getAnimatedFraction(), anim2.getAnimatedFraction(), 0.0f);
+            // 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, 0.0f);
+            assertEquals(0f, value1.y, 0.0f);
+        });
+        anim2.setDuration(100);
+        anim2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+
+        mActivityRule.runOnUiThread(() -> {
+            anim1.start();
+            anim2.start();
+        });
+
+        // Wait until both of the animations finish
+        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
     public void testSetProperty() throws Throwable {
         float[] values = {mStartY, mEndY};
-        ShapeHolderYProperty property=new ShapeHolderYProperty(ShapeHolder.class.getClass(),"y");
+        ShapeHolderYProperty property=new ShapeHolderYProperty(ShapeHolder.class,"y");
         property.setObject(mObject);
         PropertyValuesHolder pVHolder = PropertyValuesHolder.ofFloat("", values);
         pVHolder.setProperty(property);
@@ -294,7 +696,7 @@
 
     class ShapeHolderYProperty extends Property {
         private ShapeHolder shapeHolder ;
-        private Class type = Float.class.getClass();
+        private Class type = Float.class;
         private String name = "y";
         @SuppressWarnings("unchecked")
         public ShapeHolderYProperty(Class type, String name) throws Exception {
@@ -338,7 +740,7 @@
 
     class ViewColorProperty extends Property {
         private View view ;
-        private Class type = Integer.class.getClass();
+        private Class type = Integer.class;
         private String name = "backgroundColor";
         @SuppressWarnings("unchecked")
         public ViewColorProperty(Class type, String name) throws Exception {
@@ -391,7 +793,7 @@
         for(int i = 0; i < 3; i++) {
             float y = mActivity.view.newBall.getY();
             yArray[i] = y;
-            Thread.sleep(300);
+            SystemClock.sleep(300);
         }
         return yArray;
     }
@@ -409,21 +811,12 @@
     }
 
     private void startAnimation(final Animator animator) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.startAnimation(animator);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
     }
 
     private void startAnimation(final ObjectAnimator mObjectAnimator,
             final ObjectAnimator colorAnimator) throws Throwable {
-        Thread mAnimationRunnable = new Thread() {
-            public void run() {
-                mActivity.startAnimation(mObjectAnimator, colorAnimator);
-            }
-        };
-        this.runTestOnUiThread(mAnimationRunnable);
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(mObjectAnimator, colorAnimator));
     }
 }
 
diff --git a/tests/tests/animation/src/android/animation/cts/ShapeHolder.java b/tests/tests/animation/src/android/animation/cts/ShapeHolder.java
index 4723c67..e35ef64 100644
--- a/tests/tests/animation/src/android/animation/cts/ShapeHolder.java
+++ b/tests/tests/animation/src/android/animation/cts/ShapeHolder.java
@@ -16,10 +16,10 @@
 
 package android.animation.cts;
 
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.Shape;
 import android.graphics.Paint;
 import android.graphics.RadialGradient;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.Shape;
 
 /**
  * A data structure that holds a Shape and various properties that can be used to define
diff --git a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
index b778530..605e1c1 100644
--- a/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
+++ b/tests/tests/animation/src/android/animation/cts/ValueAnimatorTest.java
@@ -15,42 +15,84 @@
  */
 package android.animation.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+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.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
-import android.test.ActivityInstrumentationTestCase2;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public class ValueAnimatorTest extends
-        ActivityInstrumentationTestCase2<AnimationActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ValueAnimatorTest {
+    private static final float EPSILON = 0.0001f;
+    private static float sPreviousAnimatorScale = 1.0f;
+
     private AnimationActivity mActivity;
     private ValueAnimator mValueAnimator;
-    private long mDuration = 2000;
+    private final long mDuration = 2000;
 
-    public ValueAnimatorTest() {
-        super(AnimationActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<AnimationActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
         mValueAnimator = mActivity.createAnimatorWithDuration(mDuration);
     }
 
-    public void testDuration() throws Throwable {
-        final long duration = 2000;
-        ValueAnimator valueAnimatorLocal = mActivity.createAnimatorWithDuration(duration);
-        startAnimation(valueAnimatorLocal);
-        assertEquals(duration, valueAnimatorLocal.getDuration());
+    @BeforeClass
+    public static void beforeClass() {
+        sPreviousAnimatorScale = ValueAnimator.getDurationScale();
+        ValueAnimator.setDurationScale(1.0f);
     }
 
+    @AfterClass
+    public static void afterClass() {
+        ValueAnimator.setDurationScale(sPreviousAnimatorScale);
+    }
+
+    @Test
+    public void testDuration() throws Throwable {
+        ValueAnimator valueAnimatorLocal = mActivity.createAnimatorWithDuration(mDuration);
+        startAnimation(valueAnimatorLocal);
+        assertEquals(mDuration, valueAnimatorLocal.getDuration());
+    }
+
+    @Test
     public void testIsRunning() throws Throwable {
         assertFalse(mValueAnimator.isRunning());
         startAnimation(mValueAnimator);
@@ -58,6 +100,7 @@
         assertTrue(valueAnimatorReturned.isRunning());
     }
 
+    @Test
     public void testIsStarted() throws Throwable {
         assertFalse(mValueAnimator.isRunning());
         assertFalse(mValueAnimator.isStarted());
@@ -68,6 +111,7 @@
         assertTrue(mValueAnimator.isStarted());
     }
 
+    @Test
     public void testRepeatMode() throws Throwable {
         ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatMode(
             ValueAnimator.RESTART);
@@ -75,6 +119,7 @@
         assertEquals(ValueAnimator.RESTART, mValueAnimator.getRepeatMode());
     }
 
+    @Test
     public void testRepeatCount() throws Throwable {
         int repeatCount = 2;
         ValueAnimator mValueAnimator = mActivity.createAnimatorWithRepeatCount(repeatCount);
@@ -82,203 +127,287 @@
         assertEquals(repeatCount, mValueAnimator.getRepeatCount());
     }
 
+    @Test
     public void testStartDelay() {
         long startDelay = 1000;
         mValueAnimator.setStartDelay(startDelay);
         assertEquals(startDelay, mValueAnimator.getStartDelay());
     }
 
+    @Test
     public void testGetCurrentPlayTime() throws Throwable {
         startAnimation(mValueAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         long currentPlayTime = mValueAnimator.getCurrentPlayTime();
         assertTrue(currentPlayTime  >  0);
     }
 
-    /**
-     * Test for equality within some epsilon. This accounts for minor differences
-     * due to floating-point accuracy.
-     */
-    private void assertRoughlyEqual(float expected, float actual) {
-        final float epsilon = .001f;
-        assertTrue(actual > (expected - epsilon) && actual < (expected + epsilon));
-    }
-
+    @Test
     public void testSetCurrentPlayTime() throws Throwable {
         final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
         final ValueAnimator delayedAnim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
         delayedAnim.setStartDelay(mDuration);
         final long proposedCurrentPlayTime = mDuration / 2;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim.setCurrentPlayTime(mDuration / 2);
-                long currentPlayTime = anim.getCurrentPlayTime();
-                float currentFraction = anim.getAnimatedFraction();
-                float currentValue = (Float) anim.getAnimatedValue();
-                assertEquals(proposedCurrentPlayTime, currentPlayTime);
-                assertRoughlyEqual(.5f, currentFraction);
-                assertRoughlyEqual(50, currentValue);
+        mActivityRule.runOnUiThread(() -> {
+            anim.setCurrentPlayTime(mDuration / 2);
+            long currentPlayTime = anim.getCurrentPlayTime();
+            float currentFraction = anim.getAnimatedFraction();
+            float currentValue = (Float) anim.getAnimatedValue();
+            assertEquals(proposedCurrentPlayTime, currentPlayTime);
+            assertEquals(.5f, currentFraction, EPSILON);
+            assertEquals(50, currentValue, EPSILON);
 
-                delayedAnim.setCurrentPlayTime(mDuration / 2);
-                currentPlayTime = delayedAnim.getCurrentPlayTime();
-                currentFraction = delayedAnim.getAnimatedFraction();
-                currentValue = (Float) delayedAnim.getAnimatedValue();
-                assertEquals(proposedCurrentPlayTime, currentPlayTime);
-                assertRoughlyEqual(.5f, currentFraction);
-                assertRoughlyEqual(50, currentValue);
-            }
+            delayedAnim.setCurrentPlayTime(mDuration / 2);
+            currentPlayTime = delayedAnim.getCurrentPlayTime();
+            currentFraction = delayedAnim.getAnimatedFraction();
+            currentValue = (Float) delayedAnim.getAnimatedValue();
+            assertEquals(proposedCurrentPlayTime, currentPlayTime);
+            assertEquals(.5f, currentFraction, EPSILON);
+            assertEquals(50, currentValue, EPSILON);
         });
         // Now make sure that it's still true a little later, to test that we're
         // getting a result based on the seek time, not the wall clock time
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         long currentPlayTime = anim.getCurrentPlayTime();
         float currentFraction = anim.getAnimatedFraction();
         float currentValue = (Float) anim.getAnimatedValue();
         assertEquals(proposedCurrentPlayTime, currentPlayTime);
-        assertRoughlyEqual(.5f, currentFraction);
-        assertRoughlyEqual(50, currentValue);
+        assertEquals(.5f, currentFraction, EPSILON);
+        assertEquals(50, currentValue, EPSILON);
 
         currentPlayTime = delayedAnim.getCurrentPlayTime();
         currentFraction = delayedAnim.getAnimatedFraction();
         currentValue = (Float) delayedAnim.getAnimatedValue();
         assertEquals(proposedCurrentPlayTime, currentPlayTime);
-        assertRoughlyEqual(.5f, currentFraction);
-        assertRoughlyEqual(50, currentValue);
+        assertEquals(.5f, currentFraction, EPSILON);
+        assertEquals(50, currentValue, EPSILON);
 
         // Finally, start() the delayed animation and check that the play time was
         // not affected by playing during the delay
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delayedAnim.start();
-                long currentPlayTime = delayedAnim.getCurrentPlayTime();
-                float currentFraction = delayedAnim.getAnimatedFraction();
-                float currentValue = (Float) delayedAnim.getAnimatedValue();
-                assertEquals(proposedCurrentPlayTime, currentPlayTime);
-                assertRoughlyEqual(.5f, currentFraction);
-                assertRoughlyEqual(50, currentValue);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            delayedAnim.start();
+            assertEquals(proposedCurrentPlayTime, delayedAnim.getCurrentPlayTime());
+            assertEquals(.5f, delayedAnim.getAnimatedFraction(), EPSILON);
+            assertEquals(50, (float) delayedAnim.getAnimatedValue(), EPSILON);
         });
 
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         currentPlayTime = delayedAnim.getCurrentPlayTime();
         currentFraction = delayedAnim.getAnimatedFraction();
         currentValue = (Float) delayedAnim.getAnimatedValue();
         assertEquals(proposedCurrentPlayTime, currentPlayTime);
-        assertRoughlyEqual(.5f, currentFraction);
-        assertRoughlyEqual(50, currentValue);
+        assertEquals(.5f, currentFraction, EPSILON);
+        assertEquals(50, currentValue, EPSILON);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delayedAnim.cancel();
-            }
-        });
+        mActivityRule.runOnUiThread(delayedAnim::cancel);
     }
 
+    @Test
+    public void testPauseListener() throws Throwable {
+        // Adds two pause listeners to the animator, and remove one after the animator is paused.
+        Animator.AnimatorPauseListener l1 = mock(Animator.AnimatorPauseListener.class);
+        Animator.AnimatorPauseListener l2 = mock(Animator.AnimatorPauseListener.class);
+        ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f);
+        a1.addPauseListener(l1);
+        a1.addPauseListener(l2);
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+            a1.pause();
+            verify(l1, times(1)).onAnimationPause(a1);
+            verify(l2, times(1)).onAnimationPause(a1);
+            a1.removePauseListener(l2);
+            a1.resume();
+        });
+
+        // Check that the pause listener that is removed doesn't have resume called.
+        verify(l1, times(1)).onAnimationResume(a1);
+        verify(l2, times(0)).onAnimationResume(a1);
+    }
+
+    @Test
     public void testSetCurrentPlayTimeAfterStart() throws Throwable {
         // This test sets current play time right after start() is called on a non-delayed animation
         final long duration = 100;
         final float seekFraction = 0.2f;
         final CountDownLatch frameUpdateLatch = new CountDownLatch(1);
-        final CountDownLatch endLatch = new CountDownLatch(1);
 
         final ValueAnimator anim  = ValueAnimator.ofFloat(0, 1).setDuration(duration);
         anim.setInterpolator(null);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                endLatch.countDown();
-            }
-        });
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim.start();
-                anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    float fractionOnFirstFrame = -1f;
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        if (fractionOnFirstFrame < 0) {
-                            // First frame:
-                            fractionOnFirstFrame = animation.getAnimatedFraction();
-                            assertRoughlyEqual(seekFraction, fractionOnFirstFrame);
-                            frameUpdateLatch.countDown();
-                        } else {
-                            assertTrue(animation.getAnimatedFraction() >= fractionOnFirstFrame);
-                        }
+        final Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
+        anim.addListener(listener);
+        mActivityRule.runOnUiThread(() -> {
+            anim.start();
+            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                float fractionOnFirstFrame = -1f;
+
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    if (fractionOnFirstFrame < 0) {
+                        // First frame:
+                        fractionOnFirstFrame = animation.getAnimatedFraction();
+                        assertEquals(seekFraction, fractionOnFirstFrame, EPSILON);
+                        frameUpdateLatch.countDown();
+                    } else {
+                        assertTrue(animation.getAnimatedFraction() >= fractionOnFirstFrame);
                     }
-                });
-                long currentPlayTime = (long) (seekFraction * (float) duration);
-                anim.setCurrentPlayTime(currentPlayTime);
-            }
+                }
+            });
+            long currentPlayTime = (long) (seekFraction * (float) duration);
+            anim.setCurrentPlayTime(currentPlayTime);
         });
         assertTrue(frameUpdateLatch.await(100, TimeUnit.MILLISECONDS));
-        assertTrue(endLatch.await(200, TimeUnit.MILLISECONDS));
+        verify(listener, within(200)).onAnimationEnd(anim);
     }
 
+    @Test
     public void testSetCurrentFraction() throws Throwable {
         final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
         final long proposedCurrentPlayTime = mDuration / 2;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim.setCurrentFraction(.5f);
-                long currentPlayTime = anim.getCurrentPlayTime();
-                float currentFraction = anim.getAnimatedFraction();
-                float currentValue = (Float) anim.getAnimatedValue();
-                assertEquals(proposedCurrentPlayTime, currentPlayTime);
-                assertRoughlyEqual(.5f, currentFraction);
-                assertRoughlyEqual(50, currentValue);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            anim.setCurrentFraction(.5f);
+            long currentPlayTime = anim.getCurrentPlayTime();
+            float currentFraction = anim.getAnimatedFraction();
+            float currentValue = (Float) anim.getAnimatedValue();
+            assertEquals(proposedCurrentPlayTime, currentPlayTime);
+            assertEquals(.5f, currentFraction, EPSILON);
+            assertEquals(50, currentValue, EPSILON);
         });
         // Now make sure that it's still true a little later, to test that we're
         // getting a result based on the seek time, not the wall clock time
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         long currentPlayTime = anim.getCurrentPlayTime();
         float currentFraction = anim.getAnimatedFraction();
         float currentValue = (Float) anim.getAnimatedValue();
         assertEquals(proposedCurrentPlayTime, currentPlayTime);
-        assertRoughlyEqual(.5f, currentFraction);
-        assertRoughlyEqual(50, currentValue);
+        assertEquals(.5f, currentFraction, EPSILON);
+        assertEquals(50, currentValue, EPSILON);
     }
 
-    public void testReverseRightAfterStart() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Reverse() right after start() should trigger immediate end() at fraction 0.
-                final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
-                anim.start();
-                assertTrue(anim.isStarted());
-                anim.reverse();
-                assertFalse(anim.isStarted());
-                assertEquals(0f, anim.getAnimatedFraction());
-            }
-        });
+    @UiThreadTest
+    @Test
+    public void testReverseRightAfterStart() {
+        // Reverse() right after start() should trigger immediate end() at fraction 0.
+        final ValueAnimator anim = ValueAnimator.ofFloat(0, 100).setDuration(mDuration);
+        anim.start();
+        assertTrue(anim.isStarted());
+        anim.reverse();
+        assertFalse(anim.isStarted());
+        assertEquals(0f, anim.getAnimatedFraction(), 0.0f);
     }
 
+    @Test
     public void testGetFrameDelay() throws Throwable {
         final long frameDelay = 10;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mValueAnimator.setFrameDelay(frameDelay);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mValueAnimator.setFrameDelay(frameDelay));
         startAnimation(mValueAnimator);
-        Thread.sleep(100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                long actualFrameDelay = mValueAnimator.getFrameDelay();
-                assertEquals(frameDelay, actualFrameDelay);
-            }
+        SystemClock.sleep(100);
+        mActivityRule.runOnUiThread(() -> {
+            long actualFrameDelay = mValueAnimator.getFrameDelay();
+            assertEquals(frameDelay, actualFrameDelay);
         });
     }
 
+    @Test
+    public void testUpdateListeners() throws Throwable {
+        ValueAnimator.AnimatorUpdateListener l1 = mock(ValueAnimator.AnimatorUpdateListener.class);
+        ValueAnimator.AnimatorUpdateListener l2 = mock(ValueAnimator.AnimatorUpdateListener.class);
+        ValueAnimator.AnimatorUpdateListener l3 = mock(ValueAnimator.AnimatorUpdateListener.class);
+        ValueAnimator.AnimatorUpdateListener l4 = mock(ValueAnimator.AnimatorUpdateListener.class);
+
+        AnimatorListenerAdapter listener = mock(AnimatorListenerAdapter.class);
+
+        ValueAnimator a1 = ValueAnimator.ofFloat(0, 1f);
+        a1.setDuration(50);
+        a1.addUpdateListener(l1);
+        a1.addUpdateListener(l2);
+        a1.removeAllUpdateListeners();
+
+        a1.addUpdateListener(l3);
+        a1.addUpdateListener(l4);
+        a1.removeUpdateListener(l3);
+
+        a1.addListener(listener);
+
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+        });
+
+        // Wait for the anim to finish.
+        verify(listener, within(200)).onAnimationEnd(a1);
+
+        verify(l1, times(0)).onAnimationUpdate(a1);
+        verify(l2, times(0)).onAnimationUpdate(a1);
+        verify(l3, times(0)).onAnimationUpdate(a1);
+        verify(l4, atLeast(1)).onAnimationUpdate(a1);
+    }
+
+    @Test
+    public void testValuesSetterAndGetter() throws Throwable {
+
+        ValueAnimator a2 = ValueAnimator.ofPropertyValuesHolder();
+        PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("scaleX", 0f, 1f);
+        PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 2f);
+        a2.setValues(p1, p2);
+        PropertyValuesHolder[] holders = a2.getValues();
+        assertEquals(2, holders.length);
+
+        // Use the PropertyValueHolders returned from the getter to initialize the animator, in
+        // order to test the getter.
+        ValueAnimator a1 = ValueAnimator.ofPropertyValuesHolder(holders);
+        a1.setDuration(50);
+        a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float scaleX = (Float) animation.getAnimatedValue("scaleX");
+                float scaleY = (Float) animation.getAnimatedValue("scaleY");
+                assertTrue(scaleX >= 0f && scaleX <= 1f);
+                assertTrue(scaleY >= 1f && scaleY <= 2f);
+            }
+        });
+        AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class);
+        a1.addListener(l1);
+
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+        });
+
+        verify(l1, within(200)).onAnimationEnd(a1);
+    }
+
+    @Test
+    public void testSetObjectValues() throws Throwable {
+        TypeEvaluator<PointF> eval = new TypeEvaluator<PointF>() {
+            PointF tmpValue = new PointF();
+            @Override
+            public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
+                tmpValue.x = fraction * startValue.x + (1f - fraction) * endValue.x;
+                tmpValue.y = fraction * startValue.y + (1f - fraction) * endValue.y;
+                return tmpValue;
+            }
+        };
+
+        ValueAnimator a1 = new ValueAnimator();
+        a1.setDuration(50);
+        a1.setObjectValues(new PointF(0, 0), new PointF(1, 1));
+        a1.setEvaluator(eval);
+        a1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                PointF point = (PointF) animation.getAnimatedValue();
+                assertTrue(point.x >= 0f && point.x <= 1f);
+                assertTrue(point.y >= 0f && point.y <= 1f);
+            }
+        });
+        AnimatorListenerAdapter l1 = mock(AnimatorListenerAdapter.class);
+        a1.addListener(l1);
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+        });
+
+        verify(l1, within(200)).onAnimationEnd(a1);
+    }
+
+    @Test
     public void testSetInterpolator() throws Throwable {
         AccelerateInterpolator interpolator = new AccelerateInterpolator();
         ValueAnimator mValueAnimator = mActivity.createAnimatorWithInterpolator(interpolator);
@@ -286,13 +415,15 @@
         assertTrue(interpolator.equals(mValueAnimator.getInterpolator()));
     }
 
+    @Test
     public void testCancel() throws Throwable {
         startAnimation(mValueAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         cancelAnimation(mValueAnimator);
         assertFalse(mValueAnimator.isRunning());
     }
 
+    @Test
     public void testEnd() throws Throwable {
         Object object = mActivity.view.newBall;
         String property = "y";
@@ -304,12 +435,13 @@
         objAnimator.setInterpolator(new AccelerateInterpolator());
         objAnimator.setRepeatMode(ValueAnimator.REVERSE);
         startAnimation(objAnimator);
-        Thread.sleep(100);
+        SystemClock.sleep(100);
         endAnimation(objAnimator);
         float y = mActivity.view.newBall.getY();
-        assertEquals(y, endY);
+        assertEquals(y, endY, 0.0f);
     }
 
+    @Test
     public void testGetAnimatedFraction() throws Throwable {
         ValueAnimator objAnimator = getAnimator();
         startAnimation(objAnimator);
@@ -322,6 +454,7 @@
         }
     }
 
+    @Test
     public void testGetAnimatedValue() throws Throwable {
         ValueAnimator objAnimator = getAnimator();
         startAnimation(objAnimator);
@@ -332,6 +465,8 @@
             assertTrue(errorMessage(animatedValues), animatedValues[j + 1] >= animatedValues[j]);
         }
     }
+
+    @Test
     public void testGetAnimatedValue_PropertyName() throws Throwable {
         String property = "y";
 
@@ -345,6 +480,7 @@
         }
     }
 
+    @Test
     public void testOfFloat() throws Throwable {
         float start = 0.0f;
         float end = 1.0f;
@@ -355,12 +491,8 @@
         valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
         valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
 
-        this.runTestOnUiThread(new Runnable(){
-            public void run() {
-                valueAnimatorLocal.start();
-            }
-        });
-        Thread.sleep(100);
+        mActivityRule.runOnUiThread(valueAnimatorLocal::start);
+        SystemClock.sleep(100);
         boolean isRunning = valueAnimatorLocal.isRunning();
         assertTrue(isRunning);
 
@@ -369,6 +501,7 @@
         assertTrue(animatedValue <= end);
     }
 
+    @Test
     public void testOfInt() throws Throwable {
         int start = 0;
         int end = 10;
@@ -379,12 +512,8 @@
         valueAnimatorLocal.setInterpolator(new AccelerateInterpolator());
         valueAnimatorLocal.setRepeatMode(ValueAnimator.RESTART);
 
-        this.runTestOnUiThread(new Runnable(){
-            public void run() {
-                valueAnimatorLocal.start();
-            }
-        });
-        Thread.sleep(100);
+        mActivityRule.runOnUiThread(valueAnimatorLocal::start);
+        SystemClock.sleep(100);
         boolean isRunning = valueAnimatorLocal.isRunning();
         assertTrue(isRunning);
 
@@ -393,28 +522,127 @@
         assertTrue(animatedValue <= end);
     }
 
+    @Test
+    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((ValueAnimator animation) -> {
+            if (animation.getAnimatedFraction() > .05f) {
+                latch.countDown();
+            }
+        });
+
+        mActivityRule.runOnUiThread(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);
+
+        mActivityRule.runOnUiThread(valueAnimatorLocal::cancel);
+    }
+
+    @Test
     public void testNoDelayOnSeekAnimation() throws Throwable {
         ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
         animator.setInterpolator(new LinearInterpolator());
         animator.setStartDelay(1000);
         animator.setDuration(300);
         animator.setCurrentPlayTime(150);
-        EventWatcher watcher = new EventWatcher();
+        final Animator.AnimatorListener watcher = mock(Animator.AnimatorListener.class);
         animator.addListener(watcher);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                animator.start();
-            }
-        });
-        assertTrue(watcher.start.await(0, TimeUnit.MILLISECONDS));
+        mActivityRule.runOnUiThread(animator::start);
+        verify(watcher, times(1)).onAnimationStart(animator);
         assertTrue(((Float)animator.getAnimatedValue()) >= 0.5f);
         assertTrue(animator.getAnimatedFraction() >= 0.5f);
-        runTestOnUiThread(new Runnable() {
+        mActivityRule.runOnUiThread(animator::cancel);
+    }
+
+    @Test
+    public void testNotifiesAfterEnd() throws Throwable {
+        final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+        animator.addListener(new AnimatorListenerAdapter() {
             @Override
-            public void run() {
-                animator.cancel();
+            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);
+            }
+        });
+        mActivityRule.runOnUiThread(() -> {
+            animator.start();
+            animator.end();
+        });
+    }
+
+    @Test
+    public void testAnimatorsEnabled() throws Throwable {
+        float currentDurationScale = ValueAnimator.getDurationScale();
+        try {
+            testAnimatorsEnabledImpl(true);
+            testAnimatorsEnabledImpl(false);
+        } finally {
+            // restore scale value to avoid messing up future tests
+            ValueAnimator.setDurationScale(currentDurationScale);
+        }
+    }
+
+    private void testAnimatorsEnabledImpl(boolean enabled) throws Throwable {
+        final CountDownLatch endLatch = new CountDownLatch(1);
+        final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+        animator.setDuration(1000);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                endLatch.countDown();
+            }
+        });
+        mActivityRule.runOnUiThread(() -> {
+            animator.start();
+        });
+
+        float durationScale = enabled ? 1 : 0;
+        ValueAnimator.setDurationScale(durationScale);
+
+        if (enabled) {
+            assertTrue("Animators not enabled with duration scale 1",
+                    ValueAnimator.areAnimatorsEnabled());
+            assertFalse("Animator ended too early when animators enabled = ",
+                    endLatch.await(50, TimeUnit.MILLISECONDS));
+        } else {
+            assertFalse("Animators enabled with duration scale 0",
+                    ValueAnimator.areAnimatorsEnabled());
+            assertTrue("Animator did not end when animators enabled = ",
+                    endLatch.await(50, TimeUnit.MILLISECONDS));
+        }
+        mActivityRule.runOnUiThread(() -> {
+            animator.end();
         });
     }
 
@@ -435,7 +663,7 @@
             long sleepTime, String property) throws InterruptedException {
         float[] values = new float[n];
         for(int i = 0; i < n; i++){
-            Thread.sleep(sleepTime);
+            SystemClock.sleep(sleepTime);
             float value = 0.0f;
             if(methodName.equals("getAnimatedFraction()")) {
                 value = animator.getAnimatedFraction();
@@ -450,27 +678,15 @@
     }
 
     private void startAnimation(final ValueAnimator animator) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.startAnimation(animator);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.startAnimation(animator));
     }
 
     private void endAnimation(final ValueAnimator animator) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                animator.end();
-            }
-        });
+        mActivityRule.runOnUiThread(animator::end);
     }
 
     private void cancelAnimation(final ValueAnimator animator) throws Throwable {
-        this.runTestOnUiThread(new Runnable() {
-            public void run() {
-                animator.cancel();
-            }
-        });
+        mActivityRule.runOnUiThread(animator::cancel);
     }
 
     private String errorMessage(float[] values) {
@@ -480,27 +696,4 @@
         }
         return message.toString();
     }
-
-    class EventWatcher implements Animator.AnimatorListener {
-        public CountDownLatch start = new CountDownLatch(1);
-        public CountDownLatch end = new CountDownLatch(1);
-        public CountDownLatch cancel = new CountDownLatch(1);
-        public CountDownLatch repeat = new CountDownLatch(1);
-
-        public void onAnimationCancel(Animator animation) {
-            cancel.countDown();
-        }
-
-        public void onAnimationEnd(Animator animation) {
-            end.countDown();
-        }
-
-        public void onAnimationRepeat(Animator animation) {
-            repeat.countDown();
-        }
-
-        public void onAnimationStart(Animator animation) {
-            start.countDown();
-        }
-    }
 }
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/ActivityTransitionActivity.java b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
index 0e413c9..288a3e9 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionActivity.java
@@ -20,6 +20,8 @@
 import android.app.SharedElementCallback;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.transition.ChangeBounds;
@@ -192,7 +194,9 @@
             @Override
             public void onTransitionEnd(Transition transition) {
                 mEntering = false;
-                setResult(RESULT_OK);
+                Intent intent = new Intent();
+                intent.putExtra("Extra", new ExtraData("result"));
+                setResult(RESULT_OK, intent);
                 getWindow().getDecorView().post(new Runnable() {
                     @Override
                     public void run() {
@@ -219,6 +223,17 @@
     }
 
     @Override
+    public void onActivityReenter(int resultCode, Intent data) {
+        if (resultCode == RESULT_OK) {
+            ExtraData extraData = data.getParcelableExtra("Extra");
+            if (!"result".equals(extraData.data)) {
+                throw new RuntimeException("Incorrect returned intent data in onActivityReenter");
+            }
+        }
+        super.onActivityReenter(resultCode, data);
+    }
+
+    @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         this.resultCode = resultCode;
@@ -286,4 +301,41 @@
             return mVisibility != -1;
         }
     }
+
+    /**
+     * Used to test the class loader of the returned intent.
+     */
+    public static class ExtraData implements Parcelable {
+        public final String data;
+
+        public ExtraData(String data) {
+            this.data = data;
+        }
+
+        protected ExtraData(Parcel in) {
+            this.data = in.readString();
+        }
+
+        public static final Creator<ExtraData> CREATOR = new Creator<ExtraData>() {
+            @Override
+            public ExtraData createFromParcel(Parcel in) {
+                return new ExtraData(in);
+            }
+
+            @Override
+            public ExtraData[] newArray(int size) {
+                return new ExtraData[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(data);
+        }
+    }
 }
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
index 25d885a..fd8a230 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/ActivityTransitionTest.java
@@ -98,8 +98,8 @@
         });
 
         assertTrue("Activity didn't finish!",
-                mActivity.returnLatch.await(1500, TimeUnit.MILLISECONDS));
-        assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
+                mActivity.returnLatch.await(3000, TimeUnit.MILLISECONDS));
+        assertTrue(mActivity.reenterLatch.await(1000, TimeUnit.MILLISECONDS));
         assertNotNull(mReceiver.resultData);
         assertEquals(2, mReceiver.resultData.getInt(
                 ActivityTransitionActivity.ARRIVE_COUNT, -1));
@@ -146,9 +146,9 @@
         CountDownLatch latch = setReenterLatch();
 
         assertTrue("Activity didn't finish!",
-                mActivity.returnLatch.await(2000, TimeUnit.MILLISECONDS));
+                mActivity.returnLatch.await(3000, TimeUnit.MILLISECONDS));
         assertTrue("Reenter transition didn't finish", latch.await(1000, TimeUnit.MILLISECONDS));
-        assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
+        assertTrue(mActivity.reenterLatch.await(1000, TimeUnit.MILLISECONDS));
         getInstrumentation().waitForIdleSync();
         checkNoReturnTransitionVisibility();
         runTestOnUiThread(new Runnable() {
@@ -180,8 +180,8 @@
         });
 
         assertTrue("Activity didn't finish!",
-                mActivity.returnLatch.await(1500, TimeUnit.MILLISECONDS));
-        assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
+                mActivity.returnLatch.await(3000, TimeUnit.MILLISECONDS));
+        assertTrue(mActivity.reenterLatch.await(1000, TimeUnit.MILLISECONDS));
         getInstrumentation().waitForIdleSync();
         checkNoReturnTransitionVisibility();
         runTestOnUiThread(new Runnable() {
@@ -214,9 +214,9 @@
         });
 
         assertTrue("Activity didn't finish!",
-                mActivity.returnLatch.await(1500, TimeUnit.MILLISECONDS));
+                mActivity.returnLatch.await(3000, TimeUnit.MILLISECONDS));
         assertTrue("Reenter transition didn't finish", latch.await(1000, TimeUnit.MILLISECONDS));
-        assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
+        assertTrue(mActivity.reenterLatch.await(1000, TimeUnit.MILLISECONDS));
         getInstrumentation().waitForIdleSync();
         checkNoReturnTransitionVisibility();
         runTestOnUiThread(new Runnable() {
@@ -249,8 +249,8 @@
         });
 
         assertTrue("Activity didn't finish!",
-                mActivity.returnLatch.await(1500, TimeUnit.MILLISECONDS));
-        assertTrue(mActivity.reenterLatch.await(300, TimeUnit.MILLISECONDS));
+                mActivity.returnLatch.await(3000, TimeUnit.MILLISECONDS));
+        assertTrue(mActivity.reenterLatch.await(1000, TimeUnit.MILLISECONDS));
         getInstrumentation().waitForIdleSync();
         checkNoReturnTransitionVisibility();
         runTestOnUiThread(new Runnable() {
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..fcb1d5a 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,9 +56,17 @@
     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();
+        boolean getMetered();
+        void setMetered(boolean metered);
         String getSystemFeature();
         String getErrorMessage();
     }
@@ -63,6 +74,8 @@
     private static final NetworkInterfaceToTest[] sNetworkInterfacesToTest =
             new NetworkInterfaceToTest[] {
                     new NetworkInterfaceToTest() {
+                        private boolean metered = false;
+
                         @Override
                         public int getNetworkType() {
                             return ConnectivityManager.TYPE_WIFI;
@@ -74,6 +87,16 @@
                         }
 
                         @Override
+                        public boolean getMetered() {
+                            return metered;
+                        }
+
+                        @Override
+                        public void setMetered(boolean metered) {
+                            this.metered = metered;
+                        }
+
+                        @Override
                         public String getSystemFeature() {
                             return PackageManager.FEATURE_WIFI;
                         }
@@ -84,6 +107,7 @@
                         }
                     },
                     new NetworkInterfaceToTest() {
+                        private boolean metered = false;
                         @Override
                         public int getNetworkType() {
                             return ConnectivityManager.TYPE_MOBILE;
@@ -95,6 +119,15 @@
                         }
 
                         @Override
+                        public boolean getMetered() {
+                            return metered;
+                        }
+
+                        @Override
+                        public void setMetered(boolean metered) {
+                            this.metered = metered;
+                        }
+                        @Override
                         public String getSystemFeature() {
                             return PackageManager.FEATURE_TELEPHONY;
                         }
@@ -119,7 +152,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 +164,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 +180,7 @@
         } catch (Exception e) {
             Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
         } finally {
+            TrafficStats.clearThreadStatsTag();
             if (in != null) {
                 try {
                     in.close();
@@ -229,20 +263,25 @@
 
     private class NetworkCallback extends ConnectivityManager.NetworkCallback {
         private long mTolerance;
+        private URL mUrl;
         public boolean success;
+        public boolean metered;
 
-        NetworkCallback(long tolerance) {
+        NetworkCallback(long tolerance, URL url) {
             mTolerance = tolerance;
+            mUrl = url;
             success = false;
+            metered = false;
         }
 
         @Override
         public void onAvailable(Network network) {
             try {
                 mStartTime = System.currentTimeMillis() - mTolerance;
-                exerciseRemoteHost(network);
+                exerciseRemoteHost(network, mUrl);
                 mEndTime = System.currentTimeMillis() + mTolerance;
                 success = true;
+                metered = mCm.getNetworkInfo(network).isMetered();
                 synchronized(NetworkUsageStatsTest.this) {
                     NetworkUsageStatsTest.this.notify();
                 }
@@ -260,7 +299,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)
@@ -272,6 +311,7 @@
             }
         }
         if (callback.success) {
+            sNetworkInterfacesToTest[networkTypeIndex].setMetered(callback.metered);
             return true;
         }
 
@@ -312,6 +352,7 @@
             assertTimestamps(bucket);
             assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
             assertEquals(bucket.getUid(), NetworkStats.Bucket.UID_ALL);
+            assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForDevice(
@@ -344,6 +385,7 @@
             assertTimestamps(bucket);
             assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
             assertEquals(bucket.getUid(), NetworkStats.Bucket.UID_ALL);
+            assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForUser(
@@ -375,9 +417,13 @@
                 long totalRxPackets = 0;
                 long totalTxBytes = 0;
                 long totalRxBytes = 0;
+                boolean hasCorrectMetering = false;
+                int expectedMetering = sNetworkInterfacesToTest[i].getMetered() ?
+                        NetworkStats.Bucket.METERED_YES : NetworkStats.Bucket.METERED_NO;
                 while (result.hasNextBucket()) {
                     assertTrue(result.getNextBucket(bucket));
                     assertTimestamps(bucket);
+                    hasCorrectMetering |= bucket.getMetered() == expectedMetering;
                     if (bucket.getUid() == Process.myUid()) {
                         totalTxPackets += bucket.getTxPackets();
                         totalRxPackets += bucket.getRxPackets();
@@ -386,6 +432,8 @@
                     }
                 }
                 assertFalse(result.getNextBucket(bucket));
+                assertTrue("Incorrect metering for NetworkType: " +
+                        sNetworkInterfacesToTest[i].getNetworkType(), hasCorrectMetering);
                 assertTrue("No Rx bytes usage for uid " + Process.myUid(), totalRxBytes > 0);
                 assertTrue("No Rx packets usage for uid " + Process.myUid(), totalRxPackets > 0);
                 assertTrue("No Tx bytes usage for uid " + Process.myUid(), totalTxBytes > 0);
@@ -433,6 +481,7 @@
                     assertTrue(result.getNextBucket(bucket));
                     assertTimestamps(bucket);
                     assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
+                    assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
                     if (bucket.getUid() == Process.myUid()) {
                         totalTxPackets += bucket.getTxPackets();
                         totalRxPackets += bucket.getRxPackets();
@@ -488,6 +537,7 @@
                     assertTrue(result.getNextBucket(bucket));
                     assertTimestamps(bucket);
                     assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
+                    assertEquals(bucket.getMetered(), NetworkStats.Bucket.METERED_ALL);
                     assertEquals(bucket.getUid(), Process.myUid());
                     totalTxPackets += bucket.getTxPackets();
                     totalRxPackets += bucket.getRxPackets();
@@ -520,10 +570,100 @@
         }
     }
 
+    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.getMetered(), NetworkStats.Bucket.METERED_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/Android.mk b/tests/tests/appwidget/Android.mk
index efd15d3..d97d7d7 100644
--- a/tests/tests/appwidget/Android.mk
+++ b/tests/tests/appwidget/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_PACKAGE_NAME := CtsAppWidgetTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target-minus-junit4 ctstestrunner hamcrest
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/appwidget/AndroidTest.xml b/tests/tests/appwidget/AndroidTest.xml
index fcee457..9a8bad2 100644
--- a/tests/tests/appwidget/AndroidTest.xml
+++ b/tests/tests/appwidget/AndroidTest.xml
@@ -19,6 +19,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.appwidget.cts" />
-        <option name="runtime-hint" value="3m30s" />
+        <option name="runtime-hint" value="9m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
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/assist/Android.mk b/tests/tests/assist/Android.mk
index 61379c5..9b7d774 100644
--- a/tests/tests/assist/Android.mk
+++ b/tests/tests/assist/Android.mk
@@ -24,7 +24,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index f1af0c4..a920816 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -25,5 +25,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.assist.cts" />
+        <option name="runtime-hint" value="12m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/assist/service/Android.mk b/tests/tests/assist/service/Android.mk
index 2f72853..9b9ed84 100644
--- a/tests/tests/assist/service/Android.mk
+++ b/tests/tests/assist/service/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 := CtsAssistCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsAssistCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 05d655a..cce36b9 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -16,6 +16,8 @@
 
 package android.assist.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
 import android.assist.cts.TestStartActivity;
 import android.assist.common.Utils;
 
@@ -31,7 +33,6 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.cts.util.SystemUtil;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
diff --git a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
index c6ac3a6..d7e037c 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
@@ -16,6 +16,8 @@
 
 package android.assist.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
 import android.assist.cts.TestStartActivity;
 import android.assist.common.Utils;
 
@@ -27,7 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.SystemUtil;
 import android.graphics.Point;
 import android.os.Bundle;
 import android.provider.Settings;
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index ea4cd3d..368e47d 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -16,6 +16,8 @@
 
 package android.assist.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
 import android.assist.common.Utils;
 
 import android.app.Activity;
@@ -26,7 +28,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.SystemUtil;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
index 3ed26d1..9f095aa 100644
--- a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -16,6 +16,8 @@
 
 package android.assist.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
 import android.assist.cts.TestStartActivity;
 import android.assist.common.Utils;
 
@@ -27,7 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.SystemUtil;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
diff --git a/tests/tests/bionic/AndroidTest.xml b/tests/tests/bionic/AndroidTest.xml
index 30717da0..b822381 100644
--- a/tests/tests/bionic/AndroidTest.xml
+++ b/tests/tests/bionic/AndroidTest.xml
@@ -27,6 +27,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="CtsBionicTestCases" />
-        <option name="runtime-hint" value="1m10s" />
+        <option name="runtime-hint" value="12m10s" />
     </test>
 </configuration>
diff --git a/tests/tests/calendarcommon/AndroidTest.xml b/tests/tests/calendarcommon/AndroidTest.xml
index 65f2d7a..c411e69 100644
--- a/tests/tests/calendarcommon/AndroidTest.xml
+++ b/tests/tests/calendarcommon/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.calendarcommon2.cts" />
+        <option name="runtime-hint" value="8m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
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..890e041
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
@@ -0,0 +1,385 @@
+/*
+ * 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 static android.car.CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED;
+import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION;
+import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND;
+
+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.
+        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner);
+        mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, owner);
+        mManager.abandonAppFocus(owner);
+    }
+
+    public void testSetActiveNullListener() throws Exception {
+        try {
+            mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, null);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testRegisterNull() throws Exception {
+        try {
+            mManager.addFocusListener(null, 0);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testRegisterUnregister() throws Exception {
+        FocusChangedListerner listener = new FocusChangedListerner();
+        FocusChangedListerner listener2 = new FocusChangedListerner();
+        mManager.addFocusListener(listener, 1);
+        mManager.addFocusListener(listener2, 1);
+        mManager.removeFocusListener(listener);
+        mManager.removeFocusListener(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());
+        FocusChangedListerner change = new FocusChangedListerner();
+        FocusChangedListerner change2 = new FocusChangedListerner();
+        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        FocusOwnershipCallback owner2 = new FocusOwnershipCallback();
+        mManager.addFocusListener(change, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.addFocusListener(change, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        manager2.addFocusListener(change2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        manager2.addFocusListener(change2, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, 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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(change.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, 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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertTrue(change.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+
+        // this should be no-op
+        change.reset();
+        change2.reset();
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+
+        Assert.assertArrayEquals(expectedFocuses, mManager.getActiveAppTypes());
+        Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes());
+        assertFalse(change2.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertFalse(change.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                manager2.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner2));
+        assertTrue(owner2.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, 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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertTrue(change.waitForFocusChangedAndAssert(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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        mManager.removeFocusListener(change);
+        manager2.removeFocusListener(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());
+
+        FocusChangedListerner listener = new FocusChangedListerner();
+        FocusChangedListerner listener2 = new FocusChangedListerner();
+        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        mManager.addFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.addFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        manager2.addFocusListener(listener2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+
+        assertTrue(listener.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(listener2.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        listener.reset();
+        listener2.reset();
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND));
+
+        assertTrue(listener.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertFalse(listener2.waitForFocusChangedAndAssert(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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertFalse(listener2.waitForFocusChangedAndAssert(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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        assertTrue(listener2.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+    }
+
+    public void testMultipleChangeListenersPerManager() throws Exception {
+        FocusChangedListerner listener = new FocusChangedListerner();
+        FocusChangedListerner listener2 = new FocusChangedListerner();
+        FocusOwnershipCallback owner = new FocusOwnershipCallback();
+        mManager.addFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+        mManager.addFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND);
+        mManager.addFocusListener(listener2, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
+
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION));
+
+        assertTrue(listener.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+        assertTrue(listener2.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true));
+
+        listener.reset();
+        listener2.reset();
+        assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED,
+                mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, owner));
+        assertTrue(owner.waitForOwnershipGrantAndAssert(
+                DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND));
+
+        assertTrue(listener.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, true));
+        assertFalse(listener2.waitForFocusChangedAndAssert(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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND, false));
+        assertFalse(listener2.waitForFocusChangedAndAssert(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.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+        assertTrue(listener2.waitForFocusChangedAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
+                CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
+    }
+
+    private class FocusChangedListerner implements CarAppFocusManager.OnAppFocusChangedListener {
+        private int mLastChangeAppType;
+        private boolean mLastChangeAppActive;
+        private final Semaphore mChangeWait = new Semaphore(0);
+
+        public boolean waitForFocusChangedAndAssert(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 onAppFocusChanged(int appType, boolean active) {
+            Log.i(TAG, "onAppFocusChange appType=" + appType + " active=" + active);
+            assertMainThread();
+            mLastChangeAppType = appType;
+            mLastChangeAppActive = active;
+            mChangeWait.release();
+        }
+    }
+
+    private class FocusOwnershipCallback
+            implements CarAppFocusManager.OnAppFocusOwnershipCallback {
+        private volatile int mLastLossEvent;
+        private final Semaphore mLossEventWait = new Semaphore(0);
+
+        private volatile int mLastGrantEvent;
+        private final Semaphore mGrantEventWait = new Semaphore(0);
+
+        public boolean waitForOwnershipGrantAndAssert(long timeoutMs, int expectedAppType)
+                throws Exception {
+            if (!mGrantEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+                return false;
+            }
+            assertEquals(expectedAppType, mLastGrantEvent);
+            return true;
+        }
+
+        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 onAppFocusOwnershipLost(int appType) {
+            Log.i(TAG, "onAppFocusOwnershipLoss " + appType);
+            assertMainThread();
+            mLastLossEvent = appType;
+            mLossEventWait.release();
+        }
+
+        @Override
+        public void onAppFocusOwnershipGranted(int appType) {
+            Log.i(TAG, "onAppFocusOwnershipGranted " + appType);
+            assertMainThread();
+            mLastGrantEvent = appType;
+            mGrantEventWait.release();
+        }
+    }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
index 1cde840..7c01455 100644
--- a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
@@ -17,6 +17,7 @@
 
 import android.car.Car;
 import android.car.CarInfoManager;
+import android.os.Bundle;
 
 public class CarInfoManagerTest extends CarApiTestBase {
 
@@ -28,45 +29,14 @@
         mCarInfoManager = (CarInfoManager) getCar().getCarManager(Car.INFO_SERVICE);
     }
 
-    public void testManufacturer() throws Exception {
-        // The values are not guaranteed, so just checking data types here.
-        mCarInfoManager.getString(CarInfoManager.KEY_MANUFACTURER);
-        mCarInfoManager.getInt(CarInfoManager.KEY_MODEL_YEAR);
-        mCarInfoManager.getString(CarInfoManager.KEY_VEHICLE_ID);
-        mCarInfoManager.getString(CarInfoManager.KEY_MODEL);
-        try {
-            mCarInfoManager.getFloat(CarInfoManager.KEY_MANUFACTURER);
-            fail("type check failed");
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
-        try {
-            mCarInfoManager.getInt(CarInfoManager.KEY_MANUFACTURER);
-            fail("type check failed");
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
+    public void testVehicleId() throws Exception {
+        assertNotNull(mCarInfoManager.getVehicleId());
     }
 
-    public void testNoSuchInfo() throws Exception {
-        final String NO_SUCH_NAME = "no-such-information-available";
-        try {
-            mCarInfoManager.getString(NO_SUCH_NAME);
-            fail("wrong param check");
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
-        try {
-            mCarInfoManager.getInt(NO_SUCH_NAME);
-            fail("wrong param check");
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
-        try {
-            mCarInfoManager.getFloat(NO_SUCH_NAME);
-            fail("wrong param check");
-        } catch (IllegalArgumentException e) {
-            // Expected.
-        }
+    public void testNullables() throws Exception {
+        // no guarantee of existence. just call and check if it throws exception.
+        mCarInfoManager.getManufacturer();
+        mCarInfoManager.getModel();
+        mCarInfoManager.getModelYear();
     }
 }
diff --git a/tests/tests/car/src/android/car/cts/ExceptionsTest.java b/tests/tests/car/src/android/car/cts/ExceptionsTest.java
index 496867b..6cac872 100644
--- a/tests/tests/car/src/android/car/cts/ExceptionsTest.java
+++ b/tests/tests/car/src/android/car/cts/ExceptionsTest.java
@@ -16,7 +16,6 @@
 package android.car.cts;
 
 import android.car.CarNotConnectedException;
-import android.car.CarNotSupportedException;
 import android.test.AndroidTestCase;
 
 public class ExceptionsTest extends AndroidTestCase {
@@ -39,21 +38,4 @@
         exception = new CarNotConnectedException(CAUSE);
         assertEquals(CAUSE, exception.getCause());
     }
-
-    public void testCarNotSupportedException() {
-        CarNotSupportedException exception = new CarNotSupportedException();
-        assertNull(exception.getMessage());
-        assertNull(exception.getCause());
-
-        exception = new CarNotSupportedException(MESSAGE);
-        assertEquals(MESSAGE, exception.getMessage());
-        assertNull(exception.getCause());
-
-        exception = new CarNotSupportedException(MESSAGE, CAUSE);
-        assertEquals(MESSAGE, exception.getMessage());
-        assertEquals(CAUSE, exception.getCause());
-
-        exception = new CarNotSupportedException(CAUSE);
-        assertEquals(CAUSE, exception.getCause());
-    }
 }
diff --git a/tests/tests/carrierapi/Android.mk b/tests/tests/carrierapi/Android.mk
index 53e051f..4cb2c38 100644
--- a/tests/tests/carrierapi/Android.mk
+++ b/tests/tests/carrierapi/Android.mk
@@ -22,7 +22,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
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..67fc3fa 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -23,12 +23,27 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctsdeviceutil ctstestrunner services.core
+LOCAL_STATIC_JAVA_LIBRARIES :=  android-support-v4 \
+                                android-support-multidex \
+                                compatibility-device-util \
+                                ctstestrunner \
+                                services.core
+
+# Use multi-dex as the compatibility-common-util-devicesidelib dependency
+# on compatibility-device-util pushes us beyond 64k methods.
+LOCAL_JACK_FLAGS := --multi-dex legacy
 
 # 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/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
index e87771c..44199a8 100644
--- a/tests/tests/content/AndroidTest.xml
+++ b/tests/tests/content/AndroidTest.xml
@@ -20,6 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.content.cts" />
-        <option name="runtime-hint" value="3m30s" />
+        <option name="runtime-hint" value="21m30s" />
     </test>
 </configuration>
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-night/colors.xml b/tests/tests/content/res/values-night/colors.xml
new file mode 100644
index 0000000..1281c81
--- /dev/null
+++ b/tests/tests/content/res/values-night/colors.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.
+ -->
+
+<resources>
+    <color name="varies_uimode">#ff0000</color>
+</resources>
diff --git a/tests/tests/content/res/values/colors.xml b/tests/tests/content/res/values/colors.xml
index f3cc325..6346629 100644
--- a/tests/tests/content/res/values/colors.xml
+++ b/tests/tests/content/res/values/colors.xml
@@ -23,4 +23,5 @@
     <color name="testcolor1">#ff00ff00</color>
     <color name="testcolor2">#ffff0000</color>
     <color name="failColor">#ff0000ff</color>
+    <color name="varies_uimode">#0000ff</color>
 </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/cts/ClipboardManagerListenerTest.java b/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
index ca6bba7..961b784 100644
--- a/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
+++ b/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
@@ -18,10 +18,10 @@
 
 import android.content.ClipData;
 import android.content.ClipboardManager.OnPrimaryClipChangedListener;
-import android.cts.util.PollingCheck;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase2;
 
+import com.android.compatibility.common.util.PollingCheck;
 
 public class ClipboardManagerListenerTest
         extends ActivityInstrumentationTestCase2<ClipboardManagerListenerActivity> {
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderTest.java b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
index e7d8a05..dc4a031 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
@@ -226,6 +226,11 @@
         // cannot trigger this callback reliably
     }
 
+    public void testRefresh_DefaultImplReturnsFalse() {
+        MockContentProvider provider = new MockContentProvider();
+        assertFalse(provider.refresh(null, null, null));
+    }
+
     public void testGetIContentProvider() {
         MockContentProvider mockContentProvider = new MockContentProvider();
 
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index ea1227c..9c0c0d3 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -16,16 +16,13 @@
 
 package android.content.cts;
 
-import android.content.cts.R;
-
-
 import android.accounts.Account;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.cts.R;
 import android.content.res.AssetFileDescriptor;
-import android.cts.util.PollingCheck;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteQueryBuilder;
@@ -38,6 +35,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -55,8 +54,6 @@
     private static final Uri TABLE1_CROSS_URI =
             Uri.parse("content://" + AUTHORITY + "/testtable1/cross");
     private static final Uri TABLE2_URI = Uri.parse("content://" + AUTHORITY + "/testtable2/");
-    private static final Uri SELF_URI = Uri.parse("content://" + AUTHORITY + "/self/");
-    private static final Uri CRASH_URI = Uri.parse("content://" + AUTHORITY + "/crash/");
 
     private static final Uri LEVEL1_URI = Uri.parse("content://" + AUTHORITY + "/level/");
     private static final Uri LEVEL2_URI = Uri.parse("content://" + AUTHORITY + "/level/child");
@@ -215,7 +212,7 @@
         // Verify we can still access it.
         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
-        
+
         // Get an unstable refrence on the remote content provider.
         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
                 REMOTE_AUTHORITY);
@@ -305,7 +302,7 @@
     }
 
     public void testQuery() {
-        mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
+        mCursor = mContentResolver.query(TABLE1_URI, null, null, null);
 
         assertNotNull(mCursor);
         assertEquals(3, mCursor.getCount());
@@ -321,9 +318,14 @@
         assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
         assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
         mCursor.close();
+    }
 
-        String selection = COLUMN_ID_NAME + "=1";
-        mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null);
+    public void testQuery_WithSelectionArgs() {
+        Bundle queryArgs = new Bundle();
+        queryArgs.putString(ContentResolver.QUERY_ARG_SELECTION, COLUMN_ID_NAME + "=?");
+        queryArgs.putStringArray(ContentResolver.QUERY_ARG_SELECTION_ARGS, new String[] {"1"});
+
+        mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
         assertNotNull(mCursor);
         assertEquals(1, mCursor.getCount());
         assertEquals(3, mCursor.getColumnCount());
@@ -334,8 +336,9 @@
         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
         mCursor.close();
 
-        selection = COLUMN_KEY_NAME + "=\"" + KEY3 + "\"";
-        mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null);
+        queryArgs.putString(ContentResolver.QUERY_ARG_SELECTION, COLUMN_KEY_NAME + "=?");
+        queryArgs.putStringArray(ContentResolver.QUERY_ARG_SELECTION_ARGS, new String[] {KEY3});
+        mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
         assertNotNull(mCursor);
         assertEquals(1, mCursor.getCount());
         assertEquals(3, mCursor.getColumnCount());
@@ -345,7 +348,9 @@
         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
         mCursor.close();
+    }
 
+    public void testQuery_NullUriThrows() {
         try {
             mContentResolver.query(null, null, null, null, null);
             fail("did not throw NullPointerException when uri is null.");
@@ -567,7 +572,7 @@
                 }
             }
         }
-        
+
     }
 
     public void testCrashingOpenAssetFileDescriptor() throws IOException {
@@ -910,6 +915,44 @@
         }
     }
 
+    public void testRefresh_DefaultImplReturnsFalse() {
+        boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+        assertFalse(refreshed);
+        MockContentProvider.assertRefreshed(TABLE1_URI);
+    }
+
+    public void testRefresh_ReturnsProviderValue() {
+        try {
+            MockContentProvider.setRefreshReturnValue(true);
+            boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+            assertTrue(refreshed);
+            MockContentProvider.assertRefreshed(TABLE1_URI);
+        } finally {
+            MockContentProvider.setRefreshReturnValue(false);
+        }
+    }
+
+    public void testRefresh_NullUriThrowsImmediately() {
+        try {
+            mContentResolver.refresh(null, null, null);
+            fail("did not throw NullPointerException when uri is null.");
+        } catch (NullPointerException e) {
+            //expected.
+        }
+    }
+
+    public void testRefresh_CancellableThrowsImmediately() {
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        cancellationSignal.cancel();
+
+        try {
+            mContentResolver.refresh(TABLE1_URI, null, cancellationSignal);
+            fail("Expected OperationCanceledException");
+        } catch (OperationCanceledException ex) {
+            // expected
+        }
+    }
+
     public void testRegisterContentObserver() {
         final MockContentObserver mco = new MockContentObserver();
 
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
index 4ffe490..5f48260 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
@@ -29,7 +29,6 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteCursorDriver;
 import android.database.sqlite.SQLiteDatabase;
@@ -45,6 +44,8 @@
 import android.test.AndroidTestCase;
 import android.view.WindowManager;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/tests/content/src/android/content/cts/MockContentProvider.java b/tests/tests/content/src/android/content/cts/MockContentProvider.java
index bddc82d..e422c34 100644
--- a/tests/tests/content/src/android/content/cts/MockContentProvider.java
+++ b/tests/tests/content/src/android/content/cts/MockContentProvider.java
@@ -16,22 +16,15 @@
 
 package android.content.cts;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
+import static junit.framework.Assert.assertEquals;
 
+import android.annotation.Nullable;
 import android.content.ContentProvider;
+import android.content.ContentProvider.PipeDataWriter;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.UriMatcher;
-import android.content.ContentProvider.PipeDataWriter;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -45,6 +38,15 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+
 public class MockContentProvider extends ContentProvider
         implements PipeDataWriter<String> {
 
@@ -62,6 +64,9 @@
     private static final int SELF_ID = 6;
     private static final int CRASH_ID = 6;
 
+    private static @Nullable Uri sRefreshedUri;
+    private static boolean sRefreshReturnValue;
+
     private final String mAuthority;
     private final String mDbName;
     private final UriMatcher URL_MATCHER;
@@ -385,6 +390,13 @@
         }
     }
 
+    @Override
+    public boolean refresh(Uri uri, @Nullable Bundle args,
+            @Nullable CancellationSignal cancellationSignal) {
+        sRefreshedUri = uri;
+        return sRefreshReturnValue;
+    }
+
     private void crashOnLaunchIfNeeded() {
         if (getCrashOnLaunch(getContext())) {
             // The test case wants us to crash our process on first launch.
@@ -413,6 +425,14 @@
         }
     }
 
+    public static void setRefreshReturnValue(boolean value) {
+        sRefreshReturnValue = value;
+    }
+
+    public static void assertRefreshed(Uri expectedUri) {
+        assertEquals(sRefreshedUri, expectedUri);
+    }
+
     private static File getCrashOnLaunchFile(Context context) {
         return context.getFileStreamPath("MockContentProvider.crashonlaunch");
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
index e11beec..48649b1 100644
--- a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
@@ -20,7 +20,6 @@
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
@@ -28,6 +27,8 @@
 import android.util.Printer;
 import android.util.StringBuilderPrinter;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
 import android.content.cts.R;
 
 
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..18b1fd3 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
@@ -23,6 +23,7 @@
 
 import android.content.Context;
 import android.content.cts.util.XmlUtils;
+import android.content.pm.ActivityInfo;
 import android.content.res.AssetManager;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -30,6 +31,7 @@
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -288,6 +290,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() {
@@ -534,6 +540,15 @@
 
     }
 
+    public void testChangingConfiguration() {
+        ColorDrawable dr1 = (ColorDrawable) mResources.getDrawable(R.color.varies_uimode);
+        assertEquals(ActivityInfo.CONFIG_UI_MODE, dr1.getChangingConfigurations());
+
+        // Test again with a drawable obtained from the cache.
+        ColorDrawable dr2 = (ColorDrawable) mResources.getDrawable(R.color.varies_uimode);
+        assertEquals(ActivityInfo.CONFIG_UI_MODE, dr2.getChangingConfigurations());
+    }
+
     private Resources resourcesForLanguage(final String lang) {
         final Configuration config = new Configuration();
         config.updateFrom(mResources.getConfiguration());
diff --git a/tests/tests/database/AndroidTest.xml b/tests/tests/database/AndroidTest.xml
index 046215d..4af84e0 100644
--- a/tests/tests/database/AndroidTest.xml
+++ b/tests/tests/database/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.database.cts" />
+        <option name="runtime-hint" value="11m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/display/AndroidTest.xml b/tests/tests/display/AndroidTest.xml
index f346c22..f7f52de 100644
--- a/tests/tests/display/AndroidTest.xml
+++ b/tests/tests/display/AndroidTest.xml
@@ -25,5 +25,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.display.cts" />
+        <option name="runtime-hint" value="17m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 48da789..4e24981 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -61,6 +61,7 @@
             (float)(SECONDARY_DISPLAY_DPI + 1) / DisplayMetrics.DENSITY_DEFAULT;
     // Matches com.android.internal.R.string.display_manager_overlay_display_name.
     private static final String OVERLAY_DISPLAY_NAME_PREFIX = "Overlay #";
+    private static final String OVERLAY_DISPLAY_TYPE = "type OVERLAY";
 
     private DisplayManager mDisplayManager;
     private WindowManager mWindowManager;
@@ -115,15 +116,15 @@
         }
     }
 
-    private boolean isSecondarySize(Display display) {
-        final Point p = new Point();
-        display.getSize(p);
-        return p.x == SECONDARY_DISPLAY_WIDTH && p.y == SECONDARY_DISPLAY_HEIGHT;
+    /** Check if the display is an overlay display, created by this test. */
+    private boolean isSecondaryDisplay(Display display) {
+        return display.toString().contains(OVERLAY_DISPLAY_TYPE);
     }
 
+    /** Get the overlay display, created by this test. */
     private Display getSecondaryDisplay(Display[] displays) {
         for (Display display : displays) {
-            if (isSecondarySize(display)) {
+            if (isSecondaryDisplay(display)) {
                 return display;
             }
         }
@@ -143,7 +144,7 @@
             if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
                 hasDefaultDisplay = true;
             }
-            if (isSecondarySize(display)) {
+            if (isSecondaryDisplay(display)) {
                 hasSecondaryDisplay = true;
             }
         }
@@ -234,22 +235,6 @@
     }
 
     /**
-     * Test that the getCurrentSizeRange method returns correct values.
-     */
-    public void testGetCurrentSizeRange() {
-        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
-
-        Point smallest = new Point();
-        Point largest = new Point();
-        display.getCurrentSizeRange(smallest, largest);
-
-        assertEquals(SECONDARY_DISPLAY_WIDTH, smallest.x);
-        assertEquals(SECONDARY_DISPLAY_HEIGHT, smallest.y);
-        assertEquals(SECONDARY_DISPLAY_WIDTH, largest.x);
-        assertEquals(SECONDARY_DISPLAY_HEIGHT, largest.y);
-    }
-
-    /**
      * Test that the getFlags method returns no flag bits set for the overlay display.
      */
     public void testFlags() {
diff --git a/tests/tests/dpi/AndroidTest.xml b/tests/tests/dpi/AndroidTest.xml
index b8d941b..7b50015 100644
--- a/tests/tests/dpi/AndroidTest.xml
+++ b/tests/tests/dpi/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.dpi.cts" />
+        <option name="runtime-hint" value="10m10s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/dpi2/AndroidTest.xml b/tests/tests/dpi2/AndroidTest.xml
index dfb1730..988f319 100644
--- a/tests/tests/dpi2/AndroidTest.xml
+++ b/tests/tests/dpi2/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.dpi2.cts" />
+        <option name="runtime-hint" value="10m40s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/dreams/AndroidTest.xml b/tests/tests/dreams/AndroidTest.xml
index b334ade..92a2f97 100644
--- a/tests/tests/dreams/AndroidTest.xml
+++ b/tests/tests/dreams/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.dreams.cts" />
+        <option name="runtime-hint" value="10m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/drm/Android.mk b/tests/tests/drm/Android.mk
index 02567be..d67c048 100644
--- a/tests/tests/drm/Android.mk
+++ b/tests/tests/drm/Android.mk
@@ -24,7 +24,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 compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/drm/AndroidTest.xml b/tests/tests/drm/AndroidTest.xml
index 48287aa..5fc854e 100644
--- a/tests/tests/drm/AndroidTest.xml
+++ b/tests/tests/drm/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.drm.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/drm/res/raw/testmp3_2.mp3 b/tests/tests/drm/res/raw/testmp3_2.mp3
new file mode 100644
index 0000000..6a70c69
--- /dev/null
+++ b/tests/tests/drm/res/raw/testmp3_2.mp3
Binary files differ
diff --git a/tests/tests/drm/src/android/drm/cts/DRMTest.java b/tests/tests/drm/src/android/drm/cts/DRMTest.java
index bb77668..e632842 100644
--- a/tests/tests/drm/src/android/drm/cts/DRMTest.java
+++ b/tests/tests/drm/src/android/drm/cts/DRMTest.java
@@ -16,15 +16,29 @@
 
 package android.drm.cts;
 
+import com.android.compatibility.common.util.MediaUtils;
 
 import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.io.SequenceInputStream;
+import java.nio.charset.StandardCharsets;
+import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.util.HashMap;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
 import java.util.Iterator;
+import java.util.Vector;
 
 import android.drm.DrmManagerClient;
 import android.drm.DrmConvertedStatus;
@@ -35,6 +49,11 @@
 import android.drm.DrmRights;
 import android.drm.DrmStore;
 import android.drm.DrmUtils;
+import android.media.MediaExtractor;
+import android.media.MediaMetadataRetriever;
+import android.media.MediaPlayer;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
 
 public class DRMTest extends AndroidTestCase {
     private static String TAG = "CtsDRMTest";
@@ -197,6 +216,90 @@
         }
     }
 
+    public void testForwardLockAccess()  throws Exception {
+        DrmManagerClient drmManager= new DrmManagerClient(mContext);
+        String[] engines = drmManager.getAvailableDrmEngines();
+        boolean haveForwardLock = false;
+        for (String engine: engines) {
+            if (engine.equals("OMA V1 Forward Lock")) {
+                haveForwardLock = true;
+            }
+        }
+        drmManager.close();
+        if (!haveForwardLock) {
+            Log.i(TAG, "Skipping forward lock test because forward lock is not available");
+            return;
+        }
+
+        Vector<InputStream> sequence = new Vector<InputStream>();
+
+        String dmHeader = "--mime_content_boundary\r\n" +
+        "Content-Type: audio/mpeg\r\n" +
+        "Content-Transfer-Encoding: binary\r\n\r\n";
+        sequence.add(new ByteArrayInputStream(dmHeader.getBytes(StandardCharsets.UTF_8)));
+
+        AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3_2);
+        FileInputStream body = afd.createInputStream();
+        sequence.add(body);
+
+        String dmFooter = "\r\n--mime_content_boundary--";
+        sequence.add(new ByteArrayInputStream(dmFooter.getBytes(StandardCharsets.UTF_8)));
+
+        SequenceInputStream dmStream = new SequenceInputStream(sequence.elements());
+        String flPath = mContext.getExternalCacheDir() + "/temp.fl";
+        RandomAccessFile flFile = new RandomAccessFile(flPath, "rw");
+        assertTrue("couldn't convert to fl file",
+                MediaUtils.convertDmToFl(mContext, dmStream,  flFile));
+        dmStream.close(); // this closes the underlying streams and AFD as well
+        flFile.close();
+
+        ParcelFileDescriptor flFd = null;
+        try {
+            // check that the .fl file can be played
+            MediaPlayer player = new MediaPlayer();
+            try {
+                flFd = ParcelFileDescriptor.open(
+                        new File(flPath), ParcelFileDescriptor.MODE_READ_ONLY);
+                player.setDataSource(flFd.getFileDescriptor(), 0, flFd.getStatSize());
+                player.prepare();
+                player.start();
+                SystemClock.sleep(2000);
+                assertTrue("player is not playing", player.isPlaying());
+                player.release();
+            } catch (Exception e) {
+                Log.d(TAG, "MediaPlayer playback failed:", e);
+            } finally {
+                player.release();
+            }
+
+            // check that the .fl file can be parsed with MediaMetadataRetriever
+            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+            try {
+                retriever.setDataSource(flFd.getFileDescriptor());
+                String numTracks =
+                        retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS);
+                assertEquals("wrong number of tracks found in file", "1", numTracks);
+            } finally {
+                retriever.release();
+            }
+
+            // check that the .fl file cannot be opened with MediaExtractor
+            MediaExtractor ex = new MediaExtractor();
+            try {
+                ex.setDataSource(flFd.getFileDescriptor());
+                int n = ex.getTrackCount();
+                fail("extractor creation should have failed, but found " + n + " tracks");
+            } catch (Exception e) {
+                // ignore, expected to fail
+            } finally {
+                ex.release();
+            }
+        } finally {
+            flFd.close();
+            new File(flPath).delete();
+        }
+    }
+
     private class OnEventListenerImpl implements DrmManagerClient.OnEventListener {
         private Config mConfig;
         public OnEventListenerImpl(Config config) {
diff --git a/tests/tests/effect/AndroidTest.xml b/tests/tests/effect/AndroidTest.xml
index abf2b22..7ba983e 100644
--- a/tests/tests/effect/AndroidTest.xml
+++ b/tests/tests/effect/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.effect.cts" />
+        <option name="runtime-hint" value="8m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/externalservice/Android.mk b/tests/tests/externalservice/Android.mk
index 3208177..14e82c5 100644
--- a/tests/tests/externalservice/Android.mk
+++ b/tests/tests/externalservice/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_STATIC_JAVA_LIBRARIES := CtsExternalServiceCommon ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := CtsExternalServiceCommon compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/externalservice/AndroidTest.xml b/tests/tests/externalservice/AndroidTest.xml
index b07f248..36ecb04 100644
--- a/tests/tests/externalservice/AndroidTest.xml
+++ b/tests/tests/externalservice/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.externalservice.cts" />
+        <option name="runtime-hint" value="12m" />
     </test>
 </configuration>
diff --git a/tests/tests/externalservice/service/Android.mk b/tests/tests/externalservice/service/Android.mk
index 9541b0e..e99a71d 100644
--- a/tests/tests/externalservice/service/Android.mk
+++ b/tests/tests/externalservice/service/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 := CtsExternalServiceCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsExternalServiceCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/gesture/AndroidTest.xml b/tests/tests/gesture/AndroidTest.xml
index 497cad1..8cc1cd4 100644
--- a/tests/tests/gesture/AndroidTest.xml
+++ b/tests/tests/gesture/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.gesture.cts" />
+        <option name="runtime-hint" value="10m50s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/graphics/Android.mk b/tests/tests/graphics/Android.mk
index d4d0d33..ee3b453 100644
--- a/tests/tests/graphics/Android.mk
+++ b/tests/tests/graphics/Android.mk
@@ -22,7 +22,13 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target-minus-junit4 \
+    compatibility-device-util \
+    ctstestrunner \
+    android-support-annotations
+
 LOCAL_JNI_SHARED_LIBRARIES := libctsgraphics_jni
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/graphics/AndroidManifest.xml b/tests/tests/graphics/AndroidManifest.xml
index f14506f..c6cf40f 100644
--- a/tests/tests/graphics/AndroidManifest.xml
+++ b/tests/tests/graphics/AndroidManifest.xml
@@ -31,8 +31,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.graphics.cts.MockActivity" android:label="MockActivity" />
-
         <activity android:name="android.opengl.cts.CompressedTextureCtsActivity"
             android:label="CompressedTextureCtsActivity"
             android:screenOrientation="nosensor">
@@ -50,7 +48,8 @@
 
         <activity android:name="android.opengl.cts.OpenGlEsVersionCtsActivity"/>
 
-        <activity android:name="android.graphics.drawable.cts.DrawableStubActivity"/>
+        <activity android:name="android.graphics.drawable.cts.DrawableStubActivity"
+                  android:theme="@style/WhiteBackgroundNoWindowAnimation"/>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
index bef75d4..f508857 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
index 85cf20b..fc383fb 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index 09fd92f..237c86e 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
index 9f1b257..0a4b40f 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
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-nodpi/vector_icon_random_path_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
index 67f5746..d010d79 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
index d24321c..5ada060 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
index 7e35798..5af7090 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
index 1427f4b..24b9662 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
index 5880467..7afe0da 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
index 93fb1d0..801573c 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
index 1703878..d3c5975 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/animated_state_list_with_avd.xml b/tests/tests/graphics/res/drawable/animated_state_list_with_avd.xml
new file mode 100644
index 0000000..7a2d3c2
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/animated_state_list_with_avd.xml
@@ -0,0 +1,54 @@
+<?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-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+            android:state_focused="true"
+            android:id="@+id/focused"
+            android:drawable="@drawable/red" />
+    <item
+            android:state_checked="false"
+            android:id="@+id/unchecked"
+            android:drawable="@drawable/black" />
+    <transition
+            android:fromId="@+id/unchecked"
+            android:toId="@+id/focused">
+        <!--empty avd -->
+        <animated-vector
+            android:drawable="@drawable/vector_drawable_grouping_1" >
+        </animated-vector>
+    </transition>
+    <transition
+            android:fromId="@+id/focused"
+            android:toId="@+id/unchecked">
+        <animated-vector
+                android:drawable="@drawable/vector_drawable_grouping_1" >
+            <target
+                    android:name="sun"
+                    android:animation="@anim/animation_grouping_1_01" />
+            <target
+                    android:name="earth"
+                    android:animation="@anim/animation_grouping_1_01" />
+        </animated-vector>
+    </transition>
+    <item
+            android:state_checked="true"
+            android:drawable="@drawable/blue" />
+    <item
+            android:state_activated="true"
+            android:drawable="@drawable/yellow" />
+</animated-selector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/animated_vector_favorite.xml b/tests/tests/graphics/res/drawable/animated_vector_favorite.xml
new file mode 100644
index 0000000..f831b7e
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/animated_vector_favorite.xml
@@ -0,0 +1,96 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+                android:height="128dp"
+                android:width="128dp"
+                android:viewportHeight="480"
+                android:viewportWidth="480" >
+
+            <group
+                    android:name="root"
+                    android:translateX="240.0"
+                    android:translateY="240.0" >
+                <path
+                        android:name="favorite"
+                        android:fillColor="#ff000000"
+                        android:strokeWidth="2"
+                        android:pathData="M2.100006104,-6
+                C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104
+                C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6
+                C-4.492996216,-6,-5.949996948,-3.718399048,-5.949996948,-1.149993896
+                C-5.949996948,2.379302979,-5.699996948,5.100006104,0,5.100006104
+                C5.699996948,5.100006104,6,2.379302979,6,-1.149993896
+                C6,-3.718399048,4.643005371-6,2.100006104-6" />
+            </group>
+
+        </vector>
+    </aapt:attr>
+
+    <target android:name="favorite">
+        <aapt:attr name="android:animation">
+            <set>
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="pathData"
+                        android:valueFrom="@string/round_box"
+                        android:valueTo="@string/heart"
+                        android:valueType="pathType" />
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="fillAlpha"
+                        android:valueFrom="1.0"
+                        android:valueTo="0.5" />
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="strokeAlpha"
+                        android:valueFrom="1.0"
+                        android:valueTo="0.1" />
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="strokeColor"
+                        android:valueFrom="#FF0000FF"
+                        android:valueTo="#FFFFFF00" />
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="fillColor"
+                        android:valueFrom="#FFFF00FF"
+                        android:valueTo="#FF00FF00" />
+            </set>
+        </aapt:attr>
+    </target>
+
+    <target android:name="root">
+        <aapt:attr name="android:animation">
+            <set>
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="scaleX"
+                        android:valueFrom="5"
+                        android:valueTo="20" />
+                <objectAnimator
+                        android:duration="3000"
+                        android:propertyName="scaleY"
+                        android:valueFrom="5"
+                        android:valueTo="20" />
+            </set>
+        </aapt:attr>
+    </target>
+
+</animated-vector>
\ No newline at end of file
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/infinite_avd.xml b/tests/tests/graphics/res/drawable/infinite_avd.xml
new file mode 100644
index 0000000..c1d5265
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/infinite_avd.xml
@@ -0,0 +1,56 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+                android:height="128dp"
+                android:width="128dp"
+                android:viewportHeight="480"
+                android:viewportWidth="480" >
+
+            <group
+                    android:translateX="240.0"
+                    android:translateY="240.0" >
+                <path
+                        android:name="favorite"
+                        android:fillColor="#ff000000"
+                        android:strokeWidth="2"
+                        android:pathData="M2.100006104,-6
+                C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104
+                C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6
+                C-4.492996216,-6,-5.949996948,-3.718399048,-5.949996948,-1.149993896
+                C-5.949996948,2.379302979,-5.699996948,5.100006104,0,5.100006104
+                C5.699996948,5.100006104,6,2.379302979,6,-1.149993896
+                C6,-3.718399048,4.643005371-6,2.100006104-6" />
+            </group>
+
+        </vector>
+    </aapt:attr>
+    <target android:name="favorite">
+        <aapt:attr name="android:animation">
+            <set>
+                <objectAnimator
+                        android:duration="400"
+                        android:repeatCount="-1"
+                        android:propertyName="fillColor"
+                        android:valueFrom="#FF000000"
+                        android:valueTo="#FFFFFFFF" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/drawable/layerdrawable_theme.xml b/tests/tests/graphics/res/drawable/layerdrawable_theme.xml
index fac42b2..2a678ff 100644
--- a/tests/tests/graphics/res/drawable/layerdrawable_theme.xml
+++ b/tests/tests/graphics/res/drawable/layerdrawable_theme.xml
@@ -25,6 +25,5 @@
             android:dither="?attr/themeBoolean"
             android:src="?attr/themeNinePatch" />
     </item>
-    <item android:drawable="?attr/themeDrawable" />
 
-</layer-list>
+</layer-list>
\ No newline at end of file
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/layout/fixed_sized_imageview.xml b/tests/tests/graphics/res/layout/fixed_sized_imageview.xml
new file mode 100644
index 0000000..ec1bb71
--- /dev/null
+++ b/tests/tests/graphics/res/layout/fixed_sized_imageview.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.
+ */
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent">
+
+    <ImageView
+            android:id="@+id/imageview"
+            android:layout_width="@dimen/imageview_fixed_size"
+            android:layout_height="@dimen/imageview_fixed_size"
+            android:layerType="hardware"
+            android:src="@drawable/animated_vector_favorite" />
+</FrameLayout>
\ No newline at end of file
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/res/values/dimens.xml b/tests/tests/graphics/res/values/dimens.xml
index bae216f..46b5a37 100755
--- a/tests/tests/graphics/res/values/dimens.xml
+++ b/tests/tests/graphics/res/values/dimens.xml
@@ -39,5 +39,9 @@
     <item name="frac25610pperc" type="dimen" format="fraction">25610%p</item>
     <item name="frac6553510pperc" type="dimen" format="fraction">6553510%p</item>
     <item name="frac6553610pperc" type="dimen" format="fraction">6553610%p</item>
+
+    <!-- Size of the image view in AVD test. Choosing a size of 90px to make sure it also works on
+    watches. -->
+    <dimen name="imageview_fixed_size">90px</dimen>
 </resources>
 
diff --git a/tests/tests/graphics/res/values/strings.xml b/tests/tests/graphics/res/values/strings.xml
index 8208b19..e599d8a 100644
--- a/tests/tests/graphics/res/values/strings.xml
+++ b/tests/tests/graphics/res/values/strings.xml
@@ -177,4 +177,8 @@
 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>
     <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string>
+    <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
+    <string name="heart">"m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
+    <string name="last_screenshot">last_screenshot</string>
+    <string name="current_screenshot">current_screenshot</string>
 </resources>
diff --git a/tests/tests/graphics/res/values/styles.xml b/tests/tests/graphics/res/values/styles.xml
index 31ed175..6991be6 100644
--- a/tests/tests/graphics/res/values/styles.xml
+++ b/tests/tests/graphics/res/values/styles.xml
@@ -166,6 +166,17 @@
         <item name="themeType">0</item>
     </style>
 
+    <style name="WhiteBackgroundNoWindowAnimation"
+           parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowOverscan">true</item>
+        <item name="android:fadingEdge">none</item>
+        <item name="android:windowBackground">@android:color/white</item>
+        <item name="android:windowContentTransitions">false</item>
+        <item name="android:windowAnimationStyle">@null</item>
+    </style>
+
     <style name="Theme_NoSwipeDismiss">
         <item name="android:windowSwipeToDismiss">false</item>
     </style>
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 6e0f277..d02adcc 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -16,23 +16,34 @@
 
 package android.graphics.cts;
 
-import android.graphics.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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Rect;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
 import android.graphics.BitmapFactory.Options;
+import android.graphics.Color;
+import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -42,36 +53,31 @@
 import java.io.InputStream;
 import java.io.RandomAccessFile;
 
-public class BitmapFactoryTest extends InstrumentationTestCase {
-    private Resources mRes;
-    // opt for non-null
-    private BitmapFactory.Options mOpt1;
-    // opt for null
-    private BitmapFactory.Options mOpt2;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapFactoryTest {
     // height and width of start.jpg
     private static final int START_HEIGHT = 31;
     private static final int START_WIDTH = 31;
-    private int mDefaultDensity;
-    private int mTargetDensity;
 
     // The test images, including baseline JPEG, a PNG, a GIF, a BMP AND a WEBP.
-    private static int[] RES_IDS = new int[] {
+    private static final int[] RES_IDS = new int[] {
             R.drawable.baseline_jpeg, R.drawable.png_test, R.drawable.gif_test,
             R.drawable.bmp_test, R.drawable.webp_test
     };
 
     // The width and height of the above image.
-    private static int WIDTHS[] = new int[] { 1280, 640, 320, 320, 640 };
-    private static int HEIGHTS[] = new int[] { 960, 480, 240, 240, 480 };
+    private static final int WIDTHS[] = new int[] { 1280, 640, 320, 320, 640 };
+    private static final int HEIGHTS[] = new int[] { 960, 480, 240, 240, 480 };
 
     // Configurations for BitmapFactory.Options
-    private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565};
-    private static int[] COLOR_TOLS = new int[] {16, 49, 576};
+    private static final Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565};
+    private static final int[] COLOR_TOLS = new int[] {16, 49, 576};
 
-    private static Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888};
-    private static int[] COLOR_TOLS_RGBA = new int[] {72, 124};
+    private static final Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888};
+    private static final int[] COLOR_TOLS_RGBA = new int[] {72, 124};
 
-    private static int[] RAW_COLORS = new int[] {
+    private static final int[] RAW_COLORS = new int[] {
         // raw data from R.drawable.premul_data
         Color.argb(255, 0, 0, 0),
         Color.argb(128, 255, 0, 0),
@@ -79,7 +85,7 @@
         Color.argb(2, 255, 254, 253),
     };
 
-    private static int[] DEPREMUL_COLORS = new int[] {
+    private static final int[] DEPREMUL_COLORS = new int[] {
         // data from R.drawable.premul_data, after premultiplied store + un-premultiplied load
         Color.argb(255, 0, 0, 0),
         Color.argb(128, 255, 0, 0),
@@ -87,10 +93,17 @@
         Color.argb(2, 255, 255, 255),
     };
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRes = getInstrumentation().getTargetContext().getResources();
+    private Resources mRes;
+    // opt for non-null
+    private BitmapFactory.Options mOpt1;
+    // opt for null
+    private BitmapFactory.Options mOpt2;
+    private int mDefaultDensity;
+    private int mTargetDensity;
+
+    @Before
+    public void setup() {
+        mRes = InstrumentationRegistry.getTargetContext().getResources();
         mDefaultDensity = DisplayMetrics.DENSITY_DEFAULT;
         mTargetDensity = mRes.getDisplayMetrics().densityDpi;
 
@@ -101,11 +114,12 @@
         mOpt2.inJustDecodeBounds = true;
     }
 
+    @Test
     public void testConstructor() {
-        // new the BitmapFactory instance
         new BitmapFactory();
     }
 
+    @Test
     public void testDecodeResource1() {
         Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.start,
                 mOpt1);
@@ -117,6 +131,7 @@
         assertNull(BitmapFactory.decodeResource(mRes, R.drawable.start, mOpt2));
     }
 
+    @Test
     public void testDecodeResource2() {
         Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.start);
         assertNotNull(b);
@@ -125,6 +140,7 @@
         assertEquals(START_WIDTH * mTargetDensity / mDefaultDensity, b.getWidth(), 1.1);
     }
 
+    @Test
     public void testDecodeResourceStream() {
         InputStream is = obtainInputStream();
         Rect r = new Rect(1, 1, 1, 1);
@@ -136,6 +152,7 @@
         assertEquals(START_WIDTH, b.getWidth());
     }
 
+    @Test
     public void testDecodeByteArray1() {
         byte[] array = obtainArray();
         Bitmap b = BitmapFactory.decodeByteArray(array, 0, array.length, mOpt1);
@@ -147,6 +164,7 @@
         assertNull(BitmapFactory.decodeByteArray(array, 0, array.length, mOpt2));
     }
 
+    @Test
     public void testDecodeByteArray2() {
         byte[] array = obtainArray();
         Bitmap b = BitmapFactory.decodeByteArray(array, 0, array.length);
@@ -156,6 +174,7 @@
         assertEquals(START_WIDTH, b.getWidth());
     }
 
+    @Test
     public void testDecodeStream1() {
         InputStream is = obtainInputStream();
         Rect r = new Rect(1, 1, 1, 1);
@@ -168,6 +187,7 @@
         assertNull(BitmapFactory.decodeStream(is, r, mOpt2));
     }
 
+    @Test
     public void testDecodeStream2() {
         InputStream is = obtainInputStream();
         Bitmap b = BitmapFactory.decodeStream(is);
@@ -177,7 +197,8 @@
         assertEquals(START_WIDTH, b.getWidth());
     }
 
-    public void testDecodeStream3() throws IOException {
+    @Test
+    public void testDecodeStream3() {
         for (int i = 0; i < RES_IDS.length; ++i) {
             InputStream is = obtainInputStream(RES_IDS[i]);
             Bitmap b = BitmapFactory.decodeStream(is);
@@ -188,7 +209,8 @@
         }
     }
 
-    public void testDecodeStream4() throws IOException {
+    @Test
+    public void testDecodeStream4() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         for (int k = 0; k < COLOR_CONFIGS.length; ++k) {
             options.inPreferredConfig = COLOR_CONFIGS[k];
@@ -222,7 +244,8 @@
         }
     }
 
-    public void testDecodeStream5() throws IOException {
+    @Test
+    public void testDecodeStream5() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         for (int k = 0; k < COLOR_CONFIGS_RGBA.length; ++k) {
             options.inPreferredConfig = COLOR_CONFIGS_RGBA[k];
@@ -259,6 +282,7 @@
         }
     }
 
+    @Test
     public void testDecodeFileDescriptor1() throws IOException {
         ParcelFileDescriptor pfd = obtainParcelDescriptor(obtainPath());
         FileDescriptor input = pfd.getFileDescriptor();
@@ -272,6 +296,7 @@
         assertNull(BitmapFactory.decodeFileDescriptor(input, r, mOpt2));
     }
 
+    @Test
     public void testDecodeFileDescriptor2() throws IOException {
         ParcelFileDescriptor pfd = obtainParcelDescriptor(obtainPath());
         FileDescriptor input = pfd.getFileDescriptor();
@@ -282,6 +307,7 @@
         assertEquals(START_WIDTH, b.getWidth());
     }
 
+    @Test
     public void testDecodeFileDescriptor3() throws IOException {
         // Arbitrary offsets to use. If the offset of the FD matches the offset of the image,
         // decoding should succeed, but if they do not match, decoding should fail.
@@ -326,6 +352,7 @@
         }
     }
 
+    @Test
     public void testDecodeFile1() throws IOException {
         Bitmap b = BitmapFactory.decodeFile(obtainPath(), mOpt1);
         assertNotNull(b);
@@ -336,6 +363,7 @@
         assertNull(BitmapFactory.decodeFile(obtainPath(), mOpt2));
     }
 
+    @Test
     public void testDecodeFile2() throws IOException {
         Bitmap b = BitmapFactory.decodeFile(obtainPath());
         assertNotNull(b);
@@ -344,7 +372,8 @@
         assertEquals(START_WIDTH, b.getWidth());
     }
 
-    public void testDecodeReuseBasic() throws IOException {
+    @Test
+    public void testDecodeReuseBasic() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inMutable = true;
         options.inSampleSize = 0; // treated as 1
@@ -388,7 +417,8 @@
         assertEquals(output.hasAlpha(), hasAlpha);
     }
 
-    public void testDecodeReuseHasAlpha() throws IOException {
+    @Test
+    public void testDecodeReuseHasAlpha() {
         final int bitmapSize = 31; // size in pixels of start, pass, and alpha resources
         final int pixelCount = bitmapSize * bitmapSize;
 
@@ -408,7 +438,8 @@
         decodeResourceWithReuse(bitmap, R.drawable.alpha, true);
     }
 
-    public void testDecodeReuseFormats() throws IOException {
+    @Test
+    public void testDecodeReuseFormats() {
         // reuse should support all image formats
         for (int i = 0; i < RES_IDS.length; ++i) {
             Bitmap reuseBuffer = Bitmap.createBitmap(1000000, 1, Bitmap.Config.ALPHA_8);
@@ -422,7 +453,8 @@
         }
     }
 
-    public void testDecodeReuseFailure() throws IOException {
+    @Test
+    public void testDecodeReuseFailure() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inMutable = true;
         options.inScaled = false;
@@ -432,13 +464,14 @@
         options.inBitmap = reduced;
         options.inSampleSize = 1;
         try {
-            Bitmap original = BitmapFactory.decodeResource(mRes, R.drawable.robot, options);
+            BitmapFactory.decodeResource(mRes, R.drawable.robot, options);
             fail("should throw exception due to lack of space");
         } catch (IllegalArgumentException e) {
         }
     }
 
-    public void testDecodeReuseScaling() throws IOException {
+    @Test
+    public void testDecodeReuseScaling() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inMutable = true;
         options.inScaled = false;
@@ -455,7 +488,8 @@
         assertEquals(originalSize, reduced.getByteCount() * 16);
     }
 
-    public void testDecodeReuseDoubleScaling() throws IOException {
+    @Test
+    public void testDecodeReuseDoubleScaling() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inMutable = true;
         options.inScaled = false;
@@ -476,7 +510,8 @@
         assertEquals(originalSize, doubleScaled.getByteCount());
     }
 
-    public void testDecodeReuseEquivalentScaling() throws IOException {
+    @Test
+    public void testDecodeReuseEquivalentScaling() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inMutable = true;
         options.inScaled = true;
@@ -495,12 +530,14 @@
         assertSame(densityReduced, scaleReduced);
     }
 
-    public void testDecodePremultipliedDefault() throws IOException {
+    @Test
+    public void testDecodePremultipliedDefault() {
         Bitmap simplePremul = BitmapFactory.decodeResource(mRes, R.drawable.premul_data);
         assertTrue(simplePremul.isPremultiplied());
     }
 
-    public void testDecodePremultipliedData() throws IOException {
+    @Test
+    public void testDecodePremultipliedData() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inScaled = false;
         Bitmap premul = BitmapFactory.decodeResource(mRes, R.drawable.premul_data, options);
@@ -520,6 +557,7 @@
         }
     }
 
+    @Test
     public void testDecodeInPurgeableAllocationCount() {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inSampleSize = 1;
@@ -542,6 +580,7 @@
         assertEquals(b.getDensity(), mDefaultCreationDensity);
     }
 
+    @Test
     public void testDecodeScaling() {
         BitmapFactory.Options defaultOpt = new BitmapFactory.Options();
 
@@ -573,6 +612,7 @@
     }
 
     // Test that writing an index8 bitmap to a Parcel succeeds.
+    @Test
     public void testParcel() {
         // Turn off scaling, which would convert to an 8888 bitmap, which does not expose
         // the bug.
@@ -598,6 +638,7 @@
         assertTrue(b2.compress(Bitmap.CompressFormat.JPEG, 50, baos));
     }
 
+    @Test
     public void testConfigs() {
         // The output Config of a BitmapFactory decode depends on the request from the
         // client and the properties of the image to be decoded.
@@ -633,6 +674,48 @@
         decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true, false);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testMutableHardwareInDecodeResource() {
+        Options options = new Options();
+        options.inMutable = true;
+        options.inPreferredConfig = Config.HARDWARE;
+        BitmapFactory.decodeResource(mRes, R.drawable.alpha, options);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testMutableHardwareInDecodeByteArray() {
+        Options options = new Options();
+        options.inMutable = true;
+        options.inPreferredConfig = Config.HARDWARE;
+        BitmapFactory.decodeByteArray(new byte[100], 1, 20, options);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testMutableHardwareInDecodeFile() {
+        Options options = new Options();
+        options.inMutable = true;
+        options.inPreferredConfig = Config.HARDWARE;
+        BitmapFactory.decodeFile("barely/care.jpg", options);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testMutableHardwareInDecodeFileDescriptor() {
+        Options options = new Options();
+        options.inMutable = true;
+        options.inPreferredConfig = Config.HARDWARE;
+        BitmapFactory.decodeFileDescriptor(null, new Rect(), options);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testMutableHardwareInDecodeResourceStream() {
+        Options options = new Options();
+        options.inMutable = true;
+        options.inPreferredConfig = Config.HARDWARE;
+        TypedValue value = new TypedValue();
+        BitmapFactory.decodeResourceStream(mRes, value,
+                new ByteArrayInputStream(new byte[20]), new Rect(), options);
+    }
+
     private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray,
             boolean hasColorTable) {
         Options opts = new BitmapFactory.Options();
@@ -697,7 +780,7 @@
         }
     }
 
-    private Bitmap grayToARGB(Bitmap gray) {
+    private static Bitmap grayToARGB(Bitmap gray) {
         Bitmap argb = Bitmap.createBitmap(gray.getWidth(), gray.getHeight(), Config.ARGB_8888);
         for (int y = 0; y < argb.getHeight(); y++) {
             for (int x = 0; x < argb.getWidth(); x++) {
@@ -725,11 +808,9 @@
         return mRes.openRawResource(resId);
     }
 
-    private ParcelFileDescriptor obtainParcelDescriptor(String path)
-            throws IOException {
+    private static ParcelFileDescriptor obtainParcelDescriptor(String path) throws IOException {
         File file = new File(path);
-        return(ParcelFileDescriptor.open(file,
-                ParcelFileDescriptor.MODE_READ_ONLY));
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
     }
 
     private String obtainPath() throws IOException {
@@ -744,7 +825,7 @@
      *               with an offset. Must be less than or equal to 1024
      */
     private String obtainPath(int resId, long offset) throws IOException {
-        File dir = getInstrumentation().getTargetContext().getFilesDir();
+        File dir = InstrumentationRegistry.getTargetContext().getFilesDir();
         dir.mkdirs();
         // The suffix does not necessarily represent theactual file type.
         File file = new File(dir, "test.jpg");
@@ -771,7 +852,7 @@
     // Compare expected to actual to see if their diff is less then mseMargin.
     // lessThanMargin is to indicate whether we expect the mean square error
     // to be "less than" or "no less than".
-    private void compareBitmaps(Bitmap expected, Bitmap actual,
+    private static void compareBitmaps(Bitmap expected, Bitmap actual,
             int mseMargin, boolean lessThanMargin, boolean isPremultiplied) {
         final int width = expected.getWidth();
         final int height = expected.getHeight();
@@ -806,13 +887,13 @@
         }
     }
 
-    private int multiplyAlpha(int color, int alpha) {
+    private static int multiplyAlpha(int color, int alpha) {
         return (color * alpha + 127) / 255;
     }
 
     // For the Bitmap with Alpha, multiply the Alpha values to get the effective
     // RGB colors and then compute the color-distance.
-    private double distance(int expect, int actual, boolean isPremultiplied) {
+    private static double distance(int expect, int actual, boolean isPremultiplied) {
         if (isPremultiplied) {
             final int a1 = Color.alpha(actual);
             final int a2 = Color.alpha(expect);
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
index 426e1b2..bcd7870 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactory_OptionsTest.java
@@ -15,14 +15,25 @@
  */
 package android.graphics.cts;
 
-import android.graphics.BitmapFactory;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-public class BitmapFactory_OptionsTest extends AndroidTestCase{
+import android.graphics.BitmapFactory;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapFactory_OptionsTest {
+    @Test
     public void testOptions(){
         new BitmapFactory.Options();
     }
 
+    @Test
     public void testRequestCancelDecode(){
         BitmapFactory.Options option = new BitmapFactory.Options();
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index 328d9ed..2b7e2fb 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -16,6 +16,12 @@
 
 package android.graphics.cts;
 
+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.junit.Assert.fail;
+
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -26,11 +32,14 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
-import android.test.InstrumentationTestCase;
-import android.util.Log;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import android.graphics.cts.R;
-
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -40,23 +49,19 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 
-public class BitmapRegionDecoderTest extends InstrumentationTestCase {
-    private static final String TAG = "BitmapRegionDecoderTest";
-    private ArrayList<File> mFilesCreated = new ArrayList<File>(
-            NAMES_TEMP_FILES.length);
-
-    private Resources mRes;
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapRegionDecoderTest {
     // The test images, including baseline JPEGs and progressive JPEGs, a PNG,
     // a WEBP, a GIF and a BMP.
-    private static int[] RES_IDS = new int[] {
+    private static final int[] RES_IDS = new int[] {
             R.drawable.baseline_jpeg, R.drawable.progressive_jpeg,
             R.drawable.baseline_restart_jpeg,
             R.drawable.progressive_restart_jpeg,
             R.drawable.png_test, R.drawable.webp_test,
             R.drawable.gif_test, R.drawable.bmp_test
     };
-    private static String[] NAMES_TEMP_FILES = new String[] {
+    private static final String[] NAMES_TEMP_FILES = new String[] {
         "baseline_temp.jpg", "progressive_temp.jpg", "baseline_restart_temp.jpg",
         "progressive_restart_temp.jpg", "png_temp.png", "webp_temp.webp",
         "gif_temp.gif", "bmp_temp.bmp"
@@ -64,47 +69,49 @@
 
     // The width and height of the above image.
     // -1 denotes that the image format is not supported by BitmapRegionDecoder
-    private static int WIDTHS[] = new int[] {
+    private static final int WIDTHS[] = new int[] {
             1280, 1280, 1280, 1280, 640, 640, -1, -1};
-    private static int HEIGHTS[] = new int[] {960, 960, 960, 960, 480, 480, -1, -1};
+    private static final int HEIGHTS[] = new int[] {960, 960, 960, 960, 480, 480, -1, -1};
 
     // The number of test images, format of which is supported by BitmapRegionDecoder
-    private static int NUM_TEST_IMAGES = 6;
+    private static final int NUM_TEST_IMAGES = 6;
 
-    private static int TILE_SIZE = 256;
+    private static final int TILE_SIZE = 256;
 
     // Configurations for BitmapFactory.Options
-    private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888,
+    private static final Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888,
             Config.RGB_565};
-    private static int[] SAMPLESIZES = new int[] {1, 4};
-
-    private int[] mExpectedColors = new int [TILE_SIZE * TILE_SIZE];
-    private int[] mActualColors = new int [TILE_SIZE * TILE_SIZE];
+    private static final int[] SAMPLESIZES = new int[] {1, 4};
 
     // We allow a certain degree of discrepancy between the tile-based decoding
     // result and the regular decoding result, because the two decoders may have
     // different implementations. The allowable discrepancy is set to a mean
     // square error of 3 * (1 * 1) among the RGB values.
-    private int mMseMargin = 3 * (1 * 1);
+    private static final int MSE_MARGIN = 3 * (1 * 1);
 
     // MSE margin for WebP Region-Decoding for 'Config.RGB_565' is little bigger.
-    private int mMseMarginWebPConfigRgb565 = 8;
+    private static final int MSE_MARGIN_WEB_P_CONFIG_RGB_565 = 8;
 
+    private final int[] mExpectedColors = new int [TILE_SIZE * TILE_SIZE];
+    private final int[] mActualColors = new int [TILE_SIZE * TILE_SIZE];
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRes = getInstrumentation().getTargetContext().getResources();
+    private ArrayList<File> mFilesCreated = new ArrayList<>(NAMES_TEMP_FILES.length);
+
+    private Resources mRes;
+
+    @Before
+    public void setup() {
+        mRes = InstrumentationRegistry.getTargetContext().getResources();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         for (File file : mFilesCreated) {
             file.delete();
         }
-        super.tearDown();
     }
 
+    @Test
     public void testNewInstanceInputStream() throws IOException {
         for (int i = 0; i < RES_IDS.length; ++i) {
             InputStream is = obtainInputStream(RES_IDS[i]);
@@ -124,6 +131,7 @@
         }
     }
 
+    @Test
     public void testNewInstanceByteArray() throws IOException {
         for (int i = 0; i < RES_IDS.length; ++i) {
             byte[] imageData = obtainByteArray(RES_IDS[i]);
@@ -139,6 +147,7 @@
         }
     }
 
+    @Test
     public void testNewInstanceStringAndFileDescriptor() throws IOException {
         for (int i = 0; i < RES_IDS.length; ++i) {
             String filepath = obtainPath(i);
@@ -161,6 +170,7 @@
         }
     }
 
+    @Test
     public void testDecodeRegionInputStream() throws IOException {
         Options opts = new BitmapFactory.Options();
         for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
@@ -175,10 +185,10 @@
                     Bitmap wholeImage = BitmapFactory.decodeStream(is2, null, opts);
 
                     if (RES_IDS[i] == R.drawable.webp_test && COLOR_CONFIGS[k] == Config.RGB_565) {
-                        compareRegionByRegion(decoder, opts, mMseMarginWebPConfigRgb565,
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN_WEB_P_CONFIG_RGB_565,
                                               wholeImage);
                     } else {
-                        compareRegionByRegion(decoder, opts, mMseMargin, wholeImage);
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN, wholeImage);
                     }
                     wholeImage.recycle();
                 }
@@ -186,6 +196,7 @@
         }
     }
 
+    @Test
     public void testDecodeRegionInputStreamInBitmap() throws IOException {
         Options opts = new BitmapFactory.Options();
         for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
@@ -205,10 +216,10 @@
                             wholeImage.getWidth(), wholeImage.getHeight(), opts.inPreferredConfig);
 
                     if (RES_IDS[i] == R.drawable.webp_test && COLOR_CONFIGS[k] == Config.RGB_565) {
-                        compareRegionByRegion(decoder, opts, mMseMarginWebPConfigRgb565,
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN_WEB_P_CONFIG_RGB_565,
                                               wholeImage);
                     } else {
-                        compareRegionByRegion(decoder, opts, mMseMargin, wholeImage);
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN, wholeImage);
                     }
                     wholeImage.recycle();
                 }
@@ -216,6 +227,7 @@
         }
     }
 
+    @Test
     public void testDecodeRegionByteArray() throws IOException {
         Options opts = new BitmapFactory.Options();
         for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
@@ -231,10 +243,10 @@
                             0, imageData.length, opts);
 
                     if (RES_IDS[i] == R.drawable.webp_test && COLOR_CONFIGS[k] == Config.RGB_565) {
-                        compareRegionByRegion(decoder, opts, mMseMarginWebPConfigRgb565,
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN_WEB_P_CONFIG_RGB_565,
                                               wholeImage);
                     } else {
-                        compareRegionByRegion(decoder, opts, mMseMargin, wholeImage);
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN, wholeImage);
                     }
                     wholeImage.recycle();
                 }
@@ -242,6 +254,7 @@
         }
     }
 
+    @Test
     public void testDecodeRegionStringAndFileDescriptor() throws IOException {
         Options opts = new BitmapFactory.Options();
         for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
@@ -255,10 +268,10 @@
                         BitmapRegionDecoder.newInstance(filepath, false);
                     Bitmap wholeImage = BitmapFactory.decodeFile(filepath, opts);
                     if (RES_IDS[i] == R.drawable.webp_test && COLOR_CONFIGS[k] == Config.RGB_565) {
-                        compareRegionByRegion(decoder, opts, mMseMarginWebPConfigRgb565,
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN_WEB_P_CONFIG_RGB_565,
                                               wholeImage);
                     } else {
-                        compareRegionByRegion(decoder, opts, mMseMargin, wholeImage);
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN, wholeImage);
                     }
 
                     ParcelFileDescriptor pfd1 = obtainParcelDescriptor(filepath);
@@ -267,10 +280,10 @@
                     ParcelFileDescriptor pfd2 = obtainParcelDescriptor(filepath);
                     FileDescriptor fd2 = pfd2.getFileDescriptor();
                     if (RES_IDS[i] == R.drawable.webp_test && COLOR_CONFIGS[k] == Config.RGB_565) {
-                        compareRegionByRegion(decoder, opts, mMseMarginWebPConfigRgb565,
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN_WEB_P_CONFIG_RGB_565,
                                               wholeImage);
                     } else {
-                        compareRegionByRegion(decoder, opts, mMseMargin, wholeImage);
+                        compareRegionByRegion(decoder, opts, MSE_MARGIN, wholeImage);
                     }
                     wholeImage.recycle();
                 }
@@ -278,6 +291,7 @@
         }
     }
 
+    @Test
     public void testRecycle() throws IOException {
         InputStream is = obtainInputStream(RES_IDS[0]);
         BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
@@ -312,6 +326,7 @@
     //     (2) The width, height, and Config of inBitmap are never changed.
     //     (3) All of the pixels decoded into inBitmap exactly match the pixels
     //         of a decode where inBitmap is NULL.
+    @Test
     public void testInBitmapReuse() throws IOException {
         Options defaultOpts = new BitmapFactory.Options();
         Options reuseOpts = new BitmapFactory.Options();
@@ -418,7 +433,7 @@
         }
     }
 
-    private Bitmap cropBitmap(Bitmap wholeImage, Rect rect) {
+    private static Bitmap cropBitmap(Bitmap wholeImage, Rect rect) {
         Bitmap cropped = Bitmap.createBitmap(rect.width(), rect.height(),
                 wholeImage.getConfig());
         Canvas canvas = new Canvas(cropped);
@@ -446,7 +461,7 @@
     }
 
     private String obtainPath(int idx) throws IOException {
-        File dir = getInstrumentation().getTargetContext().getFilesDir();
+        File dir = InstrumentationRegistry.getTargetContext().getFilesDir();
         dir.mkdirs();
         File file = new File(dir, NAMES_TEMP_FILES[idx]);
         InputStream is = obtainInputStream(RES_IDS[idx]);
@@ -462,11 +477,10 @@
         return (file.getPath());
     }
 
-    private ParcelFileDescriptor obtainParcelDescriptor(String path)
+    private static ParcelFileDescriptor obtainParcelDescriptor(String path)
             throws IOException {
         File file = new File(path);
-        return(ParcelFileDescriptor.open(file,
-                ParcelFileDescriptor.MODE_READ_ONLY));
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
     }
 
 
@@ -513,7 +527,7 @@
         }
     }
 
-    private double distance(int exp, int actual) {
+    private static double distance(int exp, int actual) {
         int r = Color.red(actual) - Color.red(exp);
         int g = Color.green(actual) - Color.green(exp);
         int b = Color.blue(actual) - Color.blue(exp);
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
index 4331581..812c308 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
@@ -15,19 +15,24 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Shader;
-import android.graphics.Bitmap.Config;
-import android.graphics.Shader.TileMode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class BitmapShaderTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapShaderTest {
     private static final int TILE_WIDTH = 20;
     private static final int TILE_HEIGHT = 20;
     private static final int BORDER_WIDTH = 5;
@@ -35,6 +40,7 @@
     private static final int CENTER_COLOR = Color.RED;
     private static final int NUM_TILES = 4;
 
+    @Test
     public void testBitmapShader() {
         Bitmap tile = Bitmap.createBitmap(TILE_WIDTH, TILE_HEIGHT, Config.ARGB_8888);
         tile.eraseColor(BORDER_COLOR);
@@ -56,7 +62,7 @@
 
         for (int y = 0; y < NUM_TILES; y++) {
             for (int x = 0; x < NUM_TILES; x++) {
-                checkTile(b, x * TILE_WIDTH, y * TILE_HEIGHT);
+                verifyTile(b, x * TILE_WIDTH, y * TILE_HEIGHT);
             }
         }
     }
@@ -65,14 +71,14 @@
      * Check the colors of the tile at the given coordinates in the given
      * bitmap.
      */
-    private void checkTile(Bitmap bitmap, int tileX, int tileY) {
+    private void verifyTile(Bitmap bitmap, int tileX, int tileY) {
         for (int y = 0; y < TILE_HEIGHT; y++) {
             for (int x = 0; x < TILE_WIDTH; x++) {
                 if (x < BORDER_WIDTH || x >= TILE_WIDTH - BORDER_WIDTH ||
                     y < BORDER_WIDTH || y >= TILE_HEIGHT - BORDER_WIDTH) {
-                    assertColor(BORDER_COLOR, bitmap, x + tileY, y + tileY);
+                    verifyColor(BORDER_COLOR, bitmap, x + tileX, y + tileY);
                 } else {
-                    assertColor(CENTER_COLOR, bitmap, x + tileY, y + tileY);
+                    verifyColor(CENTER_COLOR, bitmap, x + tileX, y + tileY);
                 }
             }
         }
@@ -83,11 +89,9 @@
      * matches the given color. Simply returns if the coordinates are outside
      * the bitmap area.
      */
-    private void assertColor(int color, Bitmap bitmap, int x, int y) {
+    private void verifyColor(int color, Bitmap bitmap, int x, int y) {
         if (x < bitmap.getWidth() && y < bitmap.getHeight()) {
             assertEquals(color, bitmap.getPixel(x, y));
-        } else {
-            return;
         }
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index f820771..34aeb25 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -15,147 +15,128 @@
  */
 package android.graphics.cts;
 
-import android.graphics.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.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.res.Resources;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.Bitmap.Config;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
 
-public class BitmapTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapTest {
+    // small alpha values cause color values to be pre-multiplied down, losing accuracy
+    private static final int PREMUL_COLOR = Color.argb(2, 255, 254, 253);
+    private static final int PREMUL_ROUNDED_COLOR = Color.argb(2, 255, 255, 255);
+    private static final int PREMUL_STORED_COLOR = Color.argb(2, 2, 2, 2);
+
     private Resources mRes;
     private Bitmap mBitmap;
     private BitmapFactory.Options mOptions;
 
-    // small alpha values cause color values to be pre-multiplied down, losing accuracy
-    private final int PREMUL_COLOR = Color.argb(2, 255, 254, 253);
-    private final int PREMUL_ROUNDED_COLOR = Color.argb(2, 255, 255, 255);
-    private final int PREMUL_STORED_COLOR = Color.argb(2, 2, 2, 2);
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mRes = getContext().getResources();
+    @Before
+    public void setup() {
+        mRes = InstrumentationRegistry.getTargetContext().getResources();
         mOptions = new BitmapFactory.Options();
         mOptions.inScaled = false;
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
     }
 
-    public void testCompress(){
+    @Test(expected=IllegalStateException.class)
+    public void testCompressRecycled() {
         mBitmap.recycle();
+        mBitmap.compress(CompressFormat.JPEG, 0, null);
+    }
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.compress(CompressFormat.JPEG, 0, null);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+    @Test(expected=NullPointerException.class)
+    public void testCompressNullStream() {
+        mBitmap.compress(CompressFormat.JPEG, 0, null);
+    }
 
-        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
+    @Test(expected=IllegalArgumentException.class)
+    public void testCompressQualityTooLow() {
+        mBitmap.compress(CompressFormat.JPEG, -1, new ByteArrayOutputStream());
+    }
 
-        // abnormal case: out stream is null
-        try{
-            mBitmap.compress(CompressFormat.JPEG, 0, null);
-            fail("shouldn't come to here");
-        }catch(NullPointerException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testCompressQualityTooHigh() {
+        mBitmap.compress(CompressFormat.JPEG, 101, new ByteArrayOutputStream());
+    }
 
-        // abnormal case: quality less than 0
-        try{
-            mBitmap.compress(CompressFormat.JPEG, -1, new ByteArrayOutputStream());
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
-
-        // abnormal case: quality bigger than 100
-        try{
-            mBitmap.compress(CompressFormat.JPEG, 101, new ByteArrayOutputStream());
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
-
-        //normal case
+    @Test
+    public void testCompress() {
         assertTrue(mBitmap.compress(CompressFormat.JPEG, 50, new ByteArrayOutputStream()));
     }
 
-    public void testCopy(){
+    @Test(expected=IllegalStateException.class)
+    public void testCopyRecycled() {
         mBitmap.recycle();
+        mBitmap.copy(Config.RGB_565, false);
+    }
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.copy(Config.RGB_565, false);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-            // expected
-        }
-
+    @Test
+    public void testCopy() {
         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
         Bitmap bitmap = mBitmap.copy(Config.ARGB_8888, false);
         WidgetTestUtils.assertEquals(mBitmap, bitmap);
     }
 
-    public void testCopyPixelsToBuffer(){
+    @Test(expected=RuntimeException.class)
+    public void testCopyPixelsToBufferUnsupportedBufferClass() {
+        final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
+
+        mBitmap.copyPixelsToBuffer(CharBuffer.allocate(pixSize));
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testCopyPixelsToBufferBufferTooSmall() {
         final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
         final int tooSmall = pixSize / 2;
 
-        // abnormal case: unsupported Buffer subclass
-        try{
-            mBitmap.copyPixelsToBuffer(CharBuffer.allocate(pixSize));
-            fail("shouldn't come to here");
-        }catch(RuntimeException e1){
-        }
+        mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
+    }
 
-        // abnormal case: Buffer not large enough for pixels
-        try{
-            mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
-            fail("shouldn't come to here");
-        }catch(RuntimeException e2){
-        }
+    @Test
+    public void testCopyPixelsToBuffer() {
+        final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
 
-        // normal case
         ByteBuffer byteBuf = ByteBuffer.allocate(pixSize);
         assertEquals(0, byteBuf.position());
         mBitmap.copyPixelsToBuffer(byteBuf);
         assertEquals(pixSize, byteBuf.position());
 
-        // abnormal case: Buffer not large enough for pixels
-        try{
-            mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
-            fail("shouldn't come to here");
-        }catch(RuntimeException e3){
-        }
-
-        // normal case
         ShortBuffer shortBuf = ShortBuffer.allocate(pixSize);
         assertEquals(0, shortBuf.position());
         mBitmap.copyPixelsToBuffer(shortBuf);
         assertEquals(pixSize >> 1, shortBuf.position());
 
-        // abnormal case: Buffer not large enough for pixels
-        try{
-            mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
-            fail("shouldn't come to here");
-        }catch(RuntimeException e4){
-        }
-
-        // normal case
         IntBuffer intBuf1 = IntBuffer.allocate(pixSize);
         assertEquals(0, intBuf1.position());
         mBitmap.copyPixelsToBuffer(intBuf1);
@@ -178,7 +159,8 @@
         }
     }
 
-    public void testCreateBitmap1(){
+    @Test
+    public void testCreateBitmap1() {
         int[] colors = createColors(100);
         Bitmap bitmap = Bitmap.createBitmap(colors, 10, 10, Config.RGB_565);
         Bitmap ret = Bitmap.createBitmap(bitmap);
@@ -188,14 +170,13 @@
         assertEquals(Config.RGB_565, ret.getConfig());
     }
 
-    public void testCreateBitmap2(){
-        //abnormal case: Illegal Argument
-        try{
-            Bitmap.createBitmap(mBitmap, -100, 50, 50, 200);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapNegativeX() {
+        Bitmap.createBitmap(mBitmap, -100, 50, 50, 200);
+    }
 
+    @Test
+    public void testCreateBitmap2() {
         // special case: output bitmap is equal to the input bitmap
         mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888);
         Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100);
@@ -209,37 +190,45 @@
         assertFalse(mBitmap.equals(ret));
     }
 
-    public void testCreateBitmap3(){
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapNegativeXY() {
         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
 
-        //abnormal case: x and/or y less than 0
-        try{
-            Bitmap.createBitmap(mBitmap, -1, -1, 10, 10, null, false);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        // abnormal case: x and/or y less than 0
+        Bitmap.createBitmap(mBitmap, -1, -1, 10, 10, null, false);
+    }
 
-        //abnormal case: width and/or height less than 0
-        try{
-            Bitmap.createBitmap(mBitmap, 1, 1, -10, -10, null, false);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapNegativeWidthHeight() {
+        mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
 
-        //abnormal case: (x + width) bigger than source bitmap's width
-        try{
-            Bitmap.createBitmap(mBitmap, 10, 10, 95, 50, null, false);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        // abnormal case: width and/or height less than 0
+        Bitmap.createBitmap(mBitmap, 1, 1, -10, -10, null, false);
+    }
 
-        //abnormal case: (y + height) bigger than source bitmap's height
-        try{
-            Bitmap.createBitmap(mBitmap, 10, 10, 50, 95, null, false);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapXRegionTooWide() {
+        mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
 
+        // abnormal case: (x + width) bigger than source bitmap's width
+        Bitmap.createBitmap(mBitmap, 10, 10, 95, 50, null, false);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapYRegionTooTall() {
+        mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+
+        // abnormal case: (y + height) bigger than source bitmap's height
+        Bitmap.createBitmap(mBitmap, 10, 10, 50, 95, null, false);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateMutableBitmapWithHardwareConfig() {
+        Bitmap.createBitmap(100, 100, Config.HARDWARE);
+    }
+
+    @Test
+    public void testCreateBitmap3() {
         // special case: output bitmap is equal to the input bitmap
         mBitmap = Bitmap.createBitmap(new int[100 * 100], 100, 100, Config.ARGB_8888);
         Bitmap ret = Bitmap.createBitmap(mBitmap, 0, 0, 100, 100, null, false);
@@ -253,7 +242,8 @@
         assertFalse(mBitmap.equals(ret));
     }
 
-    public void testCreateBitmap4(){
+    @Test
+    public void testCreateBitmap4() {
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
         assertNotNull(ret);
         assertEquals(100, ret.getWidth());
@@ -261,43 +251,49 @@
         assertEquals(Config.RGB_565, ret.getConfig());
     }
 
-    public void testCreateBitmap6(){
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapFromColorsNegativeWidthHeight() {
         int[] colors = createColors(100);
 
-        //abnormal case: width and/or height less than 0
-        try{
-            Bitmap.createBitmap(colors, 0, 100, -1, 100, Config.RGB_565);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        // abnormal case: width and/or height less than 0
+        Bitmap.createBitmap(colors, 0, 100, -1, 100, Config.RGB_565);
+    }
 
-        //abnormal case: stride less than width and bigger than -width
-        try{
-            Bitmap.createBitmap(colors, 10, 10, 100, 100, Config.RGB_565);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testCreateBitmapFromColorsIllegalStride() {
+        int[] colors = createColors(100);
 
-        //abnormal case: offset less than 0
-        try{
-            Bitmap.createBitmap(colors, -10, 100, 100, 100, Config.RGB_565);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        // abnormal case: stride less than width and bigger than -width
+        Bitmap.createBitmap(colors, 10, 10, 100, 100, Config.RGB_565);
+    }
 
-        //abnormal case: (offset + width) bigger than colors' length
-        try{
-            Bitmap.createBitmap(colors, 10, 100, 100, 100, Config.RGB_565);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testCreateBitmapFromColorsNegativeOffset() {
+        int[] colors = createColors(100);
 
-        //abnormal case: (lastScanline + width) bigger than colors' length
-        try{
-            Bitmap.createBitmap(colors, 10, 100, 50, 100, Config.RGB_565);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        // abnormal case: offset less than 0
+        Bitmap.createBitmap(colors, -10, 100, 100, 100, Config.RGB_565);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testCreateBitmapFromColorsOffsetTooLarge() {
+        int[] colors = createColors(100);
+
+        // abnormal case: (offset + width) bigger than colors' length
+        Bitmap.createBitmap(colors, 10, 100, 100, 100, Config.RGB_565);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testCreateBitmapFromColorsScalnlineTooLarge() {
+        int[] colors = createColors(100);
+
+        // abnormal case: (lastScanline + width) bigger than colors' length
+        Bitmap.createBitmap(colors, 10, 100, 50, 100, Config.RGB_565);
+    }
+
+    @Test
+    public void testCreateBitmap6() {
+        int[] colors = createColors(100);
 
         // normal case
         Bitmap ret = Bitmap.createBitmap(colors, 5, 10, 10, 5, Config.RGB_565);
@@ -307,7 +303,8 @@
         assertEquals(Config.RGB_565, ret.getConfig());
     }
 
-    public void testCreateScaledBitmap(){
+    @Test
+    public void testCreateScaledBitmap() {
         mBitmap = Bitmap.createBitmap(100, 200, Config.RGB_565);
         Bitmap ret = Bitmap.createScaledBitmap(mBitmap, 50, 100, false);
         assertNotNull(ret);
@@ -315,29 +312,28 @@
         assertEquals(100, ret.getHeight());
     }
 
-    public void testDescribeContents(){
+    @Test
+    public void testDescribeContents() {
         assertEquals(0, mBitmap.describeContents());
     }
 
-    public void testEraseColor(){
+    @Test(expected=IllegalStateException.class)
+    public void testEraseColorOnRecycled() {
         mBitmap.recycle();
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.eraseColor(0);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.eraseColor(0);
+    }
 
+    @Test(expected=IllegalStateException.class)
+    public void testEraseColorOnImmutable() {
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
 
         //abnormal case: bitmap is immutable
-        try{
-            mBitmap.eraseColor(0);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.eraseColor(0);
+    }
 
+    @Test
+    public void testEraseColor() {
         // normal case
         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
         mBitmap.eraseColor(0xffff0000);
@@ -345,16 +341,15 @@
         assertEquals(0xffff0000, mBitmap.getPixel(50, 50));
     }
 
-    public void testExtractAlpha1(){
+    @Test(expected=IllegalStateException.class)
+    public void testExtractAlphaFromRecycled() {
         mBitmap.recycle();
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.extractAlpha();
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.extractAlpha();
+    }
 
+    @Test
+    public void testExtractAlpha() {
         // normal case
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
         Bitmap ret = mBitmap.extractAlpha();
@@ -365,16 +360,15 @@
         assertEquals(0xFF, Color.alpha(result));
     }
 
-    public void testExtractAlpha2(){
+    @Test(expected=IllegalStateException.class)
+    public void testExtractAlphaWithPaintAndOffsetFromRecycled() {
         mBitmap.recycle();
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.extractAlpha(new Paint(), new int[]{0, 1});
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.extractAlpha(new Paint(), new int[]{0, 1});
+    }
 
+    @Test
+    public void testExtractAlphaWithPaintAndOffset() {
         // normal case
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
         Bitmap ret = mBitmap.extractAlpha(new Paint(), new int[]{0, 1});
@@ -385,6 +379,7 @@
         assertEquals(0xFF, Color.alpha(result));
     }
 
+    @Test
     public void testGetAllocationByteCount() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
         int alloc = mBitmap.getAllocationByteCount();
@@ -401,7 +396,8 @@
         assertEquals(mBitmap.getAllocationByteCount(), alloc);
     }
 
-    public void testGetConfig(){
+    @Test
+    public void testGetConfig() {
         Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
         Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
@@ -412,43 +408,54 @@
         assertEquals(Bitmap.Config.RGB_565, bm2.getConfig());
         // Attempting to create a 4444 bitmap actually creates an 8888 bitmap.
         assertEquals(Bitmap.Config.ARGB_8888, bm3.getConfig());
+
+        // Can't call Bitmap.createBitmap with Bitmap.Config.HARDWARE,
+        // because createBitmap creates mutable bitmap and hardware bitmaps are always immutable,
+        // so such call will throw an exception.
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inPreferredConfig = Bitmap.Config.HARDWARE;
+        Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot, options);
+        assertEquals(Bitmap.Config.HARDWARE, hardwareBitmap.getConfig());
     }
 
-    public void testGetHeight(){
+    @Test
+    public void testGetHeight() {
         assertEquals(31, mBitmap.getHeight());
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         assertEquals(200, mBitmap.getHeight());
     }
 
-    public void testGetNinePatchChunk(){
+    @Test
+    public void testGetNinePatchChunk() {
         assertNull(mBitmap.getNinePatchChunk());
     }
 
-    public void testGetPixel(){
+    @Test(expected=IllegalStateException.class)
+    public void testGetPixelFromRecycled() {
         mBitmap.recycle();
 
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.getPixel(10, 16);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.getPixel(10, 16);
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelXTooLarge() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
 
-        //abnormal case: x bigger than the source bitmap's width
-        try{
-            mBitmap.getPixel(200, 16);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        // abnormal case: x bigger than the source bitmap's width
+        mBitmap.getPixel(200, 16);
+    }
 
-        //abnormal case: y bigger than the source bitmap's height
-        try{
-            mBitmap.getPixel(10, 300);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelYTooLarge() {
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+
+        // abnormal case: y bigger than the source bitmap's height
+        mBitmap.getPixel(10, 300);
+    }
+
+    @Test
+    public void testGetPixel() {
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
 
         // normal case 565
         mBitmap.setPixel(10, 16, 0xFF << 24);
@@ -468,7 +475,8 @@
         assertEquals(0x1F1F1F1F, mBitmap.getPixel(5, 5));
     }
 
-    public void testGetRowBytes(){
+    @Test
+    public void testGetRowBytes() {
         Bitmap bm0 = Bitmap.createBitmap(100, 200, Bitmap.Config.ALPHA_8);
         Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
@@ -481,30 +489,35 @@
         assertEquals(400, bm3.getRowBytes());
     }
 
-    public void testGetWidth(){
+    @Test
+    public void testGetWidth() {
         assertEquals(31, mBitmap.getWidth());
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         assertEquals(100, mBitmap.getWidth());
     }
 
-    public void testHasAlpha(){
+    @Test
+    public void testHasAlpha() {
         assertFalse(mBitmap.hasAlpha());
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         assertTrue(mBitmap.hasAlpha());
     }
 
-    public void testIsMutable(){
+    @Test
+    public void testIsMutable() {
         assertFalse(mBitmap.isMutable());
         mBitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
         assertTrue(mBitmap.isMutable());
     }
 
-    public void testIsRecycled(){
+    @Test
+    public void testIsRecycled() {
         assertFalse(mBitmap.isRecycled());
         mBitmap.recycle();
         assertTrue(mBitmap.isRecycled());
     }
 
+    @Test
     public void testReconfigure() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
         int alloc = mBitmap.getAllocationByteCount();
@@ -513,21 +526,18 @@
         mBitmap.reconfigure(50, 100, Bitmap.Config.ALPHA_8);
         assertEquals(mBitmap.getAllocationByteCount(), alloc);
         assertEquals(mBitmap.getByteCount() * 8, alloc);
+    }
 
-        // test expanding
-        try {
-            mBitmap.reconfigure(101, 201, Bitmap.Config.ARGB_8888);
-            fail("shouldn't come to here");
-        } catch (IllegalArgumentException e) {
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testReconfigureExpanding() {
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+        mBitmap.reconfigure(101, 201, Bitmap.Config.ARGB_8888);
+    }
 
-        // test mutable
+    @Test(expected=IllegalStateException.class)
+    public void testReconfigureMutable() {
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
-        try {
-            mBitmap.reconfigure(1, 1, Bitmap.Config.ALPHA_8);
-            fail("shouldn't come to here");
-        } catch (IllegalStateException e) {
-        }
+        mBitmap.reconfigure(1, 1, Bitmap.Config.ALPHA_8);
     }
 
     // Used by testAlphaAndPremul. FIXME: Should we also test Index8? That would require decoding a
@@ -538,6 +548,7 @@
 
     // test that reconfigure, setHasAlpha, and setPremultiplied behave as expected with
     // respect to alpha and premultiplied.
+    @Test
     public void testAlphaAndPremul() {
         boolean falseTrue[] = new boolean[] { false, true };
         for (Config fromConfig : CONFIGS) {
@@ -557,7 +568,7 @@
                         bitmap.setHasAlpha(hasAlpha);
                         bitmap.setPremultiplied(isPremul);
 
-                        checkAlphaAndPremul(bitmap, hasAlpha, isPremul, false);
+                        verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, false);
 
                         // reconfigure to a smaller size so the function will still succeed when
                         // going to a Config that requires more bits.
@@ -570,7 +581,7 @@
 
                         // Check that the alpha and premultiplied state has not changed (unless
                         // we expected it to).
-                        checkAlphaAndPremul(bitmap, hasAlpha, isPremul, fromConfig == Config.RGB_565);
+                        verifyAlphaAndPremul(bitmap, hasAlpha, isPremul, fromConfig == Config.RGB_565);
                     }
                 }
             }
@@ -590,7 +601,7 @@
      *          reconfigured from RGB_565. If true, and bitmap is now a Config that supports alpha,
      *          hasAlpha() is expected to be true even if expectedAlpha is false.
      */
-    private void checkAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul,
+    private void verifyAlphaAndPremul(Bitmap bitmap, boolean expectedAlpha, boolean expectedPremul,
             boolean convertedFrom565) {
         switch (bitmap.getConfig()) {
             case ARGB_4444:
@@ -626,6 +637,7 @@
         }
     }
 
+    @Test
     public void testSetConfig() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
         int alloc = mBitmap.getAllocationByteCount();
@@ -634,23 +646,23 @@
         mBitmap.setConfig(Bitmap.Config.ALPHA_8);
         assertEquals(mBitmap.getAllocationByteCount(), alloc);
         assertEquals(mBitmap.getByteCount() * 2, alloc);
-
-        // test expanding
-        try {
-            mBitmap.setConfig(Bitmap.Config.ARGB_8888);
-            fail("shouldn't come to here");
-        } catch (IllegalArgumentException e) {
-        }
-
-        // test mutable
-        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
-        try {
-            mBitmap.setConfig(Bitmap.Config.ALPHA_8);
-            fail("shouldn't come to here");
-        } catch (IllegalStateException e) {
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetConfigExpanding() {
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+        // test expanding
+        mBitmap.setConfig(Bitmap.Config.ARGB_8888);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetConfigMutable() {
+        // test mutable
+        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
+        mBitmap.setConfig(Bitmap.Config.ALPHA_8);
+    }
+
+    @Test
     public void testSetHeight() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         int alloc = mBitmap.getAllocationByteCount();
@@ -659,153 +671,167 @@
         mBitmap.setHeight(100);
         assertEquals(mBitmap.getAllocationByteCount(), alloc);
         assertEquals(mBitmap.getByteCount() * 2, alloc);
-
-        // test expanding
-        try {
-            mBitmap.setHeight(201);
-            fail("shouldn't come to here");
-        } catch (IllegalArgumentException e) {
-        }
-
-        // test mutable
-        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
-        try {
-            mBitmap.setHeight(1);
-            fail("shouldn't come to here");
-        } catch (IllegalStateException e) {
-        }
     }
 
-    public void testSetPixel(){
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetHeightExpanding() {
+        // test expanding
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+        mBitmap.setHeight(201);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetHeightMutable() {
+        // test mutable
+        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
+        mBitmap.setHeight(1);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetPixelOnRecycled() {
         int color = 0xff << 24;
 
         mBitmap.recycle();
-
-        //abnormal case: the bitmap has been recycled
-        try{
-            mBitmap.setPixel(10, 16, color);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
-
-        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
-
-        //abnormal case: the bitmap is immutable
-        try{
-            mBitmap.setPixel(10, 16, color);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
-
-        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
-
-        //abnormal case: x bigger than the source bitmap's width
-        try{
-            mBitmap.setPixel(200, 16, color);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
-
-        //abnormal case: y bigger than the source bitmap's height
-        try{
-            mBitmap.setPixel(10, 300, color);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
-
-        // normal case
-        mBitmap.setPixel(10, 16, 0xFF << 24);
-        assertEquals(0xFF << 24, mBitmap.getPixel(10, 16));
+        mBitmap.setPixel(10, 16, color);
     }
 
-    public void testSetPixels(){
-        int[] colors = createColors(100);
-
-        //abnormal case: the bitmap has been recycled
-        mBitmap.recycle();
-
-        try{
-            mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
-
+    @Test(expected=IllegalStateException.class)
+    public void testSetPixelOnImmutable() {
+        int color = 0xff << 24;
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
 
-        // abnormal case: the bitmap is immutable
-        try{
-            mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.setPixel(10, 16, color);
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelXIsTooLarge() {
+        int color = 0xff << 24;
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+
+        // abnormal case: x bigger than the source bitmap's width
+        mBitmap.setPixel(200, 16, color);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelYIsTooLarge() {
+        int color = 0xff << 24;
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+
+        // abnormal case: y bigger than the source bitmap's height
+        mBitmap.setPixel(10, 300, color);
+    }
+
+    @Test
+    public void testSetPixel() {
+        int color = 0xff << 24;
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+
+        // normal case
+        mBitmap.setPixel(10, 16, color);
+        assertEquals(color, mBitmap.getPixel(10, 16));
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetPixelsOnRecycled() {
+        int[] colors = createColors(100);
+
+        mBitmap.recycle();
+        mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetPixelsOnImmutable() {
+        int[] colors = createColors(100);
+        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
+
+        mBitmap.setPixels(colors, 0, 0, 0, 0, 0, 0);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelsXYNegative() {
+        int[] colors = createColors(100);
         mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: x and/or y less than 0
-        try{
-            mBitmap.setPixels(colors, 0, 0, -1, -1, 200, 16);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        mBitmap.setPixels(colors, 0, 0, -1, -1, 200, 16);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelsWidthHeightNegative() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: width and/or height less than 0
-        try{
-            mBitmap.setPixels(colors, 0, 0, 0, 0, -1, -1);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        mBitmap.setPixels(colors, 0, 0, 0, 0, -1, -1);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelsXTooHigh() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: (x + width) bigger than the source bitmap's width
-        try{
-            mBitmap.setPixels(colors, 0, 0, 10, 10, 95, 50);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        mBitmap.setPixels(colors, 0, 0, 10, 10, 95, 50);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelsYTooHigh() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: (y + height) bigger than the source bitmap's height
-        try{
-            mBitmap.setPixels(colors, 0, 0, 10, 10, 50, 95);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        mBitmap.setPixels(colors, 0, 0, 10, 10, 50, 95);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetPixelsStrideIllegal() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: stride less than width and bigger than -width
-        try{
-            mBitmap.setPixels(colors, 0, 10, 10, 10, 50, 50);
-            fail("shouldn't come to here");
-        }catch(IllegalArgumentException e){
-        }
+        mBitmap.setPixels(colors, 0, 10, 10, 10, 50, 50);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testSetPixelsOffsetNegative() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: offset less than 0
-        try{
-            mBitmap.setPixels(colors, -1, 50, 10, 10, 50, 50);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        mBitmap.setPixels(colors, -1, 50, 10, 10, 50, 50);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testSetPixelsOffsetTooBig() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: (offset + width) bigger than the length of colors
-        try{
-            mBitmap.setPixels(colors, 60, 50, 10, 10, 50, 50);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        mBitmap.setPixels(colors, 60, 50, 10, 10, 50, 50);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testSetPixelsLastScanlineNegative() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: lastScanline less than 0
-        try{
-            mBitmap.setPixels(colors, 10, -50, 10, 10, 50, 50);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        mBitmap.setPixels(colors, 10, -50, 10, 10, 50, 50);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testSetPixelsLastScanlineTooBig() {
+        int[] colors = createColors(100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
         // abnormal case: (lastScanline + width) bigger than the length of colors
-        try{
-            mBitmap.setPixels(colors, 10, 50, 10, 10, 50, 50);
-            fail("shouldn't come to here");
-        }catch(ArrayIndexOutOfBoundsException e){
-        }
+        mBitmap.setPixels(colors, 10, 50, 10, 10, 50, 50);
+    }
 
-        // normal case
-        colors = createColors(100 * 100);
+    @Test
+    public void testSetPixels() {
+        int[] colors = createColors(100 * 100);
+        mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
         mBitmap.setPixels(colors, 0, 100, 0, 0, 100, 100);
         int[] ret = new int[100 * 100];
         mBitmap.getPixels(ret, 0, 100, 0, 0, 100, 100);
@@ -815,7 +841,7 @@
         }
     }
 
-    private void checkPremultipliedBitmapConfig(Config config, boolean expectedPremul) {
+    private void verifyPremultipliedBitmapConfig(Config config, boolean expectedPremul) {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, config);
         bitmap.setPremultiplied(true);
         bitmap.setPixel(0, 0, Color.TRANSPARENT);
@@ -825,13 +851,15 @@
         assertFalse(bitmap.isPremultiplied());
     }
 
+    @Test
     public void testSetPremultipliedSimple() {
-        checkPremultipliedBitmapConfig(Bitmap.Config.ALPHA_8, true);
-        checkPremultipliedBitmapConfig(Bitmap.Config.RGB_565, false);
-        checkPremultipliedBitmapConfig(Bitmap.Config.ARGB_4444, true);
-        checkPremultipliedBitmapConfig(Bitmap.Config.ARGB_8888, true);
+        verifyPremultipliedBitmapConfig(Bitmap.Config.ALPHA_8, true);
+        verifyPremultipliedBitmapConfig(Bitmap.Config.RGB_565, false);
+        verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_4444, true);
+        verifyPremultipliedBitmapConfig(Bitmap.Config.ARGB_8888, true);
     }
 
+    @Test
     public void testSetPremultipliedData() {
         // with premul, will store 2,2,2,2, so it doesn't get value correct
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@@ -853,6 +881,7 @@
         assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR);
     }
 
+    @Test
     public void testPremultipliedCanvas() {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         bitmap.setHasAlpha(true);
@@ -879,6 +908,7 @@
         bitmap.copyPixelsFromBuffer(buffer);
     }
 
+    @Test
     public void testSetPremultipliedToBuffer() {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         bitmap.setPixel(0, 0, PREMUL_COLOR);
@@ -891,6 +921,7 @@
         assertEquals(getBitmapRawInt(bitmap), storedPremul);
     }
 
+    @Test
     public void testSetPremultipliedFromBuffer() {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         bitmap.setPremultiplied(false);
@@ -903,6 +934,7 @@
         assertEquals(bitmap.getPixel(0, 0), PREMUL_COLOR);
     }
 
+    @Test
     public void testSetWidth() {
         mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
         int alloc = mBitmap.getAllocationByteCount();
@@ -911,42 +943,42 @@
         mBitmap.setWidth(50);
         assertEquals(mBitmap.getAllocationByteCount(), alloc);
         assertEquals(mBitmap.getByteCount() * 2, alloc);
-
-        // test expanding
-        try {
-            mBitmap.setWidth(101);
-            fail("shouldn't come to here");
-        } catch (IllegalArgumentException e) {
-        }
-
-        // test mutable
-        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
-        try {
-            mBitmap.setWidth(1);
-            fail("shouldn't come to here");
-        } catch (IllegalStateException e) {
-        }
     }
 
-    public void testWriteToParcel(){
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetWidthExpanding() {
+        // test expanding
+        mBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+
+        mBitmap.setWidth(101);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testSetWidthMutable() {
+        // test mutable
+        mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
+
+        mBitmap.setWidth(1);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testWriteToParcelRecycled() {
         mBitmap.recycle();
 
-        // abnormal case: the bitmap to be written has been recycled
-        try{
-            mBitmap.writeToParcel(null, 0);
-            fail("shouldn't come to here");
-        }catch(IllegalStateException e){
-        }
+        mBitmap.writeToParcel(null, 0);
+    }
 
+    @Test
+    public void testWriteToParcel() {
         // abnormal case: failed to unparcel Bitmap
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.start, mOptions);
         Parcel p = Parcel.obtain();
         mBitmap.writeToParcel(p, 0);
 
-        try{
+        try {
             Bitmap.CREATOR.createFromParcel(p);
             fail("shouldn't come to here");
-        }catch(RuntimeException e){
+        } catch(RuntimeException e){
         }
 
         // normal case
@@ -956,6 +988,7 @@
         mBitmap.equals(Bitmap.CREATOR.createFromParcel(p));
     }
 
+    @Test
     public void testGetScaledHeight1() {
         int dummyDensity = 5;
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
@@ -964,14 +997,16 @@
         assertEquals(scaledHeight, ret.getScaledHeight(dummyDensity));
     }
 
+    @Test
     public void testGetScaledHeight2() {
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
-        DisplayMetrics metrics = new DisplayMetrics();
-        metrics = getContext().getResources().getDisplayMetrics();
+        DisplayMetrics metrics =
+                InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
         int scaledHeight = scaleFromDensity(ret.getHeight(), ret.getDensity(), metrics.densityDpi);
         assertEquals(scaledHeight, ret.getScaledHeight(metrics));
     }
 
+    @Test
     public void testGetScaledHeight3() {
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
         Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
@@ -983,6 +1018,7 @@
         assertEquals(scaledHeight, ret.getScaledHeight(mCanvas));
     }
 
+    @Test
     public void testGetScaledWidth1() {
         int dummyDensity = 5;
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
@@ -991,14 +1027,16 @@
         assertEquals(scaledWidth, ret.getScaledWidth(dummyDensity));
     }
 
+    @Test
     public void testGetScaledWidth2() {
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
-        DisplayMetrics metrics = new DisplayMetrics();
-        metrics = getContext().getResources().getDisplayMetrics();
+        DisplayMetrics metrics =
+                InstrumentationRegistry.getTargetContext().getResources().getDisplayMetrics();
         int scaledWidth = scaleFromDensity(ret.getWidth(), ret.getDensity(), metrics.densityDpi);
         assertEquals(scaledWidth, ret.getScaledWidth(metrics));
     }
 
+    @Test
     public void testGetScaledWidth3() {
         Bitmap ret = Bitmap.createBitmap(100, 200, Config.RGB_565);
         Bitmap mMutableBitmap = Bitmap.createBitmap(100, 200, Config.ARGB_8888);
@@ -1009,7 +1047,7 @@
         assertEquals(scaledWidth, ret.getScaledWidth(mCanvas));
     }
 
-    private int scaleFromDensity(int size, int sdensity, int tdensity) {
+    private static int scaleFromDensity(int size, int sdensity, int tdensity) {
         if (sdensity == Bitmap.DENSITY_NONE || sdensity == tdensity) {
             return size;
         }
@@ -1018,7 +1056,7 @@
         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
     }
 
-    private int[] createColors(int size){
+    private static int[] createColors(int size) {
         int[] colors = new int[size];
 
         for (int i = 0; i < size; i++) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/Bitmap_CompressFormatTest.java b/tests/tests/graphics/src/android/graphics/cts/Bitmap_CompressFormatTest.java
index 8ae4133..30294d0 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Bitmap_CompressFormatTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Bitmap_CompressFormatTest.java
@@ -15,21 +15,31 @@
  */
 package android.graphics.cts;
 
-import java.io.ByteArrayOutputStream;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.Bitmap.Config;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Bitmap_CompressFormatTest extends AndroidTestCase{
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Bitmap_CompressFormatTest {
+    @Test
     public void testValueOf(){
         assertEquals(CompressFormat.JPEG, CompressFormat.valueOf("JPEG"));
         assertEquals(CompressFormat.PNG, CompressFormat.valueOf("PNG"));
         assertEquals(CompressFormat.WEBP, CompressFormat.valueOf("WEBP"));
     }
 
+    @Test
     public void testValues(){
         CompressFormat[] comFormat = CompressFormat.values();
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java b/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
index e097b5a..ebb7d6a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Bitmap_ConfigTest.java
@@ -15,12 +15,22 @@
  */
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Bitmap_ConfigTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Bitmap_ConfigTest {
+    @Test
     public void testValueOf(){
         assertEquals(Config.ALPHA_8, Config.valueOf("ALPHA_8"));
         assertEquals(Config.RGB_565, Config.valueOf("RGB_565"));
@@ -28,6 +38,7 @@
         assertEquals(Config.ARGB_8888, Config.valueOf("ARGB_8888"));
     }
 
+    @Test
     public void testValues(){
         Config[] config = Config.values();
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilterTest.java
index 23ac16b..b315bc9 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilterTest.java
@@ -15,26 +15,32 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
-import android.graphics.BlurMaskFilter.Blur;
-import android.util.Log;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class BlurMaskFilterTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BlurMaskFilterTest {
     private static final int OFFSET = 10;
     private static final int RADIUS = 5;
     private static final int BITMAP_WIDTH = 100;
     private static final int BITMAP_HEIGHT = 100;
     private static final int CENTER = BITMAP_HEIGHT / 2;
 
-    public void testBlurMaskFilter(){
+    @Test
+    public void testBlurMaskFilter() {
         BlurMaskFilter filter = new BlurMaskFilter(RADIUS, Blur.NORMAL);
         Paint paint = new Paint();
         paint.setMaskFilter(filter);
@@ -47,33 +53,29 @@
             for (int y = 0; y < CENTER; y++) {
                 if (x < CENTER - OFFSET - RADIUS || y < CENTER - OFFSET - RADIUS) {
                     // check that color didn't bleed (much) beyond radius
-                    checkQuadrants(Color.TRANSPARENT, b, x, y, 5);
+                    verifyQuadrants(Color.TRANSPARENT, b, x, y, 5);
                 } else if (x > CENTER - OFFSET + RADIUS && y > CENTER - OFFSET + RADIUS) {
                     // check that color didn't wash out (much) in the center
-                    checkQuadrants(Color.RED, b, x, y, 5);
+                    verifyQuadrants(Color.RED, b, x, y, 5);
                 } else {
                     // check blur zone, color should remain, alpha varies
-                    checkQuadrants(Color.RED, b, x, y, 255);
+                    verifyQuadrants(Color.RED, b, x, y, 255);
                 }
             }
         }
     }
 
-    private void checkQuadrants(int color, Bitmap bitmap, int x, int y, int alphaTolerance) {
+    private void verifyQuadrants(int color, Bitmap bitmap, int x, int y, int alphaTolerance) {
         int right = bitmap.getWidth() - 1;
         int bottom = bitmap.getHeight() - 1;
-        try {
-            checkColor(color, bitmap.getPixel(x, y), alphaTolerance);
-            checkColor(color, bitmap.getPixel(right - x, y), alphaTolerance);
-            checkColor(color, bitmap.getPixel(x, bottom - y), alphaTolerance);
-            checkColor(color, bitmap.getPixel(right - x, bottom - y), alphaTolerance);
-        } catch (Error e) {
-            Log.w(getClass().getName(), "Failed for coordinates (" + x + ", " + y + ")");
-            throw e;
-        }
+
+        verifyColor(color, bitmap.getPixel(x, y), alphaTolerance);
+        verifyColor(color, bitmap.getPixel(right - x, y), alphaTolerance);
+        verifyColor(color, bitmap.getPixel(x, bottom - y), alphaTolerance);
+        verifyColor(color, bitmap.getPixel(right - x, bottom - y), alphaTolerance);
     }
 
-    private void checkColor(int expected, int actual, int alphaTolerance) {
+    private void verifyColor(int expected, int actual, int alphaTolerance) {
         assertEquals(Color.red(expected), Color.red(actual));
         assertEquals(Color.green(expected), Color.green(actual));
         assertEquals(Color.blue(expected), Color.blue(actual));
diff --git a/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilter_BlurTest.java b/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilter_BlurTest.java
index 77d2ffa..bdc44af 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilter_BlurTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BlurMaskFilter_BlurTest.java
@@ -15,12 +15,21 @@
  */
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 import android.graphics.BlurMaskFilter;
 import android.graphics.BlurMaskFilter.Blur;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class BlurMaskFilter_BlurTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BlurMaskFilter_BlurTest {
+    @Test
     public void testValueOf(){
         assertEquals(Blur.NORMAL, Blur.valueOf("NORMAL"));
         assertEquals(Blur.SOLID, Blur.valueOf("SOLID"));
@@ -28,14 +37,15 @@
         assertEquals(Blur.INNER, Blur.valueOf("INNER"));
     }
 
+    @Test
     public void testValues(){
-        Blur[] bulr = Blur.values();
+        Blur[] blur = Blur.values();
 
-        assertEquals(4, bulr.length);
-        assertEquals(Blur.NORMAL, bulr[0]);
-        assertEquals(Blur.SOLID, bulr[1]);
-        assertEquals(Blur.OUTER, bulr[2]);
-        assertEquals(Blur.INNER, bulr[3]);
+        assertEquals(4, blur.length);
+        assertEquals(Blur.NORMAL, blur[0]);
+        assertEquals(Blur.SOLID, blur[1]);
+        assertEquals(Blur.OUTER, blur[2]);
+        assertEquals(Blur.INNER, blur[3]);
 
         //Blur is used as a argument here for all the methods that use it
         assertNotNull(new BlurMaskFilter(10.24f, Blur.INNER));
diff --git a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
index a28d6ff..8991e0d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CameraTest.java
@@ -15,33 +15,57 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
 import android.graphics.Camera;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class CameraTest extends AndroidTestCase {
+import com.android.compatibility.common.util.CtsArrayUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CameraTest {
     private Camera mCamera;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mCamera = new Camera();
     }
 
-    public void testCamera(){
+    @Test
+    public void testCamera() {
         new Camera();
     }
 
+    @Test
     public void testRestore() {
         // we cannot get the state changed because it was a native method
         mCamera.save();
         mCamera.restore();
     }
 
+    @Test
+    public void testMatrixPreCompare() {
+        Matrix m = new Matrix();
+        mCamera.getMatrix(m);
+        float[] f = new float[9];
+        m.getValues(f);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, f, 0.0f);
+    }
+
+    @Test
     public void testTranslate() {
         Matrix m1 = new Matrix();
-        preCompare(m1);
 
         mCamera.translate(10.0f, 28.0f, 2008.0f);
         Matrix m2 = new Matrix();
@@ -50,20 +74,14 @@
 
         float[] f = new float[9];
         m2.getValues(f);
-        assertEquals(0.22291021f, f[0]);
-        assertEquals(0.0f, f[1]);
-        assertEquals(2.2291021f, f[2]);
-        assertEquals(0.0f, f[3]);
-        assertEquals(0.22291021f, f[4]);
-        assertEquals(-6.241486f, f[5]);
-        assertEquals(0.0f, f[6]);
-        assertEquals(0.0f, f[7]);
-        assertEquals(1.0f, f[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.22291021f, 0.0f, 2.2291021f, 0.0f, 0.22291021f, -6.241486f, 0.0f, 0.0f, 1.0f
+        }, f, 0.0f);
     }
 
+    @Test
     public void testRotateX() {
         Matrix m1 = new Matrix();
-        preCompare(m1);
 
         mCamera.rotateX(90.0f);
         Matrix m2 = new Matrix();
@@ -72,20 +90,14 @@
 
         float[] f = new float[9];
         m2.getValues(f);
-        assertEquals(1.0f, f[0]);
-        assertEquals(0.0f, f[1]);
-        assertEquals(0.0f, f[2]);
-        assertEquals(0.0f, f[3]);
-        assertEquals(0.0f, f[4]);
-        assertEquals(0.0f, f[5]);
-        assertEquals(0.0f, f[6]);
-        assertEquals(-0.0017361111f, f[7]);
-        assertEquals(1.0f, f[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.0017361111f, 1.0f
+        }, f, 0.0f);
     }
 
+    @Test
     public void testRotateY() {
         Matrix m1 = new Matrix();
-        preCompare(m1);
 
         mCamera.rotateY(90.0f);
         Matrix m2 = new Matrix();
@@ -94,20 +106,14 @@
 
         float[] f = new float[9];
         m2.getValues(f);
-        assertEquals(0.0f, f[0]);
-        assertEquals(0.0f, f[1]);
-        assertEquals(0.0f, f[2]);
-        assertEquals(0.0f, f[3]);
-        assertEquals(1.0f, f[4]);
-        assertEquals(0.0f, f[5]);
-        assertEquals(0.0017361111f, f[6]);
-        assertEquals(0.0f, f[7]);
-        assertEquals(1.0f, f[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0017361111f, 0.0f, 1.0f
+        }, f, 0.0f);
     }
 
+    @Test
     public void testRotateZ() {
         Matrix m1 = new Matrix();
-        preCompare(m1);
 
         mCamera.rotateZ(90.0f);
         Matrix m2 = new Matrix();
@@ -116,17 +122,37 @@
 
         float[] f = new float[9];
         m2.getValues(f);
-        assertEquals(0.0f, f[0]);
-        assertEquals(1.0f, f[1]);
-        assertEquals(0.0f, f[2]);
-        assertEquals(-1.0f, f[3]);
-        assertEquals(0.0f, f[4]);
-        assertEquals(0.0f, f[5]);
-        assertEquals(0.0f, f[6]);
-        assertEquals(0.0f, f[7]);
-        assertEquals(1.0f, f[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, f, 0.0f);
     }
 
+    @Test
+    public void testRotate() {
+        Matrix m1 = new Matrix();
+
+        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);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.6123724f, 0.6123724f, 0.0f, -0.5915063f, 0.774519f, 0.0f, 0.0009106233f,
+                0.00027516257f, 1.0f
+        }, f, 0.0f);
+    }
+
+    @Test
+    public void testLocationAccessors() {
+        mCamera.setLocation(10.0f, 20.0f, 30.0f);
+        assertEquals(10.0f, mCamera.getLocationX(), 0.0f);
+        assertEquals(20.0f, mCamera.getLocationY(), 0.0f);
+        assertEquals(30.0f, mCamera.getLocationZ(), 0.0f);
+    }
+
+    @Test
     public void testApplyToCanvas() {
         Canvas c1 = new Canvas();
         mCamera.applyToCanvas(c1);
@@ -136,26 +162,11 @@
         mCamera.getMatrix(m);
         c2.concat(m);
 
-        assertTrue(c1.getMatrix().equals(c2.getMatrix()));
+        assertEquals(c1.getMatrix(), c2.getMatrix());
     }
 
+    @Test
     public void testDotWithNormal() {
-        assertEquals(0.0792f, mCamera.dotWithNormal(0.1f, 0.28f, 0.2008f));
+        assertEquals(0.0792f, mCamera.dotWithNormal(0.1f, 0.28f, 0.2008f), 0.0f);
     }
-
-    private void preCompare(Matrix m) {
-        mCamera.getMatrix(m);
-        float[] f = new float[9];
-        m.getValues(f);
-        assertEquals(1.0f, f[0]);
-        assertEquals(0.0f, f[1]);
-        assertEquals(0.0f, f[2]);
-        assertEquals(0.0f, f[3]);
-        assertEquals(1.0f, f[4]);
-        assertEquals(0.0f, f[5]);
-        assertEquals(0.0f, f[6]);
-        assertEquals(0.0f, f[7]);
-        assertEquals(1.0f, f[8]);
-    }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index dee217b..1a3bd3d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -15,37 +15,49 @@
  */
 package android.graphics.cts;
 
-import javax.microedition.khronos.opengles.GL;
+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 android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
-import android.util.DisplayMetrics;
+import android.graphics.Canvas.EdgeType;
+import android.graphics.Canvas.VertexMode;
+import android.graphics.Color;
 import android.graphics.DrawFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.Path.Direction;
 import android.graphics.Picture;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas.EdgeType;
-import android.graphics.Canvas.VertexMode;
-import android.graphics.Path.Direction;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Region.Op;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.SpannedString;
+import android.util.DisplayMetrics;
 
-import android.graphics.cts.R;
+import com.android.compatibility.common.util.CtsArrayUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Vector;
 
-public class CanvasTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CanvasTest {
     private final static int PAINT_COLOR = 0xff00ff00;
     private final static int BITMAP_WIDTH = 10;
     private final static int BITMAP_HEIGHT = 28;
@@ -69,14 +81,12 @@
     private Bitmap mImmutableBitmap;
     private Bitmap mMutableBitmap;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setup() {
         mPaint = new Paint();
         mPaint.setColor(PAINT_COLOR);
 
-        final Resources res = getInstrumentation().getTargetContext().getResources();
+        final Resources res = InstrumentationRegistry.getTargetContext().getResources();
         BitmapFactory.Options opt = new BitmapFactory.Options();
         opt.inScaled = false; // bitmap will only be immutable if not scaled during load
         mImmutableBitmap = BitmapFactory.decodeResource(res, R.drawable.start, opt);
@@ -85,77 +95,67 @@
         mCanvas = new Canvas(mMutableBitmap);
     }
 
-    public void testCanvas1() {
-        final Canvas c = new Canvas();
-    }
-
-    public void testCanvas2() {
-        // abnormal case: bitmap to be constructed is immutable
-        try {
-            new Canvas(mImmutableBitmap);
-            fail("should throw out IllegalStateException when creating Canvas with an ImmutableBitmap");
-        } catch (IllegalStateException e) {
-            // expected
-        }
-
-        // abnormal case: bitmap to be constructed is recycled
-        mMutableBitmap.recycle();
-        try {
-            new Canvas(mMutableBitmap);
-            fail("should throw out RuntimeException when creating Canvas with a"
-                     + " MutableBitmap which is recycled");
-        } catch (RuntimeException e) {
-            // expected
-        }
+    @Test
+    public void testCanvas() {
+        new Canvas();
 
         mMutableBitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
         new Canvas(mMutableBitmap);
     }
 
-    public void testSetBitmap() {
-        // abnormal case: bitmap to be set is immutable
-        try {
-            mCanvas.setBitmap(mImmutableBitmap);
-            fail("should throw out IllegalStateException when setting an "
-                    + "ImmutableBitmap to a Canvas");
-        } catch (IllegalStateException e) {
-            // expected
-        }
+    @Test(expected=IllegalStateException.class)
+    public void testCanvasFromImmutableBitmap() {
+        // Should throw out IllegalStateException when creating Canvas with an ImmutableBitmap
+        new Canvas(mImmutableBitmap);
+    }
 
-        // abnormal case: bitmap to be set has been recycled
+    @Test(expected=RuntimeException.class)
+    public void testCanvasFromRecycledBitmap() {
+        // Should throw out RuntimeException when creating Canvas with a MutableBitmap which
+        // is recycled
         mMutableBitmap.recycle();
-        try {
-            mCanvas.setBitmap(mMutableBitmap);
-            fail("should throw out RuntimeException when setting Bitmap which is recycled"
-                          + " to a Canvas");
-        } catch (RuntimeException e) {
-            // expected
-        }
+        new Canvas(mMutableBitmap);
+    }
 
+    @Test(expected=IllegalStateException.class)
+    public void testSetBitmapToImmutableBitmap() {
+        // Should throw out IllegalStateException when setting an ImmutableBitmap to a Canvas
+        mCanvas.setBitmap(mImmutableBitmap);
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testSetBitmapToRecycledBitmap() {
+        // Should throw out RuntimeException when setting Bitmap which is recycled to a Canvas
+        mMutableBitmap.recycle();
+        mCanvas.setBitmap(mMutableBitmap);
+    }
+
+    @Test
+    public void testSetBitmap() {
         mMutableBitmap = Bitmap.createBitmap(BITMAP_WIDTH, 31, Config.ARGB_8888);
         mCanvas.setBitmap(mMutableBitmap);
         assertEquals(BITMAP_WIDTH, mCanvas.getWidth());
         assertEquals(31, mCanvas.getHeight());
     }
 
+    @Test
     public void testIsOpaque() {
         assertFalse(mCanvas.isOpaque());
     }
 
-    public void testRestore() {
-        // abnormal case: save not called before restore
-        try {
-            mCanvas.restore();
-            fail("should throw out IllegalStateException because cannot restore Canvas"
-                            + " before save");
-        } catch (IllegalStateException e) {
-            // expected
-        }
+    @Test(expected=IllegalStateException.class)
+    public void testRestoreWithoutSave() {
+        // Should throw out IllegalStateException because cannot restore Canvas before save
+        mCanvas.restore();
+    }
 
+    @Test
+    public void testRestore() {
         mCanvas.save();
         mCanvas.restore();
     }
 
+    @Test
     public void testSave1() {
         final Matrix m1 = new Matrix();
         m1.setValues(values1);
@@ -170,20 +170,17 @@
         final Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         final float[] values4 = new float[FLOAT_ARRAY_LEN];
         final Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testSave2() {
         // test save current matrix only
         Matrix m1 = new Matrix();
@@ -199,18 +196,14 @@
         Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         float[] values4 = new float[FLOAT_ARRAY_LEN];
         Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
 
         // test save current clip only, don't know how to get clip saved,
         // but can make sure Matrix can't be saved in this case
@@ -227,18 +220,14 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values4, 0.0f);
 
         // test save everything
         m1 = new Matrix();
@@ -254,20 +243,17 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testSaveFlags1() {
         int[] flags = {
             Canvas.MATRIX_SAVE_FLAG,
@@ -275,6 +261,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags2() {
         int[] flags = {
             Canvas.CLIP_SAVE_FLAG,
@@ -282,6 +269,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags3() {
         int[] flags = {
             Canvas.ALL_SAVE_FLAG,
@@ -291,6 +279,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags4() {
         int[] flags = {
             Canvas.ALL_SAVE_FLAG,
@@ -300,6 +289,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags5() {
         int[] flags = {
             Canvas.MATRIX_SAVE_FLAG,
@@ -312,6 +302,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags6() {
         int[] flags = {
             Canvas.CLIP_SAVE_FLAG,
@@ -324,6 +315,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags7() {
         int[] flags = {
             Canvas.MATRIX_SAVE_FLAG,
@@ -336,6 +328,7 @@
         verifySaveFlagsSequence(flags);
     }
 
+    @Test
     public void testSaveFlags8() {
         int[] flags = {
             Canvas.MATRIX_SAVE_FLAG,
@@ -352,6 +345,7 @@
     // state across the matching restore call boundary. This is a vanilla
     // test and doesn't exercise any interaction between the clip stack
     // and SkCanvas' deferred save/restore system.
+    @Test
     public void testSaveFlags9() {
         Rect clip0 = new Rect();
         assertTrue(mCanvas.getClipBounds(clip0));
@@ -382,6 +376,7 @@
     // This test exercises the saveLayer MATRIX_SAVE_FLAG flag and its
     // interaction with the clip stack and SkCanvas deferred save/restore
     // system.
+    @Test
     public void testSaveFlags10() {
         RectF rect1 = new RectF(0, 0, BITMAP_WIDTH / 2, BITMAP_HEIGHT);
         RectF rect2 = new RectF(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT / 2);
@@ -459,6 +454,7 @@
         assertEquals(clip9, clip0);
     }
 
+    @Test
     public void testSaveLayer1() {
         final Paint p = new Paint();
         final RectF rF = new RectF(0, 10, 31, 0);
@@ -477,18 +473,14 @@
         Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         float[] values4 = new float[FLOAT_ARRAY_LEN];
         Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
 
         // test save current clip only, don't know how to get clip saved,
         // but can make sure Matrix can't be saved in this case
@@ -505,18 +497,14 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values4, 0.0f);
 
         // test save everything
         m1 = new Matrix();
@@ -532,20 +520,17 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testSaveLayer2() {
         final Paint p = new Paint();
 
@@ -563,18 +548,14 @@
         Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         float[] values4 = new float[FLOAT_ARRAY_LEN];
         Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
 
         // test save current clip only, don't know how to get clip saved,
         // but can make sure Matrix can't be saved in this case
@@ -591,18 +572,14 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values4, 0.0f);
 
         // test save everything
         m1 = new Matrix();
@@ -618,20 +595,17 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testSaveLayerAlpha1() {
         final RectF rF = new RectF(0, 10, 31, 0);
 
@@ -649,18 +623,14 @@
         Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         float[] values4 = new float[FLOAT_ARRAY_LEN];
         Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
 
         // test save current clip only, don't know how to get clip saved,
         // but can make sure Matrix can't be saved in this case
@@ -677,18 +647,14 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values4, 0.0f);
 
         // test save everything
         m1 = new Matrix();
@@ -704,20 +670,17 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testSaveLayerAlpha2() {
         // test save current matrix only
         Matrix m1 = new Matrix();
@@ -733,18 +696,14 @@
         Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         float[] values4 = new float[FLOAT_ARRAY_LEN];
         Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
 
         // test save current clip only, don't know how to get clip saved,
         // but can make sure Matrix can't be saved in this case
@@ -761,18 +720,14 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values4, 0.0f);
 
         // test save everything
         m1 = new Matrix();
@@ -788,20 +743,17 @@
         m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restore();
         values4 = new float[FLOAT_ARRAY_LEN];
         m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testGetSaveCount() {
         // why is 1 not 0
         assertEquals(1, mCanvas.getSaveCount());
@@ -815,15 +767,14 @@
         assertEquals(5, mCanvas.getSaveCount());
     }
 
-    public void testRestoreToCount() {
-        // abnormal case: saveCount less than 1
-        try {
-            mCanvas.restoreToCount(0);
-            fail("should throw out IllegalArgumentException because saveCount is less than 1");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testRestoreToCountIllegalSaveCount() {
+        // Should throw out IllegalArgumentException because saveCount is less than 1
+        mCanvas.restoreToCount(0);
+    }
 
+    @Test
+    public void testRestoreToCount() {
         final Matrix m1 = new Matrix();
         m1.setValues(values1);
         mCanvas.setMatrix(m1);
@@ -838,20 +789,17 @@
         final Matrix m3 = mCanvas.getMatrix();
         m3.getValues(values3);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values2[i], values3[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values2, values3, 0.0f);
 
         mCanvas.restoreToCount(count);
         final float[] values4 = new float[FLOAT_ARRAY_LEN];
         final Matrix m4 = mCanvas.getMatrix();
         m4.getValues(values4);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(values1[i], values4[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(values1, values4, 0.0f);
     }
 
+    @Test
     public void testGetMatrix1() {
         final float[] f1 = {
                 1, 2, 3, 4, 5, 6, 7, 8, 9
@@ -868,11 +816,10 @@
         final float[] f2 = new float[FLOAT_ARRAY_LEN];
         m2.getValues(f2);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(f1[i], f2[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(f1, f2, 0.0f);
     }
 
+    @Test
     public void testGetMatrix2() {
         final float[] f1 = {
                 1, 2, 3, 4, 5, 6, 7, 8, 9
@@ -888,11 +835,10 @@
         final float[] f2 = new float[FLOAT_ARRAY_LEN];
         m2.getValues(f2);
 
-        for (int i = 0; i < FLOAT_ARRAY_LEN; i++) {
-            assertEquals(f1[i], f2[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(f1, f2, 0.0f);
     }
 
+    @Test
     public void testTranslate() {
         preCompare();
 
@@ -900,17 +846,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(1.0f, values[0]);
-        assertEquals(0.0f, values[1]);
-        assertEquals(0.1f, values[2]);
-        assertEquals(0.0f, values[3]);
-        assertEquals(1.0f, values[4]);
-        assertEquals(0.28f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+            1.0f, 0.0f, 0.1f, 0.0f, 1.0f, 0.28f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testScale1() {
         preCompare();
 
@@ -918,17 +859,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(0.5f, values[0]);
-        assertEquals(0.0f, values[1]);
-        assertEquals(0.0f, values[2]);
-        assertEquals(0.0f, values[3]);
-        assertEquals(0.5f, values[4]);
-        assertEquals(0.0f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testScale2() {
         preCompare();
 
@@ -936,17 +872,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(3.0f, values[0]);
-        assertEquals(0.0f, values[1]);
-        assertEquals(-2.0f, values[2]);
-        assertEquals(0.0f, values[3]);
-        assertEquals(3.0f, values[4]);
-        assertEquals(-2.0f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                3.0f, 0.0f, -2.0f, 0.0f, 3.0f, -2.0f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testRotate1() {
         preCompare();
 
@@ -954,17 +885,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(0.0f, values[0]);
-        assertEquals(-1.0f, values[1]);
-        assertEquals(0.0f, values[2]);
-        assertEquals(1.0f, values[3]);
-        assertEquals(0.0f, values[4]);
-        assertEquals(0.0f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testRotate2() {
         preCompare();
 
@@ -972,17 +898,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(0.8660254f, values[0]);
-        assertEquals(-0.5f, values[1]);
-        assertEquals(0.13397461f, values[2]);
-        assertEquals(0.5f, values[3]);
-        assertEquals(0.8660254f, values[4]);
-        assertEquals(-0.5f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.8660254f, -0.5f, 0.13397461f, 0.5f, 0.8660254f, -0.5f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testSkew() {
         preCompare();
 
@@ -990,17 +911,12 @@
 
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(1.0f, values[0]);
-        assertEquals(1.0f, values[1]);
-        assertEquals(0.0f, values[2]);
-        assertEquals(3.0f, values[3]);
-        assertEquals(1.0f, values[4]);
-        assertEquals(0.0f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                1.0f, 1.0f, 0.0f, 3.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testConcat() {
         preCompare();
 
@@ -1011,17 +927,12 @@
         mCanvas.concat(m);
 
         mCanvas.getMatrix().getValues(values);
-        assertEquals(0.0f, values[0]);
-        assertEquals(1.0f, values[1]);
-        assertEquals(2.0f, values[2]);
-        assertEquals(3.0f, values[3]);
-        assertEquals(4.0f, values[4]);
-        assertEquals(5.0f, values[5]);
-        assertEquals(6.0f, values[6]);
-        assertEquals(7.0f, values[7]);
-        assertEquals(8.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f
+        }, values, 0.0f);
     }
 
+    @Test
     public void testClipRect1() {
         assertFalse(mCanvas.clipRect(mRectF, Op.DIFFERENCE));
         assertFalse(mCanvas.clipRect(mRectF, Op.INTERSECT));
@@ -1031,6 +942,7 @@
         assertFalse(mCanvas.clipRect(mRectF, Op.XOR));
     }
 
+    @Test
     public void testClipRect2() {
         assertFalse(mCanvas.clipRect(mRect, Op.DIFFERENCE));
         assertFalse(mCanvas.clipRect(mRect, Op.INTERSECT));
@@ -1040,14 +952,17 @@
         assertFalse(mCanvas.clipRect(mRect, Op.XOR));
     }
 
+    @Test
     public void testClipRect3() {
         assertTrue(mCanvas.clipRect(mRectF));
     }
 
+    @Test
     public void testClipRect4() {
         assertTrue(mCanvas.clipRect(mRect));
     }
 
+    @Test
     public void testClipRect5() {
         assertFalse(mCanvas.clipRect(0, 0, 10, 31, Op.DIFFERENCE));
         assertFalse(mCanvas.clipRect(0, 0, 10, 31, Op.INTERSECT));
@@ -1057,20 +972,24 @@
         assertFalse(mCanvas.clipRect(0, 0, 10, 31, Op.XOR));
     }
 
+    @Test
     public void testClipRect6() {
         assertTrue(mCanvas.clipRect(0.5f, 0.5f, 10.5f, 31.5f));
     }
 
+    @Test
     public void testClipRect7() {
         assertTrue(mCanvas.clipRect(0, 0, 10, 31));
     }
 
+    @Test
     public void testClipPath1() {
         final Path p = new Path();
         p.addRect(mRectF, Direction.CCW);
         assertTrue(mCanvas.clipPath(p));
     }
 
+    @Test
     public void testClipPath2() {
         final Path p = new Path();
         p.addRect(mRectF, Direction.CCW);
@@ -1083,10 +1002,12 @@
         assertFalse(mCanvas.clipPath(p, Op.XOR));
     }
 
+    @Test
     public void testClipRegion1() {
         assertFalse(mCanvas.clipRegion(new Region(0, 10, 29, 0)));
     }
 
+    @Test
     public void testClipRegion2() {
         final Region r = new Region(0, 10, 29, 0);
 
@@ -1098,6 +1019,7 @@
         assertFalse(mCanvas.clipRegion(r, Op.XOR));
     }
 
+    @Test
     public void testClipRegion3() {
         assertTrue(mCanvas.clipRegion(new Region(0, 0, 10, 10)));
         final Rect clip = mCanvas.getClipBounds();
@@ -1107,6 +1029,7 @@
         assertEquals(10, clip.bottom);
     }
 
+    @Test
     public void testClipRegion4() {
         mCanvas.translate(10, 10);
         mCanvas.scale(2, 2);
@@ -1122,6 +1045,7 @@
         assertEquals(0, clip.bottom);
     }
 
+    @Test
     public void testGetDrawFilter() {
         assertNull(mCanvas.getDrawFilter());
         final DrawFilter dF = new DrawFilter();
@@ -1130,11 +1054,13 @@
         assertTrue(dF.equals(mCanvas.getDrawFilter()));
     }
 
+    @Test
     public void testQuickReject1() {
         assertFalse(mCanvas.quickReject(mRectF, EdgeType.AA));
         assertFalse(mCanvas.quickReject(mRectF, EdgeType.BW));
     }
 
+    @Test
     public void testQuickReject2() {
         final Path p = new Path();
         p.addRect(mRectF, Direction.CCW);
@@ -1143,11 +1069,13 @@
         assertFalse(mCanvas.quickReject(p, EdgeType.BW));
     }
 
+    @Test
     public void testQuickReject3() {
         assertFalse(mCanvas.quickReject(0, 0, 10, 31, EdgeType.AA));
         assertFalse(mCanvas.quickReject(0, 0, 10, 31, EdgeType.BW));
     }
 
+    @Test
     public void testGetClipBounds1() {
         final Rect r = new Rect();
 
@@ -1156,6 +1084,7 @@
         assertEquals(BITMAP_HEIGHT, r.height());
     }
 
+    @Test
     public void testGetClipBounds2() {
         final Rect r = mCanvas.getClipBounds();
 
@@ -1163,12 +1092,13 @@
         assertEquals(BITMAP_HEIGHT, r.height());
     }
 
-    private void checkDrewColor(int color) {
+    private void verifyDrewColor(int color) {
         assertEquals(color, mMutableBitmap.getPixel(0, 0));
         assertEquals(color, mMutableBitmap.getPixel(BITMAP_WIDTH / 2, BITMAP_HEIGHT / 2));
         assertEquals(color, mMutableBitmap.getPixel(BITMAP_WIDTH - 1, BITMAP_HEIGHT - 1));
     }
 
+    @Test
     public void testDrawRGB() {
         final int alpha = 0xff;
         final int red = 0xff;
@@ -1178,9 +1108,10 @@
         mCanvas.drawRGB(red, green, blue);
 
         final int color = alpha << 24 | red << 16 | green << 8 | blue;
-        checkDrewColor(color);
+        verifyDrewColor(color);
     }
 
+    @Test
     public void testDrawARGB() {
         final int alpha = 0xff;
         final int red = 0x22;
@@ -1189,62 +1120,62 @@
 
         mCanvas.drawARGB(alpha, red, green, blue);
         final int color = alpha << 24 | red << 16 | green << 8 | blue;
-        checkDrewColor(color);
+        verifyDrewColor(color);
     }
 
+    @Test
     public void testDrawColor1() {
-        final int color = 0xffff0000;
+        final int color = Color.RED;
 
         mCanvas.drawColor(color);
-        checkDrewColor(color);
+        verifyDrewColor(color);
     }
 
+    @Test
     public void testDrawColor2() {
-        mCanvas.drawColor(0xffff0000, Mode.CLEAR);
-        mCanvas.drawColor(0xffff0000, Mode.DARKEN);
-        mCanvas.drawColor(0xffff0000, Mode.DST);
-        mCanvas.drawColor(0xffff0000, Mode.DST_ATOP);
-        mCanvas.drawColor(0xffff0000, Mode.DST_IN);
-        mCanvas.drawColor(0xffff0000, Mode.DST_OUT);
-        mCanvas.drawColor(0xffff0000, Mode.DST_OVER);
-        mCanvas.drawColor(0xffff0000, Mode.LIGHTEN);
-        mCanvas.drawColor(0xffff0000, Mode.MULTIPLY);
-        mCanvas.drawColor(0xffff0000, Mode.SCREEN);
-        mCanvas.drawColor(0xffff0000, Mode.SRC);
-        mCanvas.drawColor(0xffff0000, Mode.SRC_ATOP);
-        mCanvas.drawColor(0xffff0000, Mode.SRC_IN);
-        mCanvas.drawColor(0xffff0000, Mode.SRC_OUT);
-        mCanvas.drawColor(0xffff0000, Mode.SRC_OVER);
-        mCanvas.drawColor(0xffff0000, Mode.XOR);
+        mCanvas.drawColor(Color.RED, Mode.CLEAR);
+        mCanvas.drawColor(Color.RED, Mode.DARKEN);
+        mCanvas.drawColor(Color.RED, Mode.DST);
+        mCanvas.drawColor(Color.RED, Mode.DST_ATOP);
+        mCanvas.drawColor(Color.RED, Mode.DST_IN);
+        mCanvas.drawColor(Color.RED, Mode.DST_OUT);
+        mCanvas.drawColor(Color.RED, Mode.DST_OVER);
+        mCanvas.drawColor(Color.RED, Mode.LIGHTEN);
+        mCanvas.drawColor(Color.RED, Mode.MULTIPLY);
+        mCanvas.drawColor(Color.RED, Mode.SCREEN);
+        mCanvas.drawColor(Color.RED, Mode.SRC);
+        mCanvas.drawColor(Color.RED, Mode.SRC_ATOP);
+        mCanvas.drawColor(Color.RED, Mode.SRC_IN);
+        mCanvas.drawColor(Color.RED, Mode.SRC_OUT);
+        mCanvas.drawColor(Color.RED, Mode.SRC_OVER);
+        mCanvas.drawColor(Color.RED, Mode.XOR);
     }
 
+    @Test
     public void testDrawPaint() {
         mCanvas.drawPaint(mPaint);
 
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawPointsInvalidOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because of invalid offset
+        mCanvas.drawPoints(new float[]{
+                10.0f, 29.0f
+        }, -1, 2, mPaint);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawPointsInvalidCount() {
+        // Should throw out ArrayIndexOutOfBoundsException because of invalid count
+        mCanvas.drawPoints(new float[]{
+                10.0f, 29.0f
+        }, 0, 31, mPaint);
+    }
+
+    @Test
     public void testDrawPoints1() {
-        // abnormal case: invalid offset
-        try {
-            mCanvas.drawPoints(new float[] {
-                    10.0f, 29.0f
-            }, -1, 2, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because of invalid offset");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: invalid count
-        try {
-            mCanvas.drawPoints(new float[] {
-                    10.0f, 29.0f
-            }, 0, 31, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because of invalid count");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
         // normal case
         mCanvas.drawPoints(new float[] {
                 0, 0
@@ -1253,45 +1184,45 @@
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test
     public void testDrawPoints2() {
         mCanvas.drawPoints(new float[]{0, 0}, mPaint);
 
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test
     public void testDrawPoint() {
         mCanvas.drawPoint(0, 0, mPaint);
 
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test
     public void testDrawLine() {
         mCanvas.drawLine(0, 0, 10, 12, mPaint);
 
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawLinesInvalidOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because of invalid offset
+        mCanvas.drawLines(new float[]{
+                0, 0, 10, 31
+        }, 2, 4, new Paint());
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawLinesInvalidCount() {
+        // Should throw out ArrayIndexOutOfBoundsException because of invalid count
+        mCanvas.drawLines(new float[]{
+                0, 0, 10, 31
+        }, 0, 8, new Paint());
+    }
+
+    @Test
     public void testDrawLines1() {
-        // abnormal case: invalid offset
-        try {
-            mCanvas.drawLines(new float[] {
-                    0, 0, 10, 31
-            }, 2, 4, new Paint());
-            fail("should throw out ArrayIndexOutOfBoundsException because of invalid offset");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: invalid count
-        try {
-            mCanvas.drawLines(new float[] {
-                    0, 0, 10, 31
-            }, 0, 8, new Paint());
-            fail("should throw out ArrayIndexOutOfBoundsException because of invalid count");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
         // normal case
         mCanvas.drawLines(new float[] {
                 0, 0, 10, 12
@@ -1300,6 +1231,7 @@
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
+    @Test
     public void testDrawLines2() {
         mCanvas.drawLines(new float[] {
                 0, 0, 10, 12
@@ -1308,43 +1240,46 @@
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
     }
 
-    private void checkDrewPaint() {
+    private void verifyDrewPaint() {
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 0));
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(5, 6));
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(9, 11));
     }
 
+    @Test
     public void testDrawRect1() {
         mCanvas.drawRect(new RectF(0, 0, 10, 12), mPaint);
 
-        checkDrewPaint();
+        verifyDrewPaint();
     }
 
+    @Test
     public void testDrawRect2() {
         mCanvas.drawRect(new Rect(0, 0, 10, 12), mPaint);
 
-        checkDrewPaint();
+        verifyDrewPaint();
     }
 
+    @Test
     public void testDrawRect3() {
         mCanvas.drawRect(0, 0, 10, 12, mPaint);
 
-        checkDrewPaint();
+        verifyDrewPaint();
     }
 
-    public void testDrawOval() {
-        // abnormal case: Oval is null
-        try {
-            mCanvas.drawOval(null, mPaint);
-            fail("should throw out NullPointerException because oval is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+    @Test(expected=NullPointerException.class)
+    public void testDrawOvalNull() {
+        // Should throw out NullPointerException because oval is null
+        mCanvas.drawOval(null, mPaint);
+    }
 
+    @Test
+    public void testDrawOval() {
         // normal case
         mCanvas.drawOval(new RectF(0, 0, 10, 12), mPaint);
     }
 
+    @Test
     public void testDrawCircle() {
         // special case: circle's radius <= 0
         mCanvas.drawCircle(10.0f, 10.0f, -1.0f, mPaint);
@@ -1355,132 +1290,119 @@
         assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(9, 11));
     }
 
-    public void testDrawArc() {
-        // abnormal case: oval is null
-        try {
-            mCanvas.drawArc(null, 10.0f, 29.0f, true, mPaint);
-            fail("should throw NullPointerException because oval is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+    @Test(expected=NullPointerException.class)
+    public void testDrawArcNullOval() {
+        // Should throw NullPointerException because oval is null
+        mCanvas.drawArc(null, 10.0f, 29.0f, true, mPaint);
+    }
 
+    @Test
+    public void testDrawArc() {
         // normal case
         mCanvas.drawArc(new RectF(0, 0, 10, 12), 10, 11, false, mPaint);
         mCanvas.drawArc(new RectF(0, 0, 10, 12), 10, 11, true, mPaint);
     }
 
-    public void testDrawRoundRect() {
-        // abnormal case: RoundRect is null
-        try {
-            mCanvas.drawRoundRect(null, 10.0f, 29.0f, mPaint);
-            fail("should throw out NullPointerException because RoundRect is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+    @Test(expected=NullPointerException.class)
+    public void testDrawRoundRectNull() {
+        // Should throw out NullPointerException because RoundRect is null
+        mCanvas.drawRoundRect(null, 10.0f, 29.0f, mPaint);
+    }
 
+    @Test
+    public void testDrawRoundRect() {
         mCanvas.drawRoundRect(new RectF(0, 0, 10, 12), 8, 8, mPaint);
     }
 
+    @Test
     public void testDrawPath() {
         mCanvas.drawPath(new Path(), mPaint);
     }
 
-    public void testDrawBitmap1() {
+    @Test(expected=RuntimeException.class)
+    public void testDrawBitmapAtPointRecycled() {
         Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
-
-        // abnormal case: the bitmap to be drawn is recycled
         b.recycle();
-        try {
-            mCanvas.drawBitmap(b, 10.0f, 29.0f, mPaint);
-            fail("should throw out RuntimeException because bitmap has been recycled");
-        } catch (RuntimeException e) {
-            // expected
-        }
 
-        b = Bitmap.createBitmap(BITMAP_WIDTH, 12, Config.ARGB_8888);
+        // Should throw out RuntimeException because bitmap has been recycled
+        mCanvas.drawBitmap(b, 10.0f, 29.0f, mPaint);
+    }
+
+    @Test
+    public void testDrawBitmapAtPoint() {
+        Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 12, Config.ARGB_8888);
         mCanvas.drawBitmap(b, 10, 12, null);
         mCanvas.drawBitmap(b, 5, 12, mPaint);
     }
 
-    public void testDrawBitmap2() {
+    @Test(expected=RuntimeException.class)
+    public void testDrawBitmapSrcDstFloatRecycled() {
         Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
-
-        // abnormal case: the bitmap to be drawn is recycled
         b.recycle();
-        try {
-            mCanvas.drawBitmap(b, null, new RectF(), mPaint);
-            fail("should throw out RuntimeException because bitmap has been recycled");
-        } catch (RuntimeException e) {
-            // expected
-        }
 
-        b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+        // Should throw out RuntimeException because bitmap has been recycled
+        mCanvas.drawBitmap(b, null, new RectF(), mPaint);
+    }
+
+    @Test
+    public void testDrawBitmapSrcDstFloat() {
+        Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
         mCanvas.drawBitmap(b, new Rect(), new RectF(), null);
         mCanvas.drawBitmap(b, new Rect(), new RectF(), mPaint);
     }
 
-    public void testDrawBitmap3() {
+    @Test(expected=RuntimeException.class)
+    public void testDrawBitmapSrcDstIntRecycled() {
         Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
-
-        // abnormal case: the bitmap to be drawn is recycled
         b.recycle();
-        try {
-            mCanvas.drawBitmap(b, null, new Rect(), mPaint);
-            fail("should throw out RuntimeException because bitmap has been recycled");
-        } catch (RuntimeException e) {
-            // expected
-        }
 
-        b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+        // Should throw out RuntimeException because bitmap has been recycled
+        mCanvas.drawBitmap(b, null, new Rect(), mPaint);
+    }
+
+    @Test
+    public void testDrawBitmapSrcDstInt() {
+        Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
         mCanvas.drawBitmap(b, new Rect(), new Rect(), null);
         mCanvas.drawBitmap(b, new Rect(), new Rect(), mPaint);
     }
 
-    public void testDrawBitmap4() {
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapIntsNegativeWidth() {
+        // Should throw out IllegalArgumentException because width is less than 0
+        mCanvas.drawBitmap(new int[2008], 10, 10, 10, 10, -1, 10, true, null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapIntsNegativeHeight() {
+        // Should throw out IllegalArgumentException because height is less than 0
+        mCanvas.drawBitmap(new int[2008], 10, 10, 10, 10, 10, -1, true, null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapIntsBadStride() {
+        // Should throw out IllegalArgumentException because stride less than width and
+        // bigger than -width
+        mCanvas.drawBitmap(new int[2008], 10, 5, 10, 10, 10, 10, true, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapIntsNegativeOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because offset less than 0
+        mCanvas.drawBitmap(new int[2008], -1, 10, 10, 10, 10, 10, true, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapIntsBadOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because sum of offset and width
+        // is bigger than colors' length
+        mCanvas.drawBitmap(new int[29], 10, 29, 10, 10, 20, 10, true, null);
+    }
+
+    @Test
+    public void testDrawBitmapInts() {
         final int[] colors = new int[2008];
 
-        // abnormal case: width less than 0
-        try {
-            mCanvas.drawBitmap(colors, 10, 10, 10, 10, -1, 10, true, null);
-            fail("should throw out IllegalArgumentException because width is less than 0");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: height less than 0
-        try {
-            mCanvas.drawBitmap(colors, 10, 10, 10, 10, 10, -1, true, null);
-            fail("should throw out IllegalArgumentException because height is less than 0");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: stride less than width and bigger than -width
-        try {
-            mCanvas.drawBitmap(colors, 10, 5, 10, 10, 10, 10, true, null);
-            fail("should throw out IllegalArgumentException because stride less than width and"
-                            + " bigger than -width");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: offset less than 0
-        try {
-            mCanvas.drawBitmap(colors, -1, 10, 10, 10, 10, 10, true, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because offset less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: (offset + width) bigger than colors' length
-        try {
-            mCanvas.drawBitmap(new int[29], 10, 29, 10, 10, 20, 10, true, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of offset and width"
-                            + " is bigger than colors' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
         // special case: width equals to 0
         mCanvas.drawBitmap(colors, 10, 10, 10, 10, 0, 10, true, null);
 
@@ -1492,51 +1414,42 @@
         mCanvas.drawBitmap(colors, 10, 10, 10, 10, 10, 29, true, mPaint);
     }
 
-    public void testDrawBitmap6() {
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapFloatsNegativeWidth() {
+        // Should throw out IllegalArgumentException because width is less than 0
+        mCanvas.drawBitmap(new int[2008], 10, 10, 10.0f, 10.0f, -1, 10, true, null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapFloatsNegativeHeight() {
+        // Should throw out IllegalArgumentException because height is less than 0
+        mCanvas.drawBitmap(new int[2008], 10, 10, 10.0f, 10.0f, 10, -1, true, null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testDrawBitmapFloatsBadStride() {
+        // Should throw out IllegalArgumentException because stride less than width and
+        // bigger than -width
+        mCanvas.drawBitmap(new int[2008], 10, 5, 10.0f, 10.0f, 10, 10, true, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapFloatsNegativeOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because offset less than 0
+        mCanvas.drawBitmap(new int[2008], -1, 10, 10.0f, 10.0f, 10, 10, true, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapFloatsBadOffset() {
+        // Should throw out ArrayIndexOutOfBoundsException because sum of offset and width
+        // is bigger than colors' length
+        mCanvas.drawBitmap(new int[29], 10, 29, 10.0f, 10.0f, 20, 10, true, null);
+    }
+
+    @Test
+    public void testDrawBitmapFloats() {
         final int[] colors = new int[2008];
 
-        // abnormal case: width less than 0
-        try {
-            mCanvas.drawBitmap(colors, 10, 10, 10.0f, 10.0f, -1, 10, true, null);
-            fail("should throw out IllegalArgumentException because width is less than 0");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: height less than 0
-        try {
-            mCanvas.drawBitmap(colors, 10, 10, 10.0f, 10.0f, 10, -1, true, null);
-            fail("should throw out IllegalArgumentException because height is less than 0");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: stride less than width and bigger than -width
-        try {
-            mCanvas.drawBitmap(colors, 10, 5, 10.0f, 10.0f, 10, 10, true, null);
-            fail("should throw out IllegalArgumentException because stride is less than width "
-                                + "and bigger than -width");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // abnormal case: offset less than 0
-        try {
-            mCanvas.drawBitmap(colors, -1, 10, 10.0f, 10.0f, 10, 10, true, null);
-            fail("should throw out IllegalArgumentException because offset is less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: (offset + width) bigger than colors' length
-        try {
-            mCanvas.drawBitmap(new int[29], 10, 29, 10.0f, 10.0f, 20, 10, true, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of offset and width"
-                            + " is bigger than colors' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
         // special case: width equals to 0
         mCanvas.drawBitmap(colors, 10, 10, 10.0f, 10.0f, 0, 10, true, null);
 
@@ -1548,49 +1461,70 @@
         mCanvas.drawBitmap(colors, 10, 10, 10.0f, 10.0f, 10, 29, true, mPaint);
     }
 
-    public void testDrawBitmap5() {
+    @Test
+    public void testDrawBitmapMatrix() {
         final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
         mCanvas.drawBitmap(b, new Matrix(), null);
         mCanvas.drawBitmap(b, new Matrix(), mPaint);
     }
 
-    public void testDrawBitmapMesh() {
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshNegativeWidth() {
         final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
 
-        // abnormal case: meshWidth less than 0
-        try {
-            mCanvas.drawBitmapMesh(b, -1, 10, null, 0, null, 0, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because meshWidth less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out ArrayIndexOutOfBoundsException because meshWidth less than 0
+        mCanvas.drawBitmapMesh(b, -1, 10, null, 0, null, 0, null);
+    }
 
-        // abnormal case: meshHeight less than 0
-        try {
-            mCanvas.drawBitmapMesh(b, 10, -1, null, 0, null, 0, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because meshHeight "
-                                    + "is less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshNegativeHeight() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
 
-        // abnormal case: vertOffset less than 0
-        try {
-            mCanvas.drawBitmapMesh(b, 10, 10, null, -1, null, 0, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because vertOffset "
-                                                + "is less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out ArrayIndexOutOfBoundsException because meshHeight is less than 0
+        mCanvas.drawBitmapMesh(b, 10, -1, null, 0, null, 0, null);
+    }
 
-        // abnormal case: colorOffset less than 0
-        try {
-            mCanvas.drawBitmapMesh(b, 10, 10, null, 10, null, -1, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because colorOffset is"
-                                    + " less than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshNegativeVertOffset() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+
+        // Should throw out ArrayIndexOutOfBoundsException because vertOffset is less than 0
+        mCanvas.drawBitmapMesh(b, 10, 10, null, -1, null, 0, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshNegativeColorOffset() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+
+        // Should throw out ArrayIndexOutOfBoundsException because colorOffset is less than 0
+        mCanvas.drawBitmapMesh(b, 10, 10, null, 10, null, -1, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshTooFewVerts() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+
+        // Should throw out ArrayIndexOutOfBoundsException because verts' length is too short
+        mCanvas.drawBitmapMesh(b, 10, 10, new float[] {
+                10.0f, 29.0f
+        }, 10, null, 10, null);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawBitmapMeshTooFewColors() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
+
+        // Should throw out ArrayIndexOutOfBoundsException because colors' length is too short
+        // abnormal case: colors' length is too short
+        final float[] verts = new float[2008];
+        mCanvas.drawBitmapMesh(b, 10, 10, verts, 10, new int[] {
+                10, 29
+        }, 10, null);
+    }
+
+    @Test
+    public void testDrawBitmapMesh() {
+        final Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, 29, Config.ARGB_8888);
 
         // special case: meshWidth equals to 0
         mCanvas.drawBitmapMesh(b, 0, 10, null, 10, null, 10, null);
@@ -1598,36 +1532,15 @@
         // special case: meshHeight equals to 0
         mCanvas.drawBitmapMesh(b, 10, 0, null, 10, null, 10, null);
 
-        // abnormal case: verts' length is too short
-        try {
-            mCanvas.drawBitmapMesh(b, 10, 10, new float[] {
-                    10.0f, 29.0f
-            }, 10, null, 10, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because verts' length"
-                                    + " is too short");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: colors' length is too short
-        final float[] verts = new float[2008];
-        try {
-            mCanvas.drawBitmapMesh(b, 10, 10, verts, 10, new int[] {
-                    10, 29
-            }, 10, null);
-            fail("should throw out ArrayIndexOutOfBoundsException because colors' "
-                        + "length is too short");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
         // normal case
+        final float[] verts = new float[2008];
         final int[] colors = new int[2008];
         mCanvas.drawBitmapMesh(b, 10, 10, verts, 10, colors, 10, null);
         mCanvas.drawBitmapMesh(b, 10, 10, verts, 10, colors, 10, mPaint);
     }
 
-    public void testDrawVertices() {
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawVerticesTooFewVerts() {
         final float[] verts = new float[10];
         final float[] texs = new float[10];
         final int[] colors = new int[10];
@@ -1635,45 +1548,65 @@
                 0, 1, 2, 3, 4, 1
         };
 
-        // abnormal case: (vertOffset + vertexCount) bigger than verts' length
-        try {
-            mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 8, texs, 0, colors, 0, indices,
-                    0, 4, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of vertOffset and"
-                            + " vertexCount is bigger than verts' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out ArrayIndexOutOfBoundsException because sum of vertOffset and
+        // vertexCount is bigger than verts' length
+        mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 8, texs, 0, colors, 0, indices,
+                0, 4, mPaint);
+    }
 
-        // abnormal case: (texOffset + vertexCount) bigger than texs' length
-        try {
-            mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 30, colors, 0, indices,
-                    0, 4, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of texOffset and"
-                                    + " vertexCount is bigger thatn texs' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawVerticesTooFewTexs() {
+        final float[] verts = new float[10];
+        final float[] texs = new float[10];
+        final int[] colors = new int[10];
+        final short[] indices = {
+                0, 1, 2, 3, 4, 1
+        };
 
-        // abnormal case: (colorOffset + vertexCount) bigger than colors' length
-        try {
-            mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 0, colors, 30, indices,
-                    0, 4, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of colorOffset and"
-                                + " vertexCount is bigger than colors' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out ArrayIndexOutOfBoundsException because sum of texOffset and
+        // vertexCount is bigger thatn texs' length
+        mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 30, colors, 0, indices,
+                0, 4, mPaint);
+    }
 
-        // abnormal case: (indexOffset + indexCount) bigger than indices' length
-        try {
-            mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 0, colors, 0, indices,
-                    10, 30, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of indexOffset and"
-                            + " indexCount is bigger than indices' length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawVerticesTooFewColors() {
+        final float[] verts = new float[10];
+        final float[] texs = new float[10];
+        final int[] colors = new int[10];
+        final short[] indices = {
+                0, 1, 2, 3, 4, 1
+        };
+
+        // Should throw out ArrayIndexOutOfBoundsException because sum of colorOffset and
+        // vertexCount is bigger than colors' length
+        mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 0, colors, 30, indices,
+                0, 4, mPaint);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawVerticesTooFewIndices() {
+        final float[] verts = new float[10];
+        final float[] texs = new float[10];
+        final int[] colors = new int[10];
+        final short[] indices = {
+                0, 1, 2, 3, 4, 1
+        };
+
+        // Should throw out ArrayIndexOutOfBoundsException because sum of indexOffset and
+        // indexCount is bigger than indices' length
+        mCanvas.drawVertices(VertexMode.TRIANGLES, 10, verts, 0, texs, 0, colors, 0, indices,
+                10, 30, mPaint);
+    }
+
+    @Test
+    public void testDrawVertices() {
+        final float[] verts = new float[10];
+        final float[] texs = new float[10];
+        final int[] colors = new int[10];
+        final short[] indices = {
+                0, 1, 2, 3, 4, 1
+        };
 
         // special case: in texs, colors, indices, one of them, two of them and
         // all are null
@@ -1697,85 +1630,71 @@
                 6, mPaint);
     }
 
-    public void testDrawText1() {
-        final char[] text = {
-                'a', 'n', 'd', 'r', 'o', 'i', 'd'
-        };
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawArrayTextNegativeIndex() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
 
-        // abnormal case: index less than 0
-        try {
-            mCanvas.drawText(text, -1, 7, 10, 10, mPaint);
-            fail("should throw out IndexOutOfBoundsException because index is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out IndexOutOfBoundsException because index is less than 0
+        mCanvas.drawText(text, -1, 7, 10, 10, mPaint);
+    }
 
-        // abnormal case: count less than 0
-        try {
-            mCanvas.drawText(text, 0, -1, 10, 10, mPaint);
-            fail("should throw out IndexOutOfBoundsException because count is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawArrayTextNegativeCount() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
 
-        // abnormal case: (index + count) bigger than text's length
-        try {
-            mCanvas.drawText(text, 0, 10, 10, 10, mPaint);
-            fail("should throw out IndexOutOfBoundsException because sum of index and count "
-                                + "is bigger than text's length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out IndexOutOfBoundsException because count is less than 0
+        mCanvas.drawText(text, 0, -1, 10, 10, mPaint);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawArrayTextTextLengthTooSmall() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
+
+        // Should throw out IndexOutOfBoundsException because sum of index and count
+        // is bigger than text's length
+        mCanvas.drawText(text, 0, 10, 10, 10, mPaint);
+    }
+
+    @Test
+    public void testDrawArrayText() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
 
         // normal case
         mCanvas.drawText(text, 0, 7, 10, 10, mPaint);
     }
 
-    public void testDrawText2() {
+    @Test
+    public void testDrawStringTextAtPosition() {
         mCanvas.drawText("android", 10, 30, mPaint);
     }
 
-    public void testDrawText3() {
-        final String text = "android";
-
-        // abnormal case: start less than 0
-        try {
-            mCanvas.drawText(text, -1, 7, 10, 30, mPaint);
-            fail("should throw out IndexOutOfBoundsException because start is lesss than 0");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: end less than 0
-        try {
-            mCanvas.drawText(text, 0, -1, 10, 30, mPaint);
-            fail("should throw out IndexOutOfBoundsException because end is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: start bigger than end
-        try {
-            mCanvas.drawText(text, 3, 1, 10, 30, mPaint);
-            fail("should throw out IndexOutOfBoundsException because start is bigger than end");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // abnormal case: (end - start) bigger than text's length
-        try {
-            mCanvas.drawText(text, 0, 10, 10, 30, mPaint);
-            fail("should throw out IndexOutOfBoundsException because end subtracts start should"
-                                + " bigger than text's length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        // normal case
-        mCanvas.drawText(text, 0, 7, 10, 30, mPaint);
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextTextAtPositionWithOffsetsNegativeStart() {
+        // Should throw out IndexOutOfBoundsException because start is less than 0
+        mCanvas.drawText("android", -1, 7, 10, 30, mPaint);
     }
 
-    public void testDrawText4() {
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextTextAtPositionWithOffsetsNegativeEnd() {
+        // Should throw out IndexOutOfBoundsException because end is less than 0
+        mCanvas.drawText("android", 0, -1, 10, 30, mPaint);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextTextAtPositionWithOffsetsStartEndMismatch() {
+        // Should throw out IndexOutOfBoundsException because start is bigger than end
+        mCanvas.drawText("android", 3, 1, 10, 30, mPaint);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextTextAtPositionWithOffsetsTextTooLong() {
+        // Should throw out IndexOutOfBoundsException because end subtracts start should
+        // bigger than text's length
+        mCanvas.drawText("android", 0, 10, 10, 30, mPaint);
+    }
+
+    @Test
+    public void testDrawTextTextAtPositionWithOffsets() {
         final String t1 = "android";
         mCanvas.drawText(t1, 0, 7, 10, 30, mPaint);
 
@@ -1792,6 +1711,7 @@
         mCanvas.drawText(t5, 0, 7, 10, 30, mPaint);
     }
 
+    @Test
     public void testDrawTextRun() {
         final String text = "android";
         final Paint paint = new Paint();
@@ -1800,213 +1720,248 @@
         mCanvas.drawTextRun(text, 0, text.length(), 0, text.length(), 0.0f, 0.0f, false, paint);
         mCanvas.drawTextRun(text, text.length(), text.length(), text.length(), text.length(),
                 0.0f, 0.0f, false, paint);
-
-        try {
-            mCanvas.drawTextRun((char[])null, 0, 0, 0, 0, 0.0f, 0.0f, false, paint);
-            fail("should throw out NullPointerException because text is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun((CharSequence)null, 0, 0, 0, 0, 0.0f, 0.0f, false, paint);
-            fail("should throw out NullPointerException because text is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text.toCharArray(), 0, 0, 0, 0, 0.0f, 0.0f, false, null);
-            fail("should throw out NullPointerException because paint is null");
-        } catch (NullPointerException e) {
-        }
-        try {
-            mCanvas.drawTextRun(text, 0, 0, 0, 0, 0.0f, 0.0f, false, null);
-            fail("should throw out NullPointerException because paint is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text.toCharArray(), -1, text.length(), 0, text.length(), 0.0f, 0.0f,
-                    false, paint);
-            fail("should throw out IndexOutOfBoundsException because index is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text.toCharArray(), 0, -1, 0, text.length(), 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because count is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text.toCharArray(), 0, text.length(), 1, text.length(), 0.0f, 0.0f,
-                    false, paint);
-            fail("should throw out IndexOutOfBoundsException because contextIndex is bigger than "
-                    + "index");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-
-        try {
-            mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() - 1, 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because contexIndex + contextCount "
-                    + "is less than index + count");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text.toCharArray(), 0, text.length() + 1, 0, text.length() + 1,
-                    0.0f, 0.0f, false, paint);
-            fail("should throw out IndexOutOfBoundsException because index + count is bigger than "
-                    + "text length");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text, 0, text.length(), -1, text.length(), 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because contextStart is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text, 0, text.length(), 1, text.length(), 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because start is less than "
-                    + "contextStart");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text, 1, 0, 0, text.length(), 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because end is less than start");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() - 1, 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because contextEnd is less than end");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() + 1, 0.0f, 0.0f, false,
-                    paint);
-            fail("should throw out IndexOutOfBoundsException because contextEnd is bigger than "
-                    + "text length");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
-    public void testDrawPosText1() {
+    @Test(expected=NullPointerException.class)
+    public void testDrawTextRunNullCharArray() {
+        // Should throw out NullPointerException because text is null
+        mCanvas.drawTextRun((char[]) null, 0, 0, 0, 0, 0.0f, 0.0f, false, new Paint());
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testDrawTextRunNullCharSequence() {
+        // Should throw out NullPointerException because text is null
+        mCanvas.drawTextRun((CharSequence) null, 0, 0, 0, 0, 0.0f, 0.0f, false, new Paint());
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testDrawTextRunCharArrayNullPaint() {
+        // Should throw out NullPointerException because paint is null
+        mCanvas.drawTextRun("android".toCharArray(), 0, 0, 0, 0, 0.0f, 0.0f, false, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testDrawTextRunCharSequenceNullPaint() {
+        // Should throw out NullPointerException because paint is null
+        mCanvas.drawTextRun("android", 0, 0, 0, 0, 0.0f, 0.0f, false, null);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunNegativeIndex() {
+        final String text = "android";
+        final Paint paint = new Paint();
+
+        // Should throw out IndexOutOfBoundsException because index is less than 0
+        mCanvas.drawTextRun(text.toCharArray(), -1, text.length(), 0, text.length(), 0.0f, 0.0f,
+                false, new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunNegativeCount() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because count is less than 0
+        mCanvas.drawTextRun(text.toCharArray(), 0, -1, 0, text.length(), 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunContestIndexTooLarge() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because contextIndex is bigger than index
+        mCanvas.drawTextRun(text.toCharArray(), 0, text.length(), 1, text.length(), 0.0f, 0.0f,
+                false, new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunContestIndexTooSmall() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because contextIndex + contextCount
+        // is less than index + count
+        mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() - 1, 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunIndexTooLarge() {
+        final String text = "android";
+        final Paint paint = new Paint();
+
+        // Should throw out IndexOutOfBoundsException because index + count is bigger than
+        // text length
+        mCanvas.drawTextRun(text.toCharArray(), 0, text.length() + 1, 0, text.length() + 1,
+                0.0f, 0.0f, false, new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunNegativeContextStart() {
+        final String text = "android";
+        final Paint paint = new Paint();
+
+        // Should throw out IndexOutOfBoundsException because contextStart is less than 0
+        mCanvas.drawTextRun(text, 0, text.length(), -1, text.length(), 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunStartLessThanContextStart() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because start is less than contextStart
+        mCanvas.drawTextRun(text, 0, text.length(), 1, text.length(), 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunEndLessThanStart() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because end is less than start
+        mCanvas.drawTextRun(text, 1, 0, 0, text.length(), 0.0f, 0.0f, false, new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunContextEndLessThanEnd() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because contextEnd is less than end
+        mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() - 1, 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawTextRunContextEndLargerThanTextLength() {
+        final String text = "android";
+
+        // Should throw out IndexOutOfBoundsException because contextEnd is bigger than
+        // text length
+        mCanvas.drawTextRun(text, 0, text.length(), 0, text.length() + 1, 0.0f, 0.0f, false,
+                new Paint());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawPosTextWithIndexAndCountNegativeIndex() {
         final char[] text = {
                 'a', 'n', 'd', 'r', 'o', 'i', 'd'
         };
-        final float[] pos = new float[] {
+        final float[] pos = new float[]{
                 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f,
                 7.0f, 7.0f
         };
 
-        // abnormal case: index less than 0
-        try {
-            mCanvas.drawPosText(text, -1, 7, pos, mPaint);
-            fail("should throw out IndexOutOfBoundsException because index is less than 0");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out IndexOutOfBoundsException because index is less than 0
+        mCanvas.drawPosText(text, -1, 7, pos, mPaint);
+    }
 
-        // abnormal case: index + count > text.length
-        try {
-            mCanvas.drawPosText(text, 1, 10, pos, mPaint);
-            fail("should throw out IndexOutOfBoundsException because sum of index and count is"
-                                + " bigger than text's length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
 
-        // abnormal case: count*2 > pos.length
-        try {
-            mCanvas.drawPosText(text, 1, 10, new float[] {
-                    10.0f, 30.f
-            }, mPaint);
-            fail("should throw out IndexOutOfBoundsException because 2 times of count is"
-                                + " bigger than pos' length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawPosTextWithIndexAndCountTextTooShort() {
+        final char[] text = {
+                'a', 'n', 'd', 'r', 'o', 'i', 'd'
+        };
+        final float[] pos = new float[]{
+                0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f,
+                7.0f, 7.0f
+        };
+
+        // Should throw out IndexOutOfBoundsException because sum of index and count is
+        // bigger than text's length
+        mCanvas.drawPosText(text, 1, 10, pos, mPaint);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawPosTextWithIndexAndCountCountTooLarge() {
+        final char[] text = {
+                'a', 'n', 'd', 'r', 'o', 'i', 'd'
+        };
+
+        // Should throw out IndexOutOfBoundsException because 2 times of count is
+        // bigger than pos' length
+        mCanvas.drawPosText(text, 1, 10, new float[] {
+                10.0f, 30.f
+        }, mPaint);
+    }
+
+    @Test
+    public void testDrawPosTextWithIndexAndCount() {
+        final char[] text = {
+                'a', 'n', 'd', 'r', 'o', 'i', 'd'
+        };
+        final float[] pos = new float[]{
+                0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f,
+                7.0f, 7.0f
+        };
 
         // normal case
         mCanvas.drawPosText(text, 0, 7, pos, mPaint);
     }
 
-    public void testDrawPosText2() {
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDrawPosTextCountTooLarge() {
         final String text = "android";
-        final float[] pos = new float[] {
+
+        // Should throw out IndexOutOfBoundsException because 2 times of count is
+        // bigger than pos' length
+        mCanvas.drawPosText(text, new float[]{
+                10.0f, 30.f
+        }, mPaint);
+    }
+
+    @Test
+    public void testDrawPosText() {
+        final String text = "android";
+        final float[] pos = new float[]{
                 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f,
                 7.0f, 7.0f
         };
-
-        // abnormal case: text.length()*2 > pos.length
-        try {
-            mCanvas.drawPosText(text, new float[] {
-                    10.0f, 30.f
-            }, mPaint);
-            fail("should throw out IndexOutOfBoundsException because 2 times of text's length is"
-                                + " bigger than pos' length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
         // normal case
         mCanvas.drawPosText(text, pos, mPaint);
     }
 
-    public void testDrawTextOnPath1() {
-        final Path path = new Path();
-        final char[] text = {
-                'a', 'n', 'd', 'r', 'o', 'i', 'd'
-        };
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawTextOnPathWithIndexAndCountNegativeIndex() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
 
-        // abnormal case: index < 0
-        try {
-            mCanvas.drawTextOnPath(text, -1, 7, path, 10.0f, 10.0f, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because index is smaller than 0");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+        // Should throw out ArrayIndexOutOfBoundsException because index is smaller than 0
+        mCanvas.drawTextOnPath(text, -1, 7, new Path(), 10.0f, 10.0f, mPaint);
+    }
 
-        // abnormal case: index + count > text.length
-        try {
-            mCanvas.drawTextOnPath(text, 0, 10, path, 10.0f, 10.0f, mPaint);
-            fail("should throw out ArrayIndexOutOfBoundsException because sum of index and"
-                            + " count is bigger than text's length");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testDrawTextOnPathWithIndexAndCountTextTooShort() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
+
+        // Should throw out ArrayIndexOutOfBoundsException because sum of index and
+        // count is bigger than text's length
+        mCanvas.drawTextOnPath(text, 0, 10, new Path(), 10.0f, 10.0f, mPaint);
+    }
+
+    @Test
+    public void testDrawTextOnPathWithIndexAndCount() {
+        final char[] text = { 'a', 'n', 'd', 'r', 'o', 'i', 'd' };
 
         // normal case
-        mCanvas.drawTextOnPath(text, 0, 7, path, 10.0f, 10.0f, mPaint);
+        mCanvas.drawTextOnPath(text, 0, 7, new Path(), 10.0f, 10.0f, mPaint);
     }
 
-    public void testDrawTextOnPath2() {
+    @Test
+    public void testDrawTextOnPathtestDrawTextRunNegativeCount() {
         final Path path = new Path();
-        String text = "";
 
         // no character in text
-        mCanvas.drawTextOnPath(text, path, 10.0f, 10.0f, mPaint);
+        mCanvas.drawTextOnPath("", path, 10.0f, 10.0f, mPaint);
 
         // There are characters in text
-        text = "android";
-        mCanvas.drawTextOnPath(text, path, 10.0f, 10.0f, mPaint);
+        mCanvas.drawTextOnPath("android", path, 10.0f, 10.0f, mPaint);
     }
 
+    @Test
     public void testDrawPicture1() {
         mCanvas.drawPicture(new Picture());
     }
 
+    @Test
     public void testDrawPicture2() {
         final RectF dst = new RectF(0, 0, 10, 31);
         final Picture p = new Picture();
@@ -2018,6 +1973,7 @@
         mCanvas.drawPicture(p, dst);
     }
 
+    @Test
     public void testDrawPicture3() {
         final Rect dst = new Rect(0, 10, 30, 0);
         final Picture p = new Picture();
@@ -2029,6 +1985,7 @@
         mCanvas.drawPicture(p, dst);
     }
 
+    @Test
     public void testDensity() {
         // set Density
         mCanvas.setDensity(DisplayMetrics.DENSITY_DEFAULT);
@@ -2042,15 +1999,9 @@
     private void preCompare() {
         final float[] values = new float[FLOAT_ARRAY_LEN];
         mCanvas.getMatrix().getValues(values);
-        assertEquals(1.0f, values[0]);
-        assertEquals(0.0f, values[1]);
-        assertEquals(0.0f, values[2]);
-        assertEquals(0.0f, values[3]);
-        assertEquals(1.0f, values[4]);
-        assertEquals(0.0f, values[5]);
-        assertEquals(0.0f, values[6]);
-        assertEquals(0.0f, values[7]);
-        assertEquals(1.0f, values[8]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f
+        }, values, 0.0f);
     }
 
     private RectF getDeviceClip() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/Canvas_EdgeTypeTest.java b/tests/tests/graphics/src/android/graphics/cts/Canvas_EdgeTypeTest.java
index 3716d82..f34ec71 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Canvas_EdgeTypeTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Canvas_EdgeTypeTest.java
@@ -15,19 +15,28 @@
  */
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Canvas;
+import android.graphics.Canvas.EdgeType;
 import android.graphics.Path;
 import android.graphics.RectF;
-import android.graphics.Canvas.EdgeType;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Canvas_EdgeTypeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Canvas_EdgeTypeTest {
+    @Test
     public void testValueOf(){
         assertEquals(EdgeType.BW, EdgeType.valueOf("BW"));
         assertEquals(EdgeType.AA, EdgeType.valueOf("AA"));
     }
 
+    @Test
     public void testValues(){
         EdgeType[] edgeType = EdgeType.values();
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/Canvas_VertexModeTest.java b/tests/tests/graphics/src/android/graphics/cts/Canvas_VertexModeTest.java
index d963ac8..68588ec 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Canvas_VertexModeTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Canvas_VertexModeTest.java
@@ -15,21 +15,30 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
 import android.graphics.Canvas.VertexMode;
-import android.test.AndroidTestCase;
+import android.graphics.Paint;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Canvas_VertexModeTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Canvas_VertexModeTest {
+    @Test
     public void testValueOf(){
         assertEquals(VertexMode.TRIANGLES, VertexMode.valueOf("TRIANGLES"));
         assertEquals(VertexMode.TRIANGLE_STRIP, VertexMode.valueOf("TRIANGLE_STRIP"));
         assertEquals(VertexMode.TRIANGLE_FAN, VertexMode.valueOf("TRIANGLE_FAN"));
     }
 
+    @Test
     public void testValues(){
         VertexMode[] verMode = VertexMode.values();
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
index 2657d15..c6f6f08 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
@@ -15,21 +15,27 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ColorMatrixColorFilterTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorMatrixColorFilterTest {
     private static final int TOLERANCE = 1;
 
+    @Test
     public void testColorMatrixColorFilter() {
         ColorMatrixColorFilter filter;
 
@@ -47,17 +53,17 @@
         paint.setColor(Color.BLUE);
         paint.setColorFilter(filter);
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.CYAN, bitmap.getPixel(0, 0));
+        verifyColor(Color.CYAN, bitmap.getPixel(0, 0));
         paint.setColor(Color.GREEN);
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.GREEN, bitmap.getPixel(0, 0));
+        verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
         paint.setColor(Color.RED);
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.RED, bitmap.getPixel(0, 0));
+        verifyColor(Color.RED, bitmap.getPixel(0, 0));
         // color components are clipped, not scaled
         paint.setColor(Color.MAGENTA);
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.WHITE, bitmap.getPixel(0, 0));
+        verifyColor(Color.WHITE, bitmap.getPixel(0, 0));
 
         float[] transparentRedAddBlue = new float[] {
                 1f, 0f, 0f, 0f, 0f,
@@ -73,29 +79,29 @@
         // the bitmap stores the result in premul colors and we read out an
         // unpremultiplied result, which causes us to need a bigger tolerance in
         // this case (due to the fact that scaling by 1/255 is not exact).
-        assertColor(Color.argb(128, 255, 0, 64), bitmap.getPixel(0, 0), 2);
+        verifyColor(Color.argb(128, 255, 0, 64), bitmap.getPixel(0, 0), 2);
         paint.setColor(Color.CYAN);
         canvas.drawPoint(0, 0, paint);
         // blue gets clipped
-        assertColor(Color.CYAN, bitmap.getPixel(0, 0));
+        verifyColor(Color.CYAN, bitmap.getPixel(0, 0));
 
         // change array to filter out green
-        assertEquals(1f, transparentRedAddBlue[6]);
+        assertEquals(1f, transparentRedAddBlue[6], 0.0f);
         transparentRedAddBlue[6] = 0f;
         // changing the array has no effect
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.CYAN, bitmap.getPixel(0, 0));
+        verifyColor(Color.CYAN, bitmap.getPixel(0, 0));
         // create a new filter with the changed matrix
         paint.setColorFilter(new ColorMatrixColorFilter(transparentRedAddBlue));
         canvas.drawPoint(0, 0, paint);
-        assertColor(Color.BLUE, bitmap.getPixel(0, 0));
+        verifyColor(Color.BLUE, bitmap.getPixel(0, 0));
     }
 
-    private void assertColor(int expected, int actual) {
-        assertColor(expected, actual, TOLERANCE);
+    private void verifyColor(int expected, int actual) {
+        verifyColor(expected, actual, TOLERANCE);
     }
-    
-    private void assertColor(int expected, int actual, int tolerance) {
+
+    private void verifyColor(int expected, int actual, int tolerance) {
         assertEquals(Color.red(expected), Color.red(actual), tolerance);
         assertEquals(Color.green(expected), Color.green(actual), tolerance);
         assertEquals(Color.blue(expected), Color.blue(actual), tolerance);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixTest.java
index 569b9fb..4a7909c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixTest.java
@@ -15,52 +15,52 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.ColorMatrix;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class ColorMatrixTest extends AndroidTestCase {
-    private ColorMatrix mColorMatrix;
+import com.android.compatibility.common.util.CtsArrayUtils;
 
-    private final float[] mSrc = new float[]{
-        0, 1, 2, 3, 4,
-        5, 6, 7, 8, 9,
-        10, 11, 12, 13, 14,
-        15, 16, 17, 18, 19
-    };
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorMatrixTest {
     private static final float TOLERANCE = 0.0000001f;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    private static final float[] SOURCE = new float[] {
+            0, 1, 2, 3, 4,
+            5, 6, 7, 8, 9,
+            10, 11, 12, 13, 14,
+            15, 16, 17, 18, 19
+    };
 
-        mColorMatrix = new ColorMatrix(mSrc);
+    private ColorMatrix mColorMatrix;
+
+    @Before
+    public void setup() {
+        mColorMatrix = new ColorMatrix(SOURCE);
     }
 
-    public void testColorMatrix(){
+    @Test
+    public void testColorMatrix() {
         new ColorMatrix();
 
-        ColorMatrix cM1 = new ColorMatrix(mSrc);
+        ColorMatrix cM1 = new ColorMatrix(SOURCE);
         float[] fA1 = cM1.getArray();
-        assertTrue(mSrc.length == fA1.length);
-        int len = mSrc.length;
-
-        for(int i = 0; i < len; i++){
-            assertEquals(mSrc[i], fA1[i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(SOURCE, fA1, 0.0f);
 
         ColorMatrix cM2 = new ColorMatrix(cM1);
         float[] fA2 = cM2.getArray();
-        assertTrue(fA1.length == fA2.length);
-        len = fA1.length;
-
-        for(int i = 0; i < len; i++){
-            assertEquals(fA1[i], fA2[i]);
-        }
-
+        CtsArrayUtils.verifyArrayEquals(fA1, fA2, 0.0f);
     }
 
-    public void testReset(){
+    @Test
+    public void testReset() {
         float[] ret = mColorMatrix.getArray();
         preCompare(ret);
 
@@ -68,67 +68,58 @@
         ret = mColorMatrix.getArray();
         assertEquals(20, ret.length);
 
-        for(int i = 0; i <= 19; i++){
-            if(0 == i % 6){
-                assertEquals(1.0f, ret[i]);
+        for (int i = 0; i <= 19; i++) {
+            if (0 == i % 6) {
+                assertEquals(1.0f, ret[i], 0.0f);
                 continue;
             }
 
-            assertEquals(0.0f, ret[i]);
+            assertEquals(0.0f, ret[i], 0.0f);
         }
     }
 
-    public void testSet1(){
+    @Test
+    public void testSet1() {
         float[] ret = mColorMatrix.getArray();
         preCompare(ret);
 
-        float[] fArray = new float[]{
-            19, 18, 17, 16, 15,
-            14, 13, 12, 11, 10,
-            9, 8, 7, 6, 5,
-            4, 3, 2, 1, 0
+        float[] fArray = new float[] {
+                19, 18, 17, 16, 15,
+                14, 13, 12, 11, 10,
+                9, 8, 7, 6, 5,
+                4, 3, 2, 1, 0
         };
 
         mColorMatrix.set(fArray);
-
         ret = mColorMatrix.getArray();
-        assertEquals(20, ret.length);
-
-        for(int i = 19; i >= 0; i--){
-            assertEquals((float) i, ret[19 - i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(fArray, ret, 0.0f);
     }
 
-    public void testSet2(){
+    @Test
+    public void testSet2() {
         float[] ret = mColorMatrix.getArray();
         preCompare(ret);
 
-        float[] fArray = new float[]{
-            19, 18, 17, 16, 15,
-            14, 13, 12, 11, 10,
-            9, 8, 7, 6, 5,
-            4, 3, 2, 1, 0
+        float[] fArray = new float[] {
+                19, 18, 17, 16, 15,
+                14, 13, 12, 11, 10,
+                9, 8, 7, 6, 5,
+                4, 3, 2, 1, 0
         };
 
         mColorMatrix.set(new ColorMatrix(fArray));
-
         ret = mColorMatrix.getArray();
-        assertEquals(20, ret.length);
-
-        for(int i = 19; i >= 0; i--){
-            assertEquals((float) i, ret[19 - i]);
-        }
+        CtsArrayUtils.verifyArrayEquals(fArray, ret, 0.0f);
     }
 
-    public void testSetRotate(){
+    @Test(expected=RuntimeException.class)
+    public void testSetRotateIllegalAxis() {
         // abnormal case: IllegalArgument axis
-        try{
-            mColorMatrix.setRotate(4, 90);
-            fail("shouldn't come to here");
-        }catch(RuntimeException e){
-            //expected
-        }
+        mColorMatrix.setRotate(4, 90);
+    }
 
+    @Test
+    public void testSetRotate() {
         mColorMatrix.setRotate(0, 180);
         float[] ret = mColorMatrix.getArray();
         assertEquals(-1.0f, ret[6], TOLERANCE);
@@ -149,33 +140,21 @@
         assertEquals(0, ret[5], TOLERANCE);
     }
 
-    public void testSetSaturation(){
+    @Test
+    public void testSetSaturation() {
         mColorMatrix.setSaturation(0.5f);
         float[] ret = mColorMatrix.getArray();
 
-        assertEquals(0.6065f, ret[0]);
-        assertEquals(0.3575f, ret[1]);
-        assertEquals(0.036f, ret[2]);
-        assertEquals(0.1065f, ret[5]);
-        assertEquals(0.85749996f, ret[6]);
-        assertEquals(0.036f, ret[7]);
-        assertEquals(0.1065f, ret[10]);
-        assertEquals(0.3575f, ret[11]);
-        assertEquals(0.536f, ret[12]);
-        assertEquals(0.0f, ret[3]);
-        assertEquals(0.0f, ret[4]);
-        assertEquals(0.0f, ret[8]);
-        assertEquals(0.0f, ret[9]);
-        assertEquals(0.0f, ret[13]);
-        assertEquals(0.0f, ret[14]);
-        assertEquals(0.0f, ret[15]);
-        assertEquals(0.0f, ret[16]);
-        assertEquals(0.0f, ret[17]);
-        assertEquals(1.0f, ret[18]);
-        assertEquals(0.0f, ret[19]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.6065f, 0.3575f, 0.036f, 0.0f, 0.0f,
+                0.1065f, 0.85749996f, 0.036f, 0.0f, 0.0f,
+                0.1065f, 0.3575f, 0.536f, 0.0f, 0.0f,
+                0.0f, 0.0f, 0.0f, 1.0f, 0.0f
+        }, ret, 0.0f);
     }
 
-    public void testSetScale(){
+    @Test
+    public void testSetScale() {
         float[] ret = mColorMatrix.getArray();
         preCompare(ret);
 
@@ -183,137 +162,100 @@
         ret = mColorMatrix.getArray();
 
         assertEquals(20, ret.length);
-        assertEquals(2.0f, ret[0]);
-        assertEquals(3.0f, ret[6]);
-        assertEquals(4.0f, ret[12]);
-        assertEquals(5.0f, ret[18]);
+        assertEquals(2.0f, ret[0], 0.0f);
+        assertEquals(3.0f, ret[6], 0.0f);
+        assertEquals(4.0f, ret[12], 0.0f);
+        assertEquals(5.0f, ret[18], 0.0f);
 
-        for(int i = 1; i <= 19; i++){
-            if(0 == i % 6){
+        for (int i = 1; i <= 19; i++) {
+            if (0 == i % 6) {
                 continue;
             }
 
-            assertEquals(0.0f, ret[i]);
+            assertEquals(0.0f, ret[i], 0.0f);
         }
     }
 
-    public void testSetRGB2YUV(){
+    @Test
+    public void testSetRGB2YUV() {
         mColorMatrix.setRGB2YUV();
         float[] ret = mColorMatrix.getArray();
 
-        assertEquals(0.299f, ret[0]);
-        assertEquals(0.587f, ret[1]);
-        assertEquals(0.114f, ret[2]);
-        assertEquals(-0.16874f, ret[5]);
-        assertEquals(-0.33126f, ret[6]);
-        assertEquals(0.5f, ret[7]);
-        assertEquals(0.5f, ret[10]);
-        assertEquals(-0.41869f, ret[11]);
-        assertEquals(-0.08131f, ret[12]);
-        assertEquals(0.0f, ret[3]);
-        assertEquals(0.0f, ret[4]);
-        assertEquals(0.0f, ret[8]);
-        assertEquals(0.0f, ret[9]);
-        assertEquals(0.0f, ret[13]);
-        assertEquals(0.0f, ret[14]);
-        assertEquals(0.0f, ret[15]);
-        assertEquals(0.0f, ret[16]);
-        assertEquals(0.0f, ret[17]);
-        assertEquals(1.0f, ret[18]);
-        assertEquals(0.0f, ret[19]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                0.299f, 0.587f, 0.114f, 0.0f, 0.0f,
+                -0.16874f, -0.33126f, 0.5f, 0.0f, 0.0f,
+                0.5f, -0.41869f, -0.08131f, 0.0f, 0.0f,
+                0.0f, 0.0f, 0.0f, 1.0f, 0.0f
+        }, ret, 0.0f);
     }
 
-    public void testSetYUV2RGB(){
+    @Test
+    public void testSetYUV2RGB() {
         mColorMatrix.setYUV2RGB();
         float[] ret = mColorMatrix.getArray();
 
-        assertEquals(1.402f, ret[2]);
-        assertEquals(1.0f, ret[5]);
-        assertEquals(-0.34414f, ret[6]);
-        assertEquals(-0.71414f, ret[7]);
-        assertEquals(1.0f, ret[10]);
-        assertEquals(1.772f, ret[11]);
-        assertEquals(0.0f, ret[12]);
-        assertEquals(1.0f, ret[0]);
-        assertEquals(0.0f, ret[1]);
-        assertEquals(0.0f, ret[3]);
-        assertEquals(0.0f, ret[4]);
-        assertEquals(0.0f, ret[8]);
-        assertEquals(0.0f, ret[9]);
-        assertEquals(0.0f, ret[13]);
-        assertEquals(0.0f, ret[14]);
-        assertEquals(0.0f, ret[15]);
-        assertEquals(0.0f, ret[16]);
-        assertEquals(0.0f, ret[17]);
-        assertEquals(1.0f, ret[18]);
-        assertEquals(0.0f, ret[19]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                1.0f, 0.0f, 1.402f, 0.0f, 0.0f,
+                1.0f, -0.34414f, -0.71414f, 0.0f, 0.0f,
+                1.0f, 1.772f, 0.0f, 0.0f, 0.0f,
+                0.0f, 0.0f, 0.0f, 1.0f, 0.0f
+        }, ret, 0.0f);
     }
 
-    public void testPostConcat(){
+    @Test
+    public void testPostConcat() {
         mColorMatrix.postConcat(new ColorMatrix());
 
         float[] ret = mColorMatrix.getArray();
 
-        for(int i = 0; i < 20; i++){
-            assertEquals((float) i, ret[i]);
+        for(int i = 0; i < 20; i++) {
+            assertEquals((float) i, ret[i], 0.0f);
         }
     }
 
-    public void testPreConcat(){
+    @Test
+    public void testPreConcat() {
         mColorMatrix.preConcat(new ColorMatrix());
 
         float[] ret = mColorMatrix.getArray();
 
-        for(int i = 0; i < 20; i++){
-            assertEquals((float) i, ret[i]);
+        for(int i = 0; i < 20; i++) {
+            assertEquals((float) i, ret[i], 0.0f);
         }
     }
 
-    public void testSetConcat(){
-        float[] floatA = new float[]{
-            0, 1, 2, 3, 4,
-            5, 6, 7, 8, 9,
-            9, 8, 7, 6, 5,
-            4, 3, 2, 1, 0,
+    @Test
+    public void testSetConcat() {
+        float[] floatA = new float[] {
+                0, 1, 2, 3, 4,
+                5, 6, 7, 8, 9,
+                9, 8, 7, 6, 5,
+                4, 3, 2, 1, 0,
         };
 
-        float[] floatB = new float[]{
-            1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1,
+        float[] floatB = new float[] {
+                1, 1, 1, 1, 1,
+                1, 1, 1, 1, 1,
+                1, 1, 1, 1, 1,
+                1, 1, 1, 1, 1,
         };
 
         mColorMatrix.setConcat(new ColorMatrix(floatA), new ColorMatrix(floatB));
 
         float[] ret = mColorMatrix.getArray();
-        assertEquals(6.0f, ret[0]);
-        assertEquals(6.0f, ret[1]);
-        assertEquals(6.0f, ret[2]);
-        assertEquals(6.0f, ret[3]);
-        assertEquals(10.0f, ret[4]);
-        assertEquals(26.0f, ret[5]);
-        assertEquals(26.0f, ret[6]);
-        assertEquals(26.0f, ret[7]);
-        assertEquals(26.0f, ret[8]);
-        assertEquals(35.0f, ret[9]);
-        assertEquals(30.0f, ret[10]);
-        assertEquals(30.0f, ret[11]);
-        assertEquals(30.0f, ret[12]);
-        assertEquals(30.0f, ret[13]);
-        assertEquals(35.0f, ret[14]);
-        assertEquals(10.0f, ret[15]);
-        assertEquals(10.0f, ret[16]);
-        assertEquals(10.0f, ret[17]);
-        assertEquals(10.0f, ret[18]);
-        assertEquals(10.0f, ret[19]);
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                6.0f, 6.0f, 6.0f, 6.0f, 10.f,
+                26.0f, 26.0f, 26.0f, 26.0f, 35.0f,
+                30.0f, 30.0f, 30.0f, 30.0f, 35.0f,
+                10.0f, 10.0f, 10.0f, 10.0f, 10.0f
+        }, ret, 0.0f);
     }
 
-    private void preCompare(float[] ret){
+    private void preCompare(float[] ret) {
         assertEquals(20, ret.length);
 
-        for(int i = 0; i < 20; i++){
-            assertEquals((float) i, ret[i]);
+        for(int i = 0; i < 20; i++) {
+            assertEquals((float) i, ret[i], 0.0f);
         }
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
new file mode 100644
index 0000000..4494656
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
@@ -0,0 +1,772 @@
+/*
+ * 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.cts;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.function.DoubleUnaryOperator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorSpaceTest {
+    // Column-major RGB->XYZ transform matrix for the sRGB color space
+    private static final float[] SRGB_TO_XYZ = {
+            0.412391f, 0.212639f, 0.019331f,
+            0.357584f, 0.715169f, 0.119195f,
+            0.180481f, 0.072192f, 0.950532f
+    };
+    // Column-major XYZ->RGB transform matrix for the sRGB color space
+    private static final float[] XYZ_TO_SRGB = {
+            3.240970f, -0.969244f,  0.055630f,
+           -1.537383f,  1.875968f, -0.203977f,
+           -0.498611f,  0.041555f,  1.056971f
+    };
+
+    private static final float[] SRGB_PRIMARIES_xyY =
+            { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
+    private static final float[] SRGB_WHITE_POINT_xyY = { 0.3127f, 0.3290f };
+
+    private static final float[] SRGB_PRIMARIES_XYZ = {
+            1.939394f, 1.000000f, 0.090909f,
+            0.500000f, 1.000000f, 0.166667f,
+            2.500000f, 1.000000f, 13.166667f
+    };
+    private static final float[] SRGB_WHITE_POINT_XYZ = { 0.950456f, 1.000f, 1.089058f };
+
+    private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity();
+
+    @Test
+    public void testNamedColorSpaces() {
+        for (ColorSpace.Named named : ColorSpace.Named.values()) {
+            ColorSpace colorSpace = ColorSpace.get(named);
+            assertNotNull(colorSpace.getName());
+            assertNotNull(colorSpace);
+            assertEquals(named.ordinal(), colorSpace.getId());
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullName() {
+        new ColorSpace.Rgb(null, new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptyName() {
+        new ColorSpace.Rgb("", new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testName() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                sIdentity, sIdentity, 0.0f, 1.0f);
+        assertEquals("Test", cs.getName());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPrimariesLength() {
+        new ColorSpace.Rgb("Test", new float[7], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testWhitePointLength() {
+        new ColorSpace.Rgb("Test", new float[6], new float[1], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullOETF() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], null, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testOETF() {
+        DoubleUnaryOperator op = Math::sqrt;
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                op, sIdentity, 0.0f, 1.0f);
+        assertEquals(op, cs.getOetf());
+        assertEquals(0.5, cs.getOetf().applyAsDouble(0.25), 1e-5);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullEOTF() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, null, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testEOTF() {
+        DoubleUnaryOperator op = x -> x * x;
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                sIdentity, op, 0.0f, 1.0f);
+        assertEquals(op, cs.getEotf());
+        assertEquals(0.0625, cs.getEotf().applyAsDouble(0.25), 1e-5);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidRange() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, sIdentity, 2.0f, 1.0f);
+    }
+
+    @Test
+    public void testRanges() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float m1 = cs.getMinValue(0);
+        float m2 = cs.getMinValue(1);
+        float m3 = cs.getMinValue(2);
+
+        assertEquals(0.0f, m1, 1e-9f);
+        assertEquals(0.0f, m2, 1e-9f);
+        assertEquals(0.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(1.0f, m1, 1e-9f);
+        assertEquals(1.0f, m2, 1e-9f);
+        assertEquals(1.0f, m3, 1e-9f);
+
+        cs = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+
+        m1 = cs.getMinValue(0);
+        m2 = cs.getMinValue(1);
+        m3 = cs.getMinValue(2);
+
+        assertEquals(0.0f, m1, 1e-9f);
+        assertEquals(-128.0f, m2, 1e-9f);
+        assertEquals(-128.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(100.0f, m1, 1e-9f);
+        assertEquals(128.0f, m2, 1e-9f);
+        assertEquals(128.0f, m3, 1e-9f);
+
+        cs = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+        m1 = cs.getMinValue(0);
+        m2 = cs.getMinValue(1);
+        m3 = cs.getMinValue(2);
+
+        assertEquals(-2.0f, m1, 1e-9f);
+        assertEquals(-2.0f, m2, 1e-9f);
+        assertEquals(-2.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(2.0f, m1, 1e-9f);
+        assertEquals(2.0f, m2, 1e-9f);
+        assertEquals(2.0f, m3, 1e-9f);
+    }
+
+    @Test
+    public void testMat3x3() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testMat3x3Inverse() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testMat3x3Primaries() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-5f);
+    }
+
+    @Test
+    public void testMat3x3WhitePoint() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-5f);
+        assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-5f);
+    }
+
+    @Test
+    public void testXYZFromPrimaries_xyY() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_xyY, SRGB_WHITE_POINT_xyY,
+                sIdentity, sIdentity, 0.0f, 1.0f);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testXYZFromPrimaries_XYZ() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_XYZ, SRGB_WHITE_POINT_XYZ,
+                sIdentity, sIdentity, 0.0f, 1.0f);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        // SRGB_PRIMARIES_xyY only has 1e-3 of precision, match it
+        assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-3f);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        // SRGB_WHITE_POINT_xyY only has 1e-3 of precision, match it
+        assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-3f);
+        assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-3f);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testIsSRGB() {
+        assertTrue(ColorSpace.get(ColorSpace.Named.SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.DISPLAY_P3).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.CIE_LAB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isSrgb());
+
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("My sRGB", SRGB_TO_XYZ,
+                x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f));
+        assertTrue(cs.isSrgb());
+    }
+
+    @Test
+    public void testIsWideGamut() {
+        assertFalse(ColorSpace.get(ColorSpace.Named.SRGB).isWideGamut());
+        assertFalse(ColorSpace.get(ColorSpace.Named.BT709).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.DCI_P3).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.BT2020).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.ACES).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.CIE_LAB).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isWideGamut());
+    }
+
+    @Test
+    public void testWhitePoint() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(whitePoint, Float.NaN);
+        assertArrayNotEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+        assertSame(whitePoint, cs.getWhitePoint(whitePoint));
+        assertArrayEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+    }
+
+    @Test
+    public void testPrimaries() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(primaries, Float.NaN);
+        assertArrayNotEquals(primaries, cs.getPrimaries(), 1e-5f);
+        assertSame(primaries, cs.getPrimaries(primaries));
+        assertArrayEquals(primaries, cs.getPrimaries(), 1e-5f);
+    }
+
+    @Test
+    public void testRGBtoXYZMatrix() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] rgbToXYZ = cs.getTransform();
+
+        assertNotNull(rgbToXYZ);
+        assertEquals(9, rgbToXYZ.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(rgbToXYZ, Float.NaN);
+        assertArrayNotEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+        assertSame(rgbToXYZ, cs.getTransform(rgbToXYZ));
+        assertArrayEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+    }
+
+    @Test
+    public void testXYZtoRGBMatrix() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] xyzToRGB = cs.getInverseTransform();
+
+        assertNotNull(xyzToRGB);
+        assertEquals(9, xyzToRGB.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(xyzToRGB, Float.NaN);
+        assertArrayNotEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+        assertSame(xyzToRGB, cs.getInverseTransform(xyzToRGB));
+        assertArrayEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+    }
+
+    @Test
+    public void testRGBtoXYZ() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.75f, 0.5f, 0.25f };
+        float[] expected = { 0.3012f, 0.2679f, 0.0840f };
+
+        float[] r1 = cs.toXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, cs.toXyz(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testXYZtoRGB() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.3012f, 0.2679f, 0.0840f };
+        float[] expected = { 0.75f, 0.5f, 0.25f };
+
+        float[] r1 = cs.fromXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, cs.fromXyz(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testConnect() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource());
+        assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination());
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        assertSame(connector.getDestination(), connector.getSource());
+
+        connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3));
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination());
+
+        connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.SRGB));
+        assertSame(connector.getSource(), connector.getDestination());
+    }
+
+    @Test
+    public void testConnector() {
+        // Connect color spaces with same white points
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+
+        float[] source = { 1.0f, 0.5f, 0.0f };
+        float[] expected = { 0.8912f, 0.4962f, 0.1164f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        float[] tmp = source;
+        source = expected;
+        expected = tmp;
+
+        r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        r3 = new float[] { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testAdaptedConnector() {
+        // Connect color spaces with different white points
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB));
+
+        float[] source = new float[] { 1.0f, 0.0f, 0.0f };
+        float[] expected = new float[] { 0.70226f, 0.2757f, 0.1036f };
+
+        float[] r = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r);
+        assertEquals(3, r.length);
+        assertArrayNotEquals(source, r, 1e-5f);
+        assertArrayEquals(expected, r, 1e-4f);
+    }
+
+    @Test
+    public void testAdaptedConnectorWithRenderIntent() {
+        // Connect a wider color space to a narrow color space
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.RenderIntent.RELATIVE);
+
+        float[] source = { 0.9f, 0.9f, 0.9f };
+
+        float[] relative = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(relative);
+        assertEquals(3, relative.length);
+        assertArrayNotEquals(source, relative, 1e-5f);
+        assertArrayEquals(new float[] { 0.8862f, 0.8862f, 0.8862f }, relative, 1e-4f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.RenderIntent.ABSOLUTE);
+
+        float[] absolute = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(absolute);
+        assertEquals(3, absolute.length);
+        assertArrayNotEquals(source, absolute, 1e-5f);
+        assertArrayNotEquals(relative, absolute, 1e-5f);
+        assertArrayEquals(new float[] { 0.8475f, 0.9217f, 0.8203f }, absolute, 1e-4f);
+    }
+
+    @Test
+    public void testIdentityConnector() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        assertSame(connector.getSource(), connector.getDestination());
+
+        float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f };
+
+        float[] r = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r);
+        assertEquals(3, r.length);
+        assertArrayEquals(source, r, 1e-5f);
+    }
+
+    @Test
+    public void testConnectorTransformIdentity() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        float[] source = { 1.0f, 0.0f, 0.0f };
+        float[] expected = { 1.0f, 0.0f, 0.0f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testAdaptation() {
+        ColorSpace adapted = ColorSpace.adapt(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.ILLUMINANT_D50);
+
+        float[] sRGBD50 = {
+                0.43602175f, 0.22247513f, 0.01392813f,
+                0.38510883f, 0.71690667f, 0.09710153f,
+                0.14308129f, 0.06061824f, 0.71415880f
+        };
+
+        assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f);
+    }
+
+    @Test
+    public void testImplicitSRGBConnector() {
+        ColorSpace.Connector connector1 = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector1.getDestination());
+
+        ColorSpace.Connector connector2 = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        float[] source = { 0.6f, 0.9f, 0.7f };
+        assertArrayEquals(
+                connector1.transform(source[0], source[1], source[2]),
+                connector2.transform(source[0], source[1], source[2]), 1e-7f);
+    }
+
+    @Test
+    public void testLab() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.CIE_LAB));
+
+        float[] source = { 100.0f, 0.0f, 0.0f };
+        float[] expected = { 1.0f, 1.0f, 1.0f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        source = new float[] { 100.0f, 0.0f, 54.0f };
+        expected = new float[] { 1.0f, 0.9925f, 0.5762f };
+
+        float[] r2 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(expected, r2, 1e-3f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.CIE_LAB), ColorSpace.RenderIntent.ABSOLUTE);
+
+        source = new float[] { 100.0f, 0.0f, 0.0f };
+        expected = new float[] { 1.0f, 0.9910f, 0.8651f };
+
+        r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        source = new float[] { 100.0f, 0.0f, 54.0f };
+        expected = new float[] { 1.0f, 0.9853f, 0.4652f };
+
+        r2 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(expected, r2, 1e-3f);
+    }
+
+    @Test
+    public void testXYZ() {
+        ColorSpace xyz = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+        float[] source = { 0.32f, 0.43f, 0.54f };
+
+        float[] r1 = xyz.toXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(source, r1, 1e-7f);
+
+        float[] r2 = xyz.fromXyz(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(source, r2, 1e-7f);
+
+        ColorSpace.Connector connector =
+                ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_XYZ));
+
+        float[] expected = { 0.2280f, 0.7541f, 0.8453f };
+
+        float[] r3 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r3);
+        assertEquals(3, r3.length);
+        assertArrayEquals(expected, r3, 1e-3f);
+    }
+
+    @Test
+    public void testIDs() {
+        // These cannot change
+        assertEquals(0, ColorSpace.get(ColorSpace.Named.SRGB).getId());
+        assertEquals(-1, ColorSpace.MIN_ID);
+        assertEquals(64, ColorSpace.MAX_ID);
+    }
+
+    @Test
+    public void testFromLinear() {
+        ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.0f, 0.5f, 1.0f };
+        float[] expected = { 0.0f, 0.7354f, 1.0f };
+
+        float[] r1 = colorSpace.fromLinear(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r2 = { source[0], source[1], source[2] };
+        assertSame(r2, colorSpace.fromLinear(r2));
+        assertEquals(3, r2.length);
+        assertArrayEquals(r1, r2, 1e-5f);
+    }
+
+    @Test
+    public void testToLinear() {
+        ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.0f, 0.5f, 1.0f };
+        float[] expected = new float[] { 0.0f, 0.2140f, 1.0f };
+
+        float[] r1 = colorSpace.toLinear(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r2 = new float[] { source[0], source[1], source[2] };
+        assertSame(r2, colorSpace.toLinear(r2));
+        assertEquals(3, r2.length);
+        assertArrayEquals(r1, r2, 1e-5f);
+    }
+
+    @Test
+    public void testIdempotentTransferFunctions() {
+        Arrays.stream(ColorSpace.Named.values())
+                .map(ColorSpace::get)
+                .filter(cs -> cs.getModel() == ColorSpace.Model.RGB)
+                .map(cs -> (ColorSpace.Rgb) cs)
+                .forEach(cs -> {
+                        float[] source = { 0.0f, 0.5f, 1.0f };
+                        float[] r = cs.fromLinear(cs.toLinear(source[0], source[1], source[2]));
+                        assertArrayEquals(source, r, 1e-3f);
+                });
+    }
+
+    @Test
+    public void testRendererSize() {
+        Bitmap b = ColorSpace.createRenderer()
+                .size(0)
+                .render();
+        assertEquals(128, b.getWidth());
+        assertEquals(128, b.getHeight());
+
+        b = ColorSpace.createRenderer()
+                .size(768)
+                .render();
+        assertEquals(768, b.getWidth());
+        assertEquals(768, b.getHeight());
+    }
+
+    @Test
+    public void testRenderer() {
+        Bitmap b = ColorSpace.createRenderer()
+                .size(1024)
+                .clip(true)
+                .showWhitePoint(false)
+                .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+                .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffffff)
+                .add(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), 0.1f, 0.5f, 0.1f, 0xff000000)
+                .add(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), 0.1f, 0.5f, 0.1f, 0xff000000)
+                .render();
+        assertNotNull(b);
+    }
+
+    @SuppressWarnings("SameParameterValue")
+    private static void assertArrayNotEquals(float[] a, float[] b, float eps) {
+        for (int i = 0; i < a.length; i++) {
+            if (Float.compare(a[i], b[i]) == 0 || Math.abs(a[i] - b[i]) < eps) {
+                fail("Expected " + a[i] + ", received " + b[i]);
+            }
+        }
+    }
+
+    private static void assertArrayEquals(float[] a, float[] b, float eps) {
+        for (int i = 0; i < a.length; i++) {
+            if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > eps) {
+                fail("Expected " + a[i] + ", received " + b[i]);
+            }
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
index 760e3f9..7df4360 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
@@ -15,82 +15,74 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Color;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class ColorTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    public void testAlpha(){
+@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();
     }
 
-    public void testArgb(){
+    @Test
+    public void testArgb() {
         assertEquals(Color.RED, Color.argb(0xff, 0xff, 0x00, 0x00));
         assertEquals(Color.YELLOW, Color.argb(0xff, 0xff, 0xff, 0x00));
     }
 
-    public void testBlue(){
+    @Test
+    public void testBlue() {
         assertEquals(0x00, Color.blue(Color.RED));
         assertEquals(0x00, Color.blue(Color.YELLOW));
     }
 
-    public void testGreen(){
+    @Test
+    public void testGreen() {
         assertEquals(0x00, Color.green(Color.RED));
         assertEquals(0xff, Color.green(Color.GREEN));
     }
 
-    public void testHSVToColor1(){
-        //abnormal case: hsv length less than 3
-        try{
-            float[] hsv = new float[2];
-            Color.HSVToColor(hsv);
-            fail("shouldn't come to here");
-        }catch(RuntimeException e){
-            //expected
-        }
+    @Test(expected=RuntimeException.class)
+    public void testHSVToColorArrayTooShort() {
+        // abnormal case: hsv length less than 3
+        float[] hsv = new float[2];
+        Color.HSVToColor(hsv);
+    }
 
+    @Test
+    public void testHSVToColor() {
         float[] hsv = new float[3];
         Color.colorToHSV(Color.RED, hsv);
         assertEquals(Color.RED, Color.HSVToColor(hsv));
     }
 
-    public void testHSVToColor2(){
-        //abnormal case: hsv length less than 3
-        try{
-            float[] hsv = new float[2];
-            Color.HSVToColor(hsv);
-            fail("shouldn't come to here");
-        }catch(RuntimeException e){
-            //expected
-        }
-
+    @Test
+    public void testHSVToColorWithAlpha() {
         float[] hsv = new float[3];
         Color.colorToHSV(Color.RED, hsv);
         assertEquals(Color.RED, Color.HSVToColor(0xff, hsv));
     }
 
-    public void testParseColor(){
-        //abnormal case: colorString starts with '#' but length is neither 7 nor 9
-        try{
-            Color.parseColor("#ff00ff0");
-            fail("should come to here");
-        }catch(IllegalArgumentException e){
-            //expected
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testParseColorStringOfInvalidLength() {
+        // abnormal case: colorString starts with '#' but length is neither 7 nor 9
+        Color.parseColor("#ff00ff0");
+    }
 
+    @Test
+    public void testParseColor() {
         assertEquals(Color.RED, Color.parseColor("#ff0000"));
         assertEquals(Color.RED, Color.parseColor("#ffff0000"));
 
-        //abnormal case: colorString doesn't start with '#' and is unknown color
-        try{
-            Color.parseColor("hello");
-            fail("should come to here");
-        }catch(IllegalArgumentException e){
-            //expected
-        }
-
         assertEquals(Color.BLACK, Color.parseColor("black"));
         assertEquals(Color.DKGRAY, Color.parseColor("darkgray"));
         assertEquals(Color.GRAY, Color.parseColor("gray"));
@@ -104,28 +96,45 @@
         assertEquals(Color.MAGENTA, Color.parseColor("magenta"));
     }
 
-    public void testRed(){
+    @Test(expected=IllegalArgumentException.class)
+    public void testParseColorUnsupportedFormat() {
+        // abnormal case: colorString doesn't start with '#' and is unknown color
+        Color.parseColor("hello");
+    }
+
+    @Test
+    public void testRed() {
         assertEquals(0xff, Color.red(Color.RED));
         assertEquals(0xff, Color.red(Color.YELLOW));
     }
 
-    public void testRgb(){
+    @Test
+    public void testRgb() {
         assertEquals(Color.RED, Color.rgb(0xff, 0x00, 0x00));
         assertEquals(Color.YELLOW, Color.rgb(0xff, 0xff, 0x00));
     }
 
-    public void testRGBToHSV(){
-        //abnormal case: hsv length less than 3
-        try{
-            float[] hsv = new float[2];
-            Color.RGBToHSV(0xff, 0x00, 0x00, hsv);
-            fail("shouldn't come to here");
-        }catch(RuntimeException e){
-            //expected
-        }
+    @Test(expected=RuntimeException.class)
+    public void testRGBToHSVArrayTooShort() {
+        // abnormal case: hsv length less than 3
+        float[] hsv = new float[2];
+        Color.RGBToHSV(0xff, 0x00, 0x00, hsv);
+    }
 
+    @Test
+    public void testRGBToHSV() {
         float[] hsv = new float[3];
         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/ComposePathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposePathEffectTest.java
index 35a38a3..bf11b93 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ComposePathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposePathEffectTest.java
@@ -15,6 +15,7 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -25,16 +26,24 @@
 import android.graphics.Path;
 import android.graphics.PathEffect;
 import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import junit.framework.TestCase;
 
-public class ComposePathEffectTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ComposePathEffectTest {
     private static final int BITMAP_WIDTH = 110;
     private static final int BITMAP_HEIGHT = 20;
     private static final int START_X = 10;
     private static final int END_X = BITMAP_WIDTH - 10;
     private static final int CENTER = BITMAP_HEIGHT / 2;
 
+    @Test
     public void testComposePathEffect() {
         Path path = new Path();
         path.moveTo(START_X, CENTER);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
index b44faff..8232699 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
@@ -15,8 +15,10 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -26,18 +28,21 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Shader;
-import android.graphics.Xfermode;
-import android.graphics.Bitmap.Config;
 import android.graphics.Shader.TileMode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ComposeShaderTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ComposeShaderTest {
     private static final int SIZE = 255;
     private static final int TOLERANCE = 5;
 
+    @Test
     public void testPorterDuff() {
         LinearGradient blueGradient = new LinearGradient(0, 0, SIZE, 0,
                 Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
@@ -70,6 +75,7 @@
         }
     }
 
+    @Test
     public void testXfermode() {
         Bitmap redBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
         redBitmap.eraseColor(Color.RED);
diff --git a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
index 553d05d..54cc3c0 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
@@ -15,29 +15,37 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.CornerPathEffect;
 import android.graphics.Paint;
+import android.graphics.Paint.Style;
 import android.graphics.Path;
 import android.graphics.PathEffect;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
-import android.graphics.Bitmap.Config;
-import android.graphics.Paint.Style;
-import android.graphics.PorterDuff.Mode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class CornerPathEffectTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CornerPathEffectTest {
     private static final int BITMAP_WIDTH = 100;
     private static final int BITMAP_HEIGHT = 100;
     private static final int PADDING = 10;
     private static final int RADIUS = 20;
     private static final int TOLERANCE = 5;
 
+    @Test
     public void testCornerPathEffect() {
         Path path = new Path();
         path.moveTo(0, PADDING);
diff --git a/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
index 209003b..cf1c971 100644
--- a/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
@@ -15,21 +15,27 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.DashPathEffect;
 import android.graphics.Paint;
+import android.graphics.Paint.Style;
 import android.graphics.Path;
 import android.graphics.PathEffect;
-import android.graphics.Bitmap.Config;
-import android.graphics.Paint.Style;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DashPathEffectTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DashPathEffectTest {
     private static final int BITMAP_WIDTH = 200;
     private static final int BITMAP_HEIGHT = 20;
     private static final int START_X = 10;
@@ -40,6 +46,7 @@
     private static final int BACKGROUND = Color.TRANSPARENT;
     private static final int FOREGROUND = Color.GREEN;
 
+    @Test
     public void testDashPathEffect() {
         PathEffect effect = new DashPathEffect(PATTERN, OFFSET);
         Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
diff --git a/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
index adae2ed..ee49e2b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
@@ -16,21 +16,28 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.DiscretePathEffect;
 import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Bitmap.Config;
 import android.graphics.Paint.Style;
+import android.graphics.Path;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DiscretePathEffectTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DiscretePathEffectTest {
     private static final int BITMAP_WIDTH = 200;
     private static final int BITMAP_HEIGHT = 100;
     private static final int START_X = 10;
@@ -39,6 +46,7 @@
     private static final int SEGMENT_LENGTH = 10; // must be < BITMAP_WIDTH
     private static final int DEVIATION = 10; // must be < BITMAP_HEIGHT
 
+    @Test
     public void testDiscretePathEffect() {
         DiscretePathEffect effect = new DiscretePathEffect(SEGMENT_LENGTH, DEVIATION);
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/DrawFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/DrawFilterTest.java
index c20bf0e..6766483 100644
--- a/tests/tests/graphics/src/android/graphics/cts/DrawFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/DrawFilterTest.java
@@ -16,19 +16,18 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
 import android.graphics.DrawFilter;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class DrawFilterTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawFilterTest {
+    @Test
     public void testConstructor() {
-        // new the DrawFilter instance
         new DrawFilter();
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java
index a61345a..c9a7710 100644
--- a/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java
@@ -16,19 +16,26 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.EmbossMaskFilter;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class EmbossMaskFilterTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmbossMaskFilterTest {
     private static final int BITMAP_WIDTH = 100;
     private static final int BITMAP_HEIGHT = 100;
     private static final int START_X = 10;
@@ -37,6 +44,7 @@
     private static final int CENTER_Y = BITMAP_HEIGHT / 2;
     private static final int STROKE_WIDTH = 10;
 
+    @Test
     public void testEmbossMaskFilter() {
         EmbossMaskFilter filter = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.5f, 8, 3);
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java b/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
index 9d6de44..9b6f1ef 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageViewCtsActivity.java
@@ -16,17 +16,16 @@
 
 package android.graphics.cts;
 
-import android.graphics.cts.R;
-
 import android.app.Activity;
+import android.graphics.drawable.AnimationDrawable;
 import android.os.Bundle;
 
 /**
- * A minimal application for {@link ImageView} test.
+ * A minimal application for {@link AnimationDrawable} test.
  */
 public class ImageViewCtsActivity 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/graphics/src/android/graphics/cts/InterpolatorTest.java b/tests/tests/graphics/src/android/graphics/cts/InterpolatorTest.java
index 20e419e..01dc1e9 100644
--- a/tests/tests/graphics/src/android/graphics/cts/InterpolatorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/InterpolatorTest.java
@@ -16,26 +16,41 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import junit.framework.TestCase;
+
 import android.graphics.Interpolator;
 import android.graphics.Interpolator.Result;
 import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class InterpolatorTest extends TestCase {
+import com.android.compatibility.common.util.CtsArrayUtils;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InterpolatorTest {
     private static final int DEFAULT_KEYFRAME_COUNT = 2;
     private static final float TOLERANCE = 0.1f;
 
+    @Test
     public void testConstructor() {
-        Interpolator i = new Interpolator(10);
-        assertEquals(10, i.getValueCount());
-        assertEquals(DEFAULT_KEYFRAME_COUNT, i.getKeyFrameCount());
+        Interpolator interpolator = new Interpolator(10);
+        assertEquals(10, interpolator.getValueCount());
+        assertEquals(DEFAULT_KEYFRAME_COUNT, interpolator.getKeyFrameCount());
 
-        i = new Interpolator(15, 20);
-        assertEquals(15, i.getValueCount());
-        assertEquals(20, i.getKeyFrameCount());
+        interpolator = new Interpolator(15, 20);
+        assertEquals(15, interpolator.getValueCount());
+        assertEquals(20, interpolator.getKeyFrameCount());
     }
 
+    @Test
     public void testReset1() {
         final int expected = 100;
         Interpolator interpolator = new Interpolator(10);
@@ -45,6 +60,7 @@
         assertEquals(DEFAULT_KEYFRAME_COUNT, interpolator.getKeyFrameCount());
     }
 
+    @Test
     public void testReset2() {
         int expected1 = 100;
         int expected2 = 200;
@@ -55,6 +71,7 @@
         assertEquals(expected2, interpolator.getKeyFrameCount());
     }
 
+    @Test
     public void testTimeToValues1() throws InterruptedException {
         Interpolator interpolator = new Interpolator(1);
         assertEquals(1, interpolator.getValueCount());
@@ -65,21 +82,21 @@
         // deviate more than TOLERANCE
         interpolator.setKeyFrame(0, (int)(time - 10000), new float[] {1.0f});
         interpolator.setKeyFrame(1, (int)(time + 10000), new float[] {2.0f});
-        assertValue(1.5f, Result.NORMAL, interpolator);
+        verifyValue(1.5f, Result.NORMAL, interpolator);
 
         // FREEZE_START
         interpolator.reset(1);
         time = SystemClock.uptimeMillis();
         interpolator.setKeyFrame(0, (int)(time + 1000), new float[] {2.0f});
         interpolator.setKeyFrame(1, (int)(time + 2000), new float[] {3.0f});
-        assertValue(2.0f, Result.FREEZE_START, interpolator);
+        verifyValue(2.0f, Result.FREEZE_START, interpolator);
 
         // FREEZE_END
         interpolator.reset(1);
         time = SystemClock.uptimeMillis();
         interpolator.setKeyFrame(0, (int)(time - 2000), new float[] {2.0f});
         interpolator.setKeyFrame(1, (int)(time - 1000), new float[] {3.0f});
-        assertValue(3.0f, Result.FREEZE_END, interpolator);
+        verifyValue(3.0f, Result.FREEZE_END, interpolator);
 
         final int valueCount = 2;
         interpolator.reset(valueCount);
@@ -94,25 +111,26 @@
         }
     }
 
+    @Test
     public void testTimeToValues2() {
         Interpolator interpolator = new Interpolator(1);
         interpolator.setKeyFrame(0, 2000, new float[] {1.0f});
         interpolator.setKeyFrame(1, 4000, new float[] {2.0f});
-        assertValue(1000, 1.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 1.5f, Result.NORMAL, interpolator);
-        assertValue(6000, 2.0f, Result.FREEZE_END, interpolator);
+        verifyValue(1000, 1.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue(6000, 2.0f, Result.FREEZE_END, interpolator);
 
         // known bug: time argument is unsigned 32bit in graphics library
-        assertValue(-1000, 2.0f, Result.FREEZE_END, interpolator);
+        verifyValue(-1000, 2.0f, Result.FREEZE_END, interpolator);
 
         interpolator.reset(1, 3);
         interpolator.setKeyFrame(0, 2000, new float[] {1.0f});
         interpolator.setKeyFrame(1, 4000, new float[] {2.0f});
         interpolator.setKeyFrame(2, 6000, new float[] {4.0f});
-        assertValue(0, 1.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 1.5f, Result.NORMAL, interpolator);
-        assertValue(5000, 3.0f, Result.NORMAL, interpolator);
-        assertValue(8000, 4.0f, Result.FREEZE_END, interpolator);
+        verifyValue(0, 1.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue(5000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue(8000, 4.0f, Result.FREEZE_END, interpolator);
 
 
         final int valueCount = 2;
@@ -130,41 +148,43 @@
         interpolator.reset(2, 2);
         interpolator.setKeyFrame(0, 4000, new float[] {1.0f, 1.0f});
         interpolator.setKeyFrame(1, 6000, new float[] {2.0f, 4.0f});
-        assertValues(2000, new float[] {1.0f, 1.0f}, Result.FREEZE_START, interpolator);
-        assertValues(5000, new float[] {1.5f, 2.5f}, Result.NORMAL, interpolator);
-        assertValues(8000, new float[] {2.0f, 4.0f}, Result.FREEZE_END, interpolator);
+        verifyValues(2000, new float[] {1.0f, 1.0f}, Result.FREEZE_START, interpolator);
+        verifyValues(5000, new float[] {1.5f, 2.5f}, Result.NORMAL, interpolator);
+        verifyValues(8000, new float[] {2.0f, 4.0f}, Result.FREEZE_END, interpolator);
     }
 
+    @Test
     public void testSetRepeatMirror() {
         Interpolator interpolator = new Interpolator(1, 3);
         interpolator.setKeyFrame(0, 2000, new float[] {1.0f});
         interpolator.setKeyFrame(1, 4000, new float[] {2.0f});
         interpolator.setKeyFrame(2, 6000, new float[] {4.0f});
 
-        assertValue(1000, 1.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 1.5f, Result.NORMAL, interpolator);
-        assertValue(5000, 3.0f, Result.NORMAL, interpolator);
-        assertValue(7000, 4.0f, Result.FREEZE_END, interpolator);
+        verifyValue(1000, 1.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue(5000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue(7000, 4.0f, Result.FREEZE_END, interpolator);
 
         // repeat once, no mirror
         interpolator.setRepeatMirror(2, false);
-        assertValue( 1000, 4.0f, Result.FREEZE_END, interpolator); // known bug
-        assertValue( 3000, 1.5f, Result.NORMAL, interpolator);
-        assertValue( 5000, 3.0f, Result.NORMAL, interpolator);
-        assertValue( 7000, 1.5f, Result.NORMAL, interpolator);
-        assertValue( 9000, 3.0f, Result.NORMAL, interpolator);
-        assertValue(11000, 4.0f, Result.FREEZE_END, interpolator);
+        verifyValue( 1000, 4.0f, Result.FREEZE_END, interpolator); // known bug
+        verifyValue( 3000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue( 5000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue( 7000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue( 9000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue(11000, 4.0f, Result.FREEZE_END, interpolator);
 
         // repeat once, mirror
         interpolator.setRepeatMirror(2, true);
-        assertValue( 1000, 4.0f, Result.FREEZE_END, interpolator); // known bug
-        assertValue( 3000, 1.5f, Result.NORMAL, interpolator);
-        assertValue( 5000, 3.0f, Result.NORMAL, interpolator);
-        assertValue( 7000, 3.0f, Result.NORMAL, interpolator);
-        assertValue( 9000, 1.5f, Result.NORMAL, interpolator);
-        assertValue(11000, 4.0f, Result.FREEZE_END, interpolator);
+        verifyValue( 1000, 4.0f, Result.FREEZE_END, interpolator); // known bug
+        verifyValue( 3000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue( 5000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue( 7000, 3.0f, Result.NORMAL, interpolator);
+        verifyValue( 9000, 1.5f, Result.NORMAL, interpolator);
+        verifyValue(11000, 4.0f, Result.FREEZE_END, interpolator);
     }
 
+    @Test
     public void testSetKeyFrame() {
         final float[] aZero = new float[] {0.0f};
         final float[] aOne = new float[] {1.0f};
@@ -172,9 +192,9 @@
         Interpolator interpolator = new Interpolator(1);
         interpolator.setKeyFrame(0, 2000, aZero);
         interpolator.setKeyFrame(1, 4000, aOne);
-        assertValue(1000, 0.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 0.5f, Result.NORMAL, interpolator);
-        assertValue(5000, 1.0f, Result.FREEZE_END, interpolator);
+        verifyValue(1000, 0.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 0.5f, Result.NORMAL, interpolator);
+        verifyValue(5000, 1.0f, Result.FREEZE_END, interpolator);
 
         final float[] linearBlend = new float[] {
                 0.0f, 0.0f, 1.0f, 1.0f
@@ -191,32 +211,32 @@
         // explicit linear blend should yield the same values
         interpolator.setKeyFrame(0, 2000, aZero, linearBlend);
         interpolator.setKeyFrame(1, 4000, aOne, linearBlend);
-        assertValue(1000, 0.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 0.5f, Result.NORMAL, interpolator);
-        assertValue(5000, 1.0f, Result.FREEZE_END, interpolator);
+        verifyValue(1000, 0.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 0.5f, Result.NORMAL, interpolator);
+        verifyValue(5000, 1.0f, Result.FREEZE_END, interpolator);
 
         // blend of end key frame is not used
         interpolator.setKeyFrame(0, 2000, aZero);
         interpolator.setKeyFrame(1, 4000, aOne, accelerateBlend);
-        assertValue(1000, 0.0f, Result.FREEZE_START, interpolator);
-        assertValue(3000, 0.5f, Result.NORMAL, interpolator);
-        assertValue(5000, 1.0f, Result.FREEZE_END, interpolator);
+        verifyValue(1000, 0.0f, Result.FREEZE_START, interpolator);
+        verifyValue(3000, 0.5f, Result.NORMAL, interpolator);
+        verifyValue(5000, 1.0f, Result.FREEZE_END, interpolator);
 
         final float[] result = new float[1];
 
         interpolator.setKeyFrame(0, 2000, aZero, accelerateBlend);
         interpolator.setKeyFrame(1, 4000, aOne);
-        assertValue(1000, 0.0f, Result.FREEZE_START, interpolator);
+        verifyValue(1000, 0.0f, Result.FREEZE_START, interpolator);
         assertEquals(Result.NORMAL, interpolator.timeToValues(3000, result));
         assertTrue(result[0] < 0.5f); // exact blend algorithm not known
-        assertValue(5000, 1.0f, Result.FREEZE_END, interpolator);
+        verifyValue(5000, 1.0f, Result.FREEZE_END, interpolator);
 
         interpolator.setKeyFrame(0, 2000, aZero, decelerateBlend);
         interpolator.setKeyFrame(1, 4000, aOne);
-        assertValue(1000, 0.0f, Result.FREEZE_START, interpolator);
+        verifyValue(1000, 0.0f, Result.FREEZE_START, interpolator);
         assertEquals(Result.NORMAL, interpolator.timeToValues(3000, result));
         assertTrue(result[0] > 0.5f); // exact blend algorithm not known
-        assertValue(5000, 1.0f, Result.FREEZE_END, interpolator);
+        verifyValue(5000, 1.0f, Result.FREEZE_END, interpolator);
 
         final int validTime = 0;
         final int valueCount = 2;
@@ -256,30 +276,23 @@
 
     }
 
-    private void assertValue(int time, float expected, Result expectedResult,
+    private void verifyValue(int time, float expected, Result expectedResult,
             Interpolator interpolator) {
         float[] values = new float[1];
         assertEquals(expectedResult, interpolator.timeToValues(time, values));
         assertEquals(expected, values[0], TOLERANCE);
     }
 
-    private void assertValues(int time, float[] expected, Result expectedResult,
+    private void verifyValues(int time, float[] expected, Result expectedResult,
             Interpolator interpolator) {
         float[] values = new float[expected.length];
         assertEquals(expectedResult, interpolator.timeToValues(time, values));
-        assertFloatArray(expected, values);
+        CtsArrayUtils.verifyArrayEquals(expected, values, TOLERANCE);
     }
 
-    private void assertValue(float expected, Result expectedResult, Interpolator interpolator) {
+    private void verifyValue(float expected, Result expectedResult, Interpolator interpolator) {
         float[] values = new float[1];
         assertEquals(expectedResult, interpolator.timeToValues(values));
         assertEquals(expected, values[0], TOLERANCE);
     }
-
-    private void assertFloatArray(float[] expected, float[] actual) {
-        assertEquals(expected.length, actual.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals(expected[i], actual[i], TOLERANCE);
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/Interpolator_ResultTest.java b/tests/tests/graphics/src/android/graphics/cts/Interpolator_ResultTest.java
index 6c29cda..e6fd397 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Interpolator_ResultTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Interpolator_ResultTest.java
@@ -16,19 +16,28 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Interpolator.Result;
-import android.graphics.Shader.TileMode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
+import junit.framework.TestCase;
 
-public class Interpolator_ResultTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Interpolator_ResultTest {
+    @Test
     public void testValueOf() {
         assertEquals(Result.FREEZE_START, Result.valueOf("FREEZE_START"));
         assertEquals(Result.FREEZE_END, Result.valueOf("FREEZE_END"));
         assertEquals(Result.NORMAL, Result.valueOf("NORMAL"));
     }
 
+    @Test
     public void testValues() {
         Result[] result = Result.values();
         assertEquals(3, result.length);
diff --git a/tests/tests/graphics/src/android/graphics/cts/LayerRasterizerTest.java b/tests/tests/graphics/src/android/graphics/cts/LayerRasterizerTest.java
deleted file mode 100644
index 289ee77..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/LayerRasterizerTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-package android.graphics.cts;
-
-import junit.framework.TestCase;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.LayerRasterizer;
-import android.graphics.Paint;
-import android.graphics.Rasterizer;
-
-public class LayerRasterizerTest extends TestCase {
-    private final static int BITMAP_WIDTH = 16;
-    private final static int BITMAP_HEIGHT = 16;
-
-    private void exerciseRasterizer(Rasterizer rasterizer) {
-        Bitmap bm = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bm);
-        Paint paint = new Paint();
-
-        // just want to confirm that we don't crash or throw an exception
-        paint.setRasterizer(rasterizer);
-        canvas.drawCircle(BITMAP_WIDTH/2, BITMAP_WIDTH/2, BITMAP_WIDTH/2, paint);
-    }
-
-    public void testConstructor() {
-        exerciseRasterizer(new LayerRasterizer());
-    }
-
-    public void testAddLayer1() {
-        LayerRasterizer layerRasterizer = new LayerRasterizer();
-        Paint p = new Paint();
-        layerRasterizer.addLayer(p);
-        exerciseRasterizer(layerRasterizer);
-    }
-
-    public void testAddLayer2() {
-        LayerRasterizer layerRasterizer = new LayerRasterizer();
-        layerRasterizer.addLayer(new Paint(), 1.0f, 1.0f);
-        exerciseRasterizer(layerRasterizer);
-        // explicitly add another layer and draw again
-        layerRasterizer.addLayer(new Paint(), 2.0f, 2.0f);
-        exerciseRasterizer(layerRasterizer);
-    }
-
-}
diff --git a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
index b8f28e0..365a75c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
@@ -16,20 +16,26 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.LightingColorFilter;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class LightingColorFilterTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LightingColorFilterTest {
     private static final int TOLERANCE = 2;
 
+    @Test
     public void testLightingColorFilter() {
         Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
@@ -39,37 +45,37 @@
         paint.setColor(Color.MAGENTA);
         paint.setColorFilter(new LightingColorFilter(Color.WHITE, Color.BLACK));
         canvas.drawPaint(paint);
-        assertColor(Color.MAGENTA, bitmap.getPixel(0, 0));
+        verifyColor(Color.MAGENTA, bitmap.getPixel(0, 0));
 
         paint.setColor(Color.MAGENTA);
         paint.setColorFilter(new LightingColorFilter(Color.CYAN, Color.BLACK));
         canvas.drawPaint(paint);
-        assertColor(Color.BLUE, bitmap.getPixel(0, 0));
+        verifyColor(Color.BLUE, bitmap.getPixel(0, 0));
 
         paint.setColor(Color.MAGENTA);
         paint.setColorFilter(new LightingColorFilter(Color.BLUE, Color.GREEN));
         canvas.drawPaint(paint);
-        assertColor(Color.CYAN, bitmap.getPixel(0, 0));
+        verifyColor(Color.CYAN, bitmap.getPixel(0, 0));
 
         // alpha is ignored
         bitmap.eraseColor(Color.TRANSPARENT);
         paint.setColor(Color.MAGENTA);
         paint.setColorFilter(new LightingColorFilter(Color.TRANSPARENT, Color.argb(0, 0, 0xFF, 0)));
         canvas.drawPaint(paint);
-        assertColor(Color.GREEN, bitmap.getPixel(0, 0));
+        verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
 
         // channels get clipped (no overflow into green or alpha)
         paint.setColor(Color.MAGENTA);
         paint.setColorFilter(new LightingColorFilter(Color.WHITE, Color.MAGENTA));
         canvas.drawPaint(paint);
-        assertColor(Color.MAGENTA, bitmap.getPixel(0, 0));
+        verifyColor(Color.MAGENTA, bitmap.getPixel(0, 0));
 
         // multiply before add
         paint.setColor(Color.argb(255, 60, 20, 40));
         paint.setColorFilter(
                 new LightingColorFilter(Color.rgb(0x80, 0xFF, 0x80), Color.rgb(0, 10, 10)));
         canvas.drawPaint(paint);
-        assertColor(Color.argb(255, 30, 30, 30), bitmap.getPixel(0, 0));
+        verifyColor(Color.argb(255, 30, 30, 30), bitmap.getPixel(0, 0));
 
         // source alpha remains unchanged
         bitmap.eraseColor(Color.TRANSPARENT);
@@ -77,10 +83,10 @@
         paint.setColorFilter(
                 new LightingColorFilter(Color.rgb(0x80, 0xFF, 0x80), Color.rgb(0, 10, 10)));
         canvas.drawPaint(paint);
-        assertColor(Color.argb(0x80, 30, 30, 30), bitmap.getPixel(0, 0));
+        verifyColor(Color.argb(0x80, 30, 30, 30), bitmap.getPixel(0, 0));
     }
 
-    private void assertColor(int expected, int actual) {
+    private void verifyColor(int expected, int actual) {
         assertEquals(Color.alpha(expected), Color.alpha(actual), TOLERANCE);
         assertEquals(Color.red(expected), Color.red(actual), TOLERANCE);
         assertEquals(Color.green(expected), Color.green(actual), TOLERANCE);
diff --git a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
index d44f7e3..dbec9b7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
@@ -16,18 +16,26 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.LinearGradient;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
 import android.graphics.Shader.TileMode;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class LinearGradientTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LinearGradientTest {
+    @Test
     public void testLinearGradient() {
         Bitmap b;
         LinearGradient lg;
@@ -51,7 +59,7 @@
         assertTrue(Color.red(b.getPixel(10, 20)) < Color.red(b.getPixel(10, 25)));
 
         lg = new LinearGradient(0, 0, 0, 40, Color.RED, Color.BLUE, TileMode.CLAMP);
-        b= drawLinearGradient(lg);
+        b = drawLinearGradient(lg);
 
         // The pixels in same gradient line should be equivalent
         assertEquals(b.getPixel(10, 10), b.getPixel(20, 10));
diff --git a/tests/tests/graphics/src/android/graphics/cts/MaskFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/MaskFilterTest.java
index 0a05ef3..6dfa96e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MaskFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MaskFilterTest.java
@@ -16,13 +16,18 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
 import android.graphics.MaskFilter;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class MaskFilterTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MaskFilterTest {
+    @Test
     public void testConstructor() {
-        // new the MaskFilter instance
         new MaskFilter();
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java b/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
index 29e4f5f..5f78c6c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MatrixTest.java
@@ -15,39 +15,75 @@
  */
 package android.graphics.cts;
 
-import android.graphics.Matrix;
-import android.graphics.RectF;
-import android.graphics.Matrix.ScaleToFit;
-import android.test.AndroidTestCase;
+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.junit.Assert.fail;
 
-public class MatrixTest extends AndroidTestCase {
+import android.graphics.Camera;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.RectF;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.CtsArrayUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@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 +92,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,189 +105,194 @@
         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]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, -4.0f, 0.0f, 0.0f, 1.0f });
         mMatrix.reset();
-        expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix.setScale(1f, 2f);
-        expect = "[1.0, 0.0, 0.0][0.0, 2.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
 
         mMatrix.setScale(1f, 2f, 3f, 4f);
-        expect = "[1.0, 0.0, 0.0][0.0, 2.0, -4.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, -4.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testSetRotate() {
         mMatrix.setRotate(1f);
-        String expect = "[0.9998477, -0.017452406, 0.0]"
-                + "[0.017452406, 0.9998477, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0f, 0.017452406f, 0.9998477f, 0.0f, 0.0f, 0.0f, 1.0f
+        });
     }
 
+    @Test
     public void testSetRotate2() {
         mMatrix.setRotate(1f, 2f, 3f);
-        String expect = "[0.9998477, -0.017452406, 0.0526618]"
-                + "[0.017452406, 0.9998477, -0.034447942][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0526618f, 0.017452406f, 0.9998477f, -0.034447942f, 0.0f,
+                0.0f, 1.0f
+        });
     }
 
+    @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());
+        verifyMatrix(new float[] { 2.0f, -1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 2.0f, -1.0f, 1.0f, 1.0f, 2.0f, -7.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, -4.0f, 2.0f, 1.0f, -6.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testSetConcat() {
         Matrix a = new Matrix();
         Matrix b = new Matrix();
         mMatrix.setConcat(a, b);
-        String expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix = new Matrix();
         mMatrix.setConcat(mMatrix, b);
         mMatrix.setConcat(a, b);
-        expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix = new Matrix();
         mValues = new float[9];
         mMatrix.setConcat(a, mMatrix);
         mMatrix.getValues(mValues);
-        expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, -4.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testPreRotate() {
         assertTrue(mMatrix.preRotate(1f));
-        String expect = "[0.9998477, -0.017452406, 0.0][0.017452406, 0.9998477, "
-                + "0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0f, 0.017452406f, 0.9998477f, 0.0f, 0.0f, 0.0f, 1.0f
+        });
     }
 
+    @Test
     public void testPreRotate2() {
         assertTrue(mMatrix.preRotate(1f, 2f, 3f));
         float[] values = new float[9];
         mMatrix.getValues(values);
-        String expect = "[0.9998477, -0.017452406, 0.0526618][0.017452406, 0.9998477,"
-                + " -0.034447942][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0526618f, 0.017452406f, 0.9998477f, -0.034447942f, 0.0f,
+                0.0f, 1.0f
+        });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, -4.0f, 2.0f, 1.0f, -6.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testPreConcat() {
         float[] values = new float[9];
         values[0] = 1000;
         Matrix matrix = new Matrix();
         matrix.setValues(values);
         assertTrue(mMatrix.preConcat(matrix));
-        String expect = "[1000.0, 0.0, 0.0][0.0, 0.0, 0.0][0.0, 0.0, 0.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 2.0f, -4.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testPostRotate() {
         assertTrue(mMatrix.postRotate(1f));
-        String expect = "[0.9998477, -0.017452406, 0.0]" +
-         "[0.017452406, 0.9998477, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0f, 0.017452406f, 0.9998477f, 0.0f, 0.0f, 0.0f, 1.0f
+        });
     }
 
+    @Test
     public void testPostRotate2() {
         assertTrue(mMatrix.postRotate(1f, 2f, 3f));
-        String expect = "[0.9998477, -0.017452406, 0.0526618]" +
-        "[0.017452406, 0.9998477, -0.034447942][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] {
+            0.9998477f, -0.017452406f, 0.0526618f, 0.017452406f, 0.9998477f, -0.034447942f, 0.0f,
+                0.0f, 1.0f
+        });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @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());
+        verifyMatrix(new float[] { 1.0f, 1.0f, -4.0f, 2.0f, 1.0f, -6.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test
     public void testPostConcat() {
         Matrix matrix = new Matrix();
         float[] values = new float[9];
@@ -258,63 +300,57 @@
         matrix.setValues(values);
         assertTrue(mMatrix.postConcat(matrix));
 
-        String expect = "[1000.0, 0.0, 0.0][0.0, 0.0, 0.0][0.0, 0.0, 0.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f });
     }
 
+    @Test
     public void testSetRectToRect() {
         RectF r1 = new RectF();
         r1.set(1f, 2f, 3f, 3f);
         RectF r2 = new RectF();
         r1.set(10f, 20f, 30f, 30f);
         assertTrue(mMatrix.setRectToRect(r1, r2, ScaleToFit.CENTER));
-        String expect = "[0.0, 0.0, 0.0][0.0, 0.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix.setRectToRect(r1, r2, ScaleToFit.END);
 
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix.setRectToRect(r1, r2, ScaleToFit.FILL);
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         mMatrix.setRectToRect(r1, r2, ScaleToFit.START);
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f });
 
         assertFalse(mMatrix.setRectToRect(r2, r1, ScaleToFit.CENTER));
 
-        expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         assertFalse(mMatrix.setRectToRect(r2, r1, ScaleToFit.FILL));
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         assertFalse(mMatrix.setRectToRect(r2, r1, ScaleToFit.START));
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
         assertFalse(mMatrix.setRectToRect(r2, r1, ScaleToFit.END));
-        assertEquals(expect, mMatrix.toShortString());
-
-        try {
-            mMatrix.setRectToRect(null, null, ScaleToFit.CENTER);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test(expected=Exception.class)
+    public void testSetRectToRectNull() {
+        mMatrix.setRectToRect(null, null, ScaleToFit.CENTER);
+    }
+
+    @Test
     public void testInvert() {
         Matrix matrix = new Matrix();
         float[] values = new float[9];
         values[0] = 1000f;
         matrix.setValues(values);
         assertTrue(mMatrix.invert(matrix));
-        String expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, matrix.toShortString());
-        expect = "[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
-        boolean result = false;
-        try {
-            result = mMatrix.invert(null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-        assertFalse(result);
+        verifyMatrix(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    @Test(expected=Exception.class)
+    public void testInvertNull() {
+        mMatrix.invert(null);
+    }
+
+    @Test
     public void testSetPolyToPoly() {
         float[] src = new float[9];
         src[0] = 100f;
@@ -322,143 +358,148 @@
         dst[0] = 200f;
         dst[1] = 300f;
         assertTrue(mMatrix.setPolyToPoly(src, 0, dst, 0, 1));
-        String expect = "[1.0, 0.0, 100.0][0.0, 1.0, 300.0][0.0, 0.0, 1.0]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 100.0f, 0.0f, 1.0f, 300.0f, 0.0f, 0.0f, 1.0f });
         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);
-        try {
-            mMatrix.mapPoints(null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(value[0], 100f, 0f);
     }
 
+    @Test(expected=Exception.class)
+    public void testMapPointsNull() {
+        mMatrix.mapPoints(null);
+    }
+
+    @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);
-        try {
-            mMatrix.mapPoints(new float[8], new float[9]);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(dst[0], 200f, 0f);
     }
 
-    public void testMapPoints3() {
+    @Test(expected=Exception.class)
+    public void testMapPointsArraysMismatch() {
+        mMatrix.mapPoints(new float[8], new float[9]);
+    }
+
+    @Test
+    public void testMapPointsWithIndices() {
         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);
-        try {
-            mMatrix.mapPoints(null, 0, new float[9], 0, 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(dst[0], 200f, 0f);
     }
 
+    @Test(expected=Exception.class)
+    public void testMapPointsWithIndicesNull() {
+        mMatrix.mapPoints(null, 0, new float[9], 0, 1);
+    }
+
+    @Test
     public void testMapVectors() {
         float[] values = new float[9];
-        values = new float[9];
         values[0] = 100f;
         mMatrix.mapVectors(values);
-        assertEquals(values[0], 100f);
-        try {
-            mMatrix.mapVectors(null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(values[0], 100f, 0f);
     }
 
-    public void testMapVectors2() {
+    @Test(expected=Exception.class)
+    public void testMapVectorsNull() {
+        mMatrix.mapVectors(null);
+    }
+
+    @Test
+    public void testMapVectorsDstSrc() {
         float[] src = new float[9];
         src[0] = 100f;
         float[] dst = new float[9];
         dst[0] = 200f;
         mMatrix.mapVectors(dst, src);
-        assertEquals(dst[0], 100f);
-
-        try {
-            mMatrix.mapVectors(new float[9], new float[8]);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(dst[0], 100f, 0f);
     }
 
-    public void testMapVectors3() {
+    @Test(expected=Exception.class)
+    public void testMapVectorsDstSrcMismatch() {
+        mMatrix.mapVectors(new float[9], new float[8]);
+    }
+
+    @Test
+    public void testMapVectorsDstSrcWithIndices() {
         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);
-
-        try {
-            mMatrix.mapRect(null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(1f, r.left, 0f);
+        assertEquals(2f, r.top, 0f);
+        assertEquals(3f, r.right, 0f);
+        assertEquals(4f, r.bottom, 0f);
     }
 
-    public void testMapRect2() {
+    @Test(expected=Exception.class)
+    public void testMapRectNull() {
+        mMatrix.mapRect(null);
+    }
+
+    @Test
+    public void testMapRectDstSrc() {
         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);
-
-        try {
-            mMatrix.mapRect(null, null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+        assertEquals(0f, src.left, 0f);
+        assertEquals(0f, src.top, 0f);
+        assertEquals(0f, src.right, 0f);
+        assertEquals(0f, src.bottom, 0f);
     }
 
+    @Test(expected=Exception.class)
+    public void testMapRectDstSrcNull() {
+        mMatrix.mapRect(null, null);
+    }
+
+    @Test
     public void testAccessValues() {
         Matrix matrix = new Matrix();
         mMatrix.invert(matrix);
@@ -468,29 +509,34 @@
         mMatrix.setValues(values);
         values = new float[9];
         mMatrix.getValues(values);
-        String expect = "[9.0, 100.0, 0.0][0.0, 0.0, 0.0][0.0, 0.0, 0.0]";
-        assertEquals(expect, toShortString(values));
+        CtsArrayUtils.verifyArrayEquals(new float[] {
+                9.0f, 100.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
+        }, values, 0.0f);
     }
 
-    private String toShortString(float[] values) {
-        return "[" + values[0] + ", " + values[1] + ", " + values[2] + "]["
-                + values[3] + ", " + values[4] + ", " + values[5] + "]["
-                + 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]";
-        assertEquals(expect, mMatrix.toShortString());
+        verifyMatrix(new float[] { 1.0f, 0.0f, 2.0f, 0.0f, 1.0f, 3.0f, 0.0f, 0.0f, 1.0f });
     }
 
+    private void verifyMatrix(float[] expected) {
+        if ((expected == null) || (expected.length != 9)) {
+            fail("Expected does not have 9 elements");
+        }
+        final float[] actualValues = new float[9];
+        mMatrix.getValues(actualValues);
+        CtsArrayUtils.verifyArrayEquals(expected, actualValues, 0.0f);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/Matrix_ScaleToFitTest.java b/tests/tests/graphics/src/android/graphics/cts/Matrix_ScaleToFitTest.java
index 5670740..bfab45d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Matrix_ScaleToFitTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Matrix_ScaleToFitTest.java
@@ -16,35 +16,40 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Matrix.ScaleToFit;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Matrix_ScaleToFitTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Matrix_ScaleToFitTest {
+    @Test
     public void testValues() {
         ScaleToFit[] scaleToFits = ScaleToFit.values();
         assertEquals(ScaleToFit.FILL,scaleToFits[0]);
-        assertEquals( ScaleToFit.START,scaleToFits[1]);
-        assertEquals( ScaleToFit.CENTER,scaleToFits[2]);
-        assertEquals( ScaleToFit.END,scaleToFits[3]);
+        assertEquals(ScaleToFit.START,scaleToFits[1]);
+        assertEquals(ScaleToFit.CENTER,scaleToFits[2]);
+        assertEquals(ScaleToFit.END,scaleToFits[3]);
     }
 
+    @Test
     public void testValueOf() {
         assertEquals(ScaleToFit.FILL,ScaleToFit.valueOf("FILL"));
-        assertEquals( ScaleToFit.START,ScaleToFit.valueOf("START"));
-        assertEquals( ScaleToFit.CENTER,ScaleToFit.valueOf("CENTER"));
+        assertEquals(ScaleToFit.START,ScaleToFit.valueOf("START"));
+        assertEquals(ScaleToFit.CENTER,ScaleToFit.valueOf("CENTER"));
         assertEquals(ScaleToFit.END,ScaleToFit.valueOf("END") );
     }
 
+    @Test
     public void testValueOf2() {
-        assertEquals(ScaleToFit.FILL, ScaleToFit.valueOf(ScaleToFit.class,
-                "FILL"));
-        assertEquals(ScaleToFit.START, ScaleToFit.valueOf(ScaleToFit.class,
-                "START"));
-        assertEquals(ScaleToFit.CENTER, ScaleToFit.valueOf(ScaleToFit.class,
-                "CENTER"));
-        assertEquals(ScaleToFit.END, ScaleToFit
-                .valueOf(ScaleToFit.class, "END"));
+        assertEquals(ScaleToFit.FILL, ScaleToFit.valueOf(ScaleToFit.class, "FILL"));
+        assertEquals(ScaleToFit.START, ScaleToFit.valueOf(ScaleToFit.class, "START"));
+        assertEquals(ScaleToFit.CENTER, ScaleToFit.valueOf(ScaleToFit.class, "CENTER"));
+        assertEquals(ScaleToFit.END, ScaleToFit.valueOf(ScaleToFit.class, "END"));
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/MockActivity.java b/tests/tests/graphics/src/android/graphics/cts/MockActivity.java
deleted file mode 100644
index addc6d3..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/MockActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-package android.graphics.cts;
-
-import android.app.Activity;
-
-public class MockActivity extends Activity {
-
-}
diff --git a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
index c1e7ead..f5c7aa3 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
@@ -16,6 +16,27 @@
 
 package android.graphics.cts;
 
+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.assertTrue;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Movie;
+import android.graphics.Paint;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -23,42 +44,38 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import android.content.Context;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.Canvas;
-import android.graphics.Movie;
-import android.graphics.Paint;
-import android.test.ActivityInstrumentationTestCase2;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class MovieTest {
+    private final int MOVIE = R.drawable.animated;
 
-public class MovieTest extends ActivityInstrumentationTestCase2<MockActivity> {
+    private Context mContext;
+    private Resources mResources;
     private Movie mMovie;
-    private final int MOVIE = android.graphics.cts.R.drawable.animated;
 
-    public MovieTest() {
-        super("android.graphics.cts", MockActivity.class);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mResources = mContext.getResources();
+        mMovie = mResources.getMovie(MOVIE);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mMovie = getActivity().getResources().getMovie(MOVIE);
-    }
-
+    @Test
     public void testDraw1() {
         Canvas c = new Canvas();
         Paint p = new Paint();
         mMovie.draw(c, 100, 200, p);
     }
 
+    @Test
     public void testDraw2() {
         Canvas c = new Canvas();
         mMovie.draw(c, 100, 200);
     }
 
+    @Test
     public void testDecodeFile() throws Exception {
-        mMovie = null;
-        File dbDir = getInstrumentation().getTargetContext().getDir("tests",
-                Context.MODE_PRIVATE);
+        File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE);
         File imagefile = new File(dbDir, "animated.gif");
         if (imagefile.exists()) {
             imagefile.delete();
@@ -67,31 +84,19 @@
         mMovie = Movie.decodeFile(imagefile.getPath());
         assertNotNull(mMovie);
 
-        mMovie = null;
         mMovie = Movie.decodeFile("/no file path");
         assertNull(mMovie);
     }
 
     private void writeSampleImage(File imagefile) throws Exception {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = getActivity().getResources().openRawResource(MOVIE);
-            target = new FileOutputStream(imagefile);
+        try (InputStream source = mResources.openRawResource(MOVIE);
+             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 {
-            if (source != null) {
-                source.close();
-            }
-            if (target != null) {
-                target.close();
-            }
         }
     }
 
@@ -108,29 +113,26 @@
 
     }
 
+    @Test
     public void testDecodeByteArray() throws Exception {
-        mMovie = null;
-        InputStream is = getActivity().getResources().openRawResource(MOVIE);
+        InputStream is = mResources.openRawResource(MOVIE);
         byte[] bytes = inputStreamToBytes(is);
         mMovie = Movie.decodeByteArray(bytes, 0, bytes.length);
         is.close();
         assertNotNull(mMovie);
     }
 
-    public void testDecodeStream() {
+    @Test
+    public void testDecodeStream() throws IOException {
         assertFalse(mMovie.isOpaque());
         mMovie = null;
-        try {
-            InputStream is = getActivity().getResources()
-                    .openRawResource(MOVIE);
+        try (InputStream is = mResources.openRawResource(MOVIE)) {
             mMovie = Movie.decodeStream(is);
-            is.close();
-        } catch (Exception e) {
-            fail("shouldn't throw exception");
         }
         assertNotNull(mMovie);
     }
 
+    @Test
     public void testSetTime() {
         assertTrue(mMovie.setTime(1000));
         assertFalse(mMovie.setTime(Integer.MAX_VALUE));
@@ -138,17 +140,17 @@
         assertFalse(mMovie.setTime(-1));
     }
 
+    @Test
     public void testGetMovieProperties() {
         assertEquals(1000, mMovie.duration());
         assertFalse(mMovie.isOpaque());
 
-        int expectedHeight = getActivity().getResources().getDrawable(MOVIE).getIntrinsicHeight();
-        int scaledHeight = WidgetTestUtils.convertDipToPixels(getActivity(), mMovie.height());
+        int expectedHeight = mResources.getDrawable(MOVIE).getIntrinsicHeight();
+        int scaledHeight = WidgetTestUtils.convertDipToPixels(mContext, mMovie.height());
         assertEquals(expectedHeight, scaledHeight);
 
-        int expectedWidth = getActivity().getResources().getDrawable(MOVIE).getIntrinsicWidth();
-        int scaledWidth = WidgetTestUtils.convertDipToPixels(getActivity(), mMovie.width());
+        int expectedWidth = mResources.getDrawable(MOVIE).getIntrinsicWidth();
+        int scaledWidth = WidgetTestUtils.convertDipToPixels(mContext, mMovie.width());
         assertEquals(expectedWidth, scaledWidth);
-
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
index 8b73380..2094d00 100644
--- a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
@@ -16,8 +16,11 @@
 
 package android.graphics.cts;
 
-import android.graphics.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.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -29,25 +32,32 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class NinePatchTest extends AndroidTestCase {
-    private static int ALPHA_OPAQUE = 0xFF;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NinePatchTest {
+    private static final int ALPHA_OPAQUE = 0xFF;
+    private static final String NAME = "TESTNAME";
+    private static final int WIDTH = 80;
+    private static final int HEIGTH = 120;
+    private static final int[] COLOR = new int[WIDTH * HEIGTH];
 
     private NinePatch mNinePatch;
     private Bitmap mBitmap;
     private BitmapFactory.Options mOptNoScale;
     private Resources mRes;
-    private final String NAME = "TESTNAME";
-    private final int WIDTH = 80;
-    private final int HEIGTH = 120;
-    private final int[] COLOR = new int[WIDTH * HEIGTH];
     private byte[] mChunk;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRes = getContext().getResources();
+    @Before
+    public void setup() {
+        mRes = InstrumentationRegistry.getTargetContext().getResources();
         mOptNoScale = new BitmapFactory.Options();
         mOptNoScale.inDensity = mOptNoScale.inTargetDensity = mRes.getDisplayMetrics().densityDpi;
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.opaque, mOptNoScale);
@@ -56,24 +66,49 @@
         mNinePatch = new NinePatch(mBitmap, mChunk, NAME);
     }
 
-    public void testConstructor() {
-        mNinePatch = null;
-        try {
-            mNinePatch = new NinePatch(mBitmap, new byte[2], NAME);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-        mNinePatch = new NinePatch(mBitmap, mChunk, NAME);
+    @Test(expected=Exception.class)
+    public void testConstructorTooShort() {
+        mNinePatch = new NinePatch(mBitmap, new byte[2]);
     }
 
+    @Test(expected=Exception.class)
+    public void testConstructorNamedTooShort() {
+        mNinePatch = new NinePatch(mBitmap, new byte[2], NAME);
+    }
+
+    @Test
+    public void testConstructor() {
+        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());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
     public void testIsNinePatchChunk() {
         assertTrue(NinePatch.isNinePatchChunk(mChunk));
         Bitmap bitmap = Bitmap.createBitmap(COLOR, 10, 10, Bitmap.Config.ARGB_4444);
         assertFalse(NinePatch.isNinePatchChunk(bitmap.getNinePatchChunk()));
         assertFalse(NinePatch.isNinePatchChunk(null));
-
     }
 
+    @Test
     public void testDraw() {
         Bitmap expected = BitmapFactory.decodeResource(mRes, R.drawable.scaled1, mOptNoScale);
 
@@ -82,7 +117,7 @@
         Canvas c = new Canvas(bitmap);
         RectF rectf = new RectF(0, 0, c.getWidth(), c.getHeight());
         mNinePatch.draw(c, rectf);
-        checkBitmapWithAlpha(expected, bitmap, ALPHA_OPAQUE);
+        verifyBitmapWithAlpha(expected, bitmap, ALPHA_OPAQUE);
 
         expected = BitmapFactory.decodeResource(mRes, R.drawable.scaled2, mOptNoScale);
         bitmap = Bitmap.createBitmap(expected.getWidth(), expected.getHeight(),
@@ -90,7 +125,7 @@
         c = new Canvas(bitmap);
         Rect rect = new Rect(0, 0, c.getWidth(), c.getHeight());
         mNinePatch.draw(c, rect);
-        checkBitmapWithAlpha(expected, bitmap, ALPHA_OPAQUE);
+        verifyBitmapWithAlpha(expected, bitmap, ALPHA_OPAQUE);
 
         bitmap = Bitmap.createBitmap(expected.getWidth(), expected.getHeight(),
                 Bitmap.Config.ARGB_8888);
@@ -100,7 +135,7 @@
         Paint p = new Paint();
         p.setAlpha(alpha);
         mNinePatch.draw(c, rect, p);
-        checkBitmapWithAlpha(expected, bitmap, alpha);
+        verifyBitmapWithAlpha(expected, bitmap, alpha);
 
         bitmap = Bitmap.createBitmap(expected.getWidth(), expected.getHeight(),
                 Bitmap.Config.ARGB_8888);
@@ -108,10 +143,10 @@
         rectf = new RectF(0, 0, c.getWidth(), c.getHeight());
         mNinePatch.setPaint(p);
         mNinePatch.draw(c, rectf);
-        checkBitmapWithAlpha(expected, bitmap, alpha);
+        verifyBitmapWithAlpha(expected, bitmap, alpha);
     }
 
-    private void checkBitmapWithAlpha(Bitmap expected, Bitmap bitmap, int alpha) {
+    private void verifyBitmapWithAlpha(Bitmap expected, Bitmap bitmap, int alpha) {
         assertEquals(expected.getWidth(), bitmap.getWidth());
         assertEquals(expected.getHeight(), bitmap.getHeight());
         int width = expected.getWidth();
@@ -131,6 +166,7 @@
         }
     }
 
+    @Test
     public void testHasAlpha() {
         assertFalse(mNinePatch.hasAlpha());
         assertEquals(mNinePatch.hasAlpha(), mBitmap.hasAlpha());
@@ -143,16 +179,19 @@
         assertEquals(ninePatch.hasAlpha(), bitmap.hasAlpha());
     }
 
+    @Test
     public void testGetHeight() {
         assertEquals(5, mNinePatch.getHeight());
         assertEquals(mNinePatch.getHeight(), mBitmap.getHeight());
     }
 
+    @Test
     public void testGetWidth() {
         assertEquals(5, mNinePatch.getHeight());
         assertEquals(mNinePatch.getWidth(), mBitmap.getWidth());
     }
 
+    @Test
     public void testGetDensity() {
         mBitmap.setDensity(11);
         assertEquals(11, mNinePatch.getDensity());
@@ -160,6 +199,7 @@
         assertEquals(mNinePatch.getDensity(), mBitmap.getDensity());
     }
 
+    @Test
     public void testGetTransparentRegion() {
         // no transparency in opaque bitmap
         Rect location = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
@@ -176,13 +216,13 @@
         region = mNinePatch.getTransparentRegion(location);
         assertNotNull(region);
         Rect regionBounds = region.getBounds();
-        assertBounds(regionBounds, 0, 0, 5, 5);
+        verifyBounds(regionBounds, 0, 0, 5, 5);
 
         location = new Rect(0, 0, mBitmap.getWidth() * 2, mBitmap.getHeight() * 2);
         region = mNinePatch.getTransparentRegion(location);
         assertNotNull(region);
         regionBounds = region.getBounds();
-        assertBounds(regionBounds, 0, 0, 10, 10);
+        verifyBounds(regionBounds, 0, 0, 10, 10);
 
         // transparent padding of 1px on the right side
         mBitmap = BitmapFactory.decodeResource(mRes, R.drawable.transparent_right, mOptNoScale);
@@ -194,15 +234,15 @@
         region = mNinePatch.getTransparentRegion(location);
         assertNotNull(region);
         regionBounds = region.getBounds();
-        assertBounds(regionBounds, 4, 0, 5, 5);
+        verifyBounds(regionBounds, 4, 0, 5, 5);
 
         location = new Rect(0, 0, mBitmap.getWidth() * 2, mBitmap.getHeight() * 2);
         region = mNinePatch.getTransparentRegion(location);
         regionBounds = region.getBounds();
-        assertBounds(regionBounds, 9, 0, 10, 10);
+        verifyBounds(regionBounds, 9, 0, 10, 10);
     }
 
-    private void assertBounds(Rect regionBounds, int left, int top, int right, int bottom) {
+    private void verifyBounds(Rect regionBounds, int left, int top, int right, int bottom) {
         assertEquals(left, regionBounds.left);
         assertEquals(top, regionBounds.top);
         assertEquals(right, regionBounds.right);
diff --git a/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
index 4b01916..b9a667e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/OutlineTest.java
@@ -16,17 +16,21 @@
 
 package android.graphics.cts;
 
-import android.graphics.Outline;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.test.suitebuilder.annotation.SmallTest;
-import org.junit.Test;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class OutlineTest {
     @Test
     public void testDefaults() {
@@ -40,6 +44,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 +78,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 +168,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/PaintFlagsDrawFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
index ee3ec7c..e466099 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintFlagsDrawFilterTest.java
@@ -16,41 +16,44 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Paint.Align;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Rect;
-import android.graphics.Bitmap.Config;
-import android.graphics.Paint.Align;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PaintFlagsDrawFilterTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PaintFlagsDrawFilterTest {
     private static final float TEXT_SIZE = 20;
     private static final float TEXT_X = 50;
     private static final float TEXT_Y = 50;
     private static final String TEXT = "Test";
     private static final int BITMAP_WIDTH = 100;
     private static final int BITMAP_HEIGHT = 100;
+
     private float mTextWidth;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+    @Test
     public void testPaintFlagsDrawFilter() {
-
         Bitmap bitmapWithoutFilter = drawText(null);
 
         PaintFlagsDrawFilter filter = new PaintFlagsDrawFilter(Paint.UNDERLINE_TEXT_FLAG, 0);
         Bitmap bitmapWithFilter = drawText(filter);
 
         Bitmap combined = delta(bitmapWithoutFilter, bitmapWithFilter);
-        assertUnderline(combined);
+        verifyUnderline(combined);
     }
 
     private Bitmap drawText(PaintFlagsDrawFilter filter) {
@@ -86,7 +89,7 @@
         return combinedBitmap;
     }
 
-    private void assertUnderline(Bitmap bitmap) {
+    private void verifyUnderline(Bitmap bitmap) {
         // Find smallest rectangle containing all RED pixels
         Rect rect = new Rect(BITMAP_WIDTH, BITMAP_HEIGHT, 0, 0);
         for (int y = 0; y < BITMAP_HEIGHT; y++) {
@@ -109,6 +112,7 @@
     }
 
     // Tests that FILTER_BITMAP_FLAG is handled properly.
+    @Test
     public void testPaintFlagsDrawFilter2() {
         // Create a bitmap with alternating black and white pixels.
         int kWidth = 5;
@@ -135,13 +139,13 @@
         Paint simplePaint = new Paint();
         canvas.drawBitmap(grid, 0, 0, simplePaint);
 
-        assertContainsOnlyBlackAndWhite(dst);
+        verifyContainsOnlyBlackAndWhite(dst);
 
         // Drawn with FILTER_BITMAP_FLAG, some pixels will be somewhere in between.
         Paint filterBitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
         canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
 
-        assertContainsNonBW(dst);
+        verifyContainsNonBW(dst);
 
         // Drawing with a paint that FILTER_BITMAP_FLAG set and a DrawFilter that removes
         // FILTER_BITMAP_FLAG should remove the effect of the flag, resulting in all pixels being
@@ -149,19 +153,19 @@
         canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
         canvas.drawBitmap(grid, 0, 0, filterBitmapPaint);
 
-        assertContainsOnlyBlackAndWhite(dst);
+        verifyContainsOnlyBlackAndWhite(dst);
 
         // Likewise, drawing with a DrawFilter that sets FILTER_BITMAP_FLAG should filter,
         // resulting in gray pixels.
         canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
         canvas.drawBitmap(grid, 0, 0, simplePaint);
 
-        assertContainsNonBW(dst);
+        verifyContainsNonBW(dst);
     }
 
     // Assert that at least one pixel is neither black nor white. This is used to verify that
     // filtering was done, since the original bitmap only contained black and white pixels.
-    private void assertContainsNonBW(Bitmap bitmap) {
+    private void verifyContainsNonBW(Bitmap bitmap) {
         for (int i = 0; i < bitmap.getWidth(); ++i) {
             for (int j = 0; j < bitmap.getHeight(); ++j) {
                 int color = bitmap.getPixel(i, j);
@@ -177,7 +181,7 @@
 
     // Assert that every pixel is either black or white. Used to verify that no filtering was
     // done, since the original bitmap contained only black and white pixels.
-    private void assertContainsOnlyBlackAndWhite(Bitmap bitmap) {
+    private void verifyContainsOnlyBlackAndWhite(Bitmap bitmap) {
         for (int i = 0; i < bitmap.getWidth(); ++i) {
             for (int j = 0; j < bitmap.getHeight(); ++j) {
                 int color = bitmap.getPixel(i, j);
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index bc04657..4916ffa 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -16,7 +16,13 @@
 
 package android.graphics.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 android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.ColorFilter;
 import android.graphics.MaskFilter;
 import android.graphics.Matrix;
@@ -27,23 +33,23 @@
 import android.graphics.Paint.Style;
 import android.graphics.Path;
 import android.graphics.PathEffect;
-import android.graphics.Rasterizer;
 import android.graphics.Rect;
 import android.graphics.Shader;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
 import android.graphics.Typeface;
 import android.graphics.Xfermode;
-import android.os.Build;
 import android.os.LocaleList;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannedString;
-import android.util.Log;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Locale;
 
-public class PaintTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PaintTest {
     private static final Typeface[] TYPEFACES = new Typeface[] {
             Typeface.DEFAULT,
             Typeface.DEFAULT_BOLD,
@@ -52,6 +58,7 @@
             Typeface.SERIF,
     };
 
+    @Test
     public void testConstructor() {
         new Paint();
 
@@ -61,6 +68,7 @@
         new Paint(p);
     }
 
+    @Test
     public void testBreakText() {
         String text = "HIJKLMN";
         char[] textChars = text.toCharArray();
@@ -79,44 +87,43 @@
             totalWidth += widths[i];
         }
 
-        float[] measured = new float[1];
         for (int i = 0; i < text.length(); i++) {
-            assertBreakText(text, textChars, textSpan, i, i + 1, true, totalWidth, 1, widths[i]);
+            verifyBreakText(text, textChars, textSpan, i, i + 1, true, totalWidth, 1, widths[i]);
         }
 
         // Measure empty string
-        assertBreakText(text, textChars, textSpan, 0, 0, true, totalWidth, 0, 0);
+        verifyBreakText(text, textChars, textSpan, 0, 0, true, totalWidth, 0, 0);
 
         // Measure substring from front: "HIJ"
-        assertBreakText(text, textChars, textSpan, 0, 3, true, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 0, 3, true, totalWidth,
                 3, widths[0] + widths[1] + widths[2]);
 
         // Reverse measure substring from front: "HIJ"
-        assertBreakText(text, textChars, textSpan, 0, 3, false, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 0, 3, false, totalWidth,
                 3, widths[0] + widths[1] + widths[2]);
 
         // Measure substring from back: "MN"
-        assertBreakText(text, textChars, textSpan, 5, 7, true, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 5, 7, true, totalWidth,
                 2, widths[5] + widths[6]);
 
         // Reverse measure substring from back: "MN"
-        assertBreakText(text, textChars, textSpan, 5, 7, false, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 5, 7, false, totalWidth,
                 2, widths[5] + widths[6]);
 
         // Measure substring in the middle: "JKL"
-        assertBreakText(text, textChars, textSpan, 2, 5, true, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 2, 5, true, totalWidth,
                 3, widths[2] + widths[3] + widths[4]);
 
         // Reverse measure substring in the middle: "JKL"
-        assertBreakText(text, textChars, textSpan, 2, 5, false, totalWidth,
+        verifyBreakText(text, textChars, textSpan, 2, 5, false, totalWidth,
                 3, widths[2] + widths[3] + widths[4]);
 
         // Measure substring in the middle and restrict width to the first 2 characters.
-        assertBreakText(text, textChars, textSpan, 2, 5, true, widths[2] + widths[3],
+        verifyBreakText(text, textChars, textSpan, 2, 5, true, widths[2] + widths[3],
                 2, widths[2] + widths[3]);
 
         // Reverse measure substring in the middle and restrict width to the last 2 characters.
-        assertBreakText(text, textChars, textSpan, 2, 5, false, widths[3] + widths[4],
+        verifyBreakText(text, textChars, textSpan, 2, 5, false, widths[3] + widths[4],
                 2, widths[3] + widths[4]);
 
         // a single Emoji (U+1f601)
@@ -128,23 +135,23 @@
         assertEquals(emoji.length(), p.getTextWidths(emoji, emojiWidths));
 
         // Measure substring with a cluster
-        assertBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, 0,
+        verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, 0,
                 0, 0);
 
         // Measure substring with a cluster
-        assertBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, emojiWidths[0],
+        verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, emojiWidths[0],
                 2, emojiWidths[0]);
 
         // Reverse measure substring with a cluster
-        assertBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, 0,
+        verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, 0,
                 0, 0);
 
         // Measure substring with a cluster
-        assertBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, emojiWidths[0],
+        verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, emojiWidths[0],
                 2, emojiWidths[0]);
     }
 
-    private void assertBreakText(String text, char[] textChars, SpannedString textSpan,
+    private void verifyBreakText(String text, char[] textChars, SpannedString textSpan,
             int start, int end, boolean measureForwards, float maxWidth, int expectedCount,
             float expectedWidth) {
         Paint p = new Paint();
@@ -169,17 +176,17 @@
                 measured[2]));
 
         for (int i = 0; i < measured.length; i++) {
-            assertEquals("i: " + i, expectedWidth, measured[i][0]);
+            assertEquals("i: " + i, expectedWidth, measured[i][0], 0.0f);
         }
     }
 
+    @Test
     public void testSet() {
         Paint p  = new Paint();
         Paint p2 = new Paint();
         ColorFilter c = new ColorFilter();
         MaskFilter m  = new MaskFilter();
         PathEffect e  = new PathEffect();
-        Rasterizer r  = new Rasterizer();
         Shader s      = new Shader();
         Typeface t    = Typeface.DEFAULT;
         Xfermode x = new Xfermode();
@@ -187,7 +194,6 @@
         p.setColorFilter(c);
         p.setMaskFilter(m);
         p.setPathEffect(e);
-        p.setRasterizer(r);
         p.setShader(s);
         p.setTypeface(t);
         p.setXfermode(x);
@@ -195,7 +201,6 @@
         assertEquals(c, p2.getColorFilter());
         assertEquals(m, p2.getMaskFilter());
         assertEquals(e, p2.getPathEffect());
-        assertEquals(r, p2.getRasterizer());
         assertEquals(s, p2.getShader());
         assertEquals(t, p2.getTypeface());
         assertEquals(x, p2.getXfermode());
@@ -204,7 +209,6 @@
         assertEquals(c, p2.getColorFilter());
         assertEquals(m, p2.getMaskFilter());
         assertEquals(e, p2.getPathEffect());
-        assertEquals(r, p2.getRasterizer());
         assertEquals(s, p2.getShader());
         assertEquals(t, p2.getTypeface());
         assertEquals(x, p2.getXfermode());
@@ -212,7 +216,6 @@
         p.setColorFilter(null);
         p.setMaskFilter(null);
         p.setPathEffect(null);
-        p.setRasterizer(null);
         p.setShader(null);
         p.setTypeface(null);
         p.setXfermode(null);
@@ -220,7 +223,6 @@
         assertNull(p2.getColorFilter());
         assertNull(p2.getMaskFilter());
         assertNull(p2.getPathEffect());
-        assertNull(p2.getRasterizer());
         assertNull(p2.getShader());
         assertNull(p2.getTypeface());
         assertNull(p2.getXfermode());
@@ -229,12 +231,12 @@
         assertNull(p2.getColorFilter());
         assertNull(p2.getMaskFilter());
         assertNull(p2.getPathEffect());
-        assertNull(p2.getRasterizer());
         assertNull(p2.getShader());
         assertNull(p2.getTypeface());
         assertNull(p2.getXfermode());
     }
 
+    @Test
     public void testAccessStrokeCap() {
         Paint p = new Paint();
 
@@ -246,15 +248,16 @@
 
         p.setStrokeCap(Cap.SQUARE);
         assertEquals(Cap.SQUARE, p.getStrokeCap());
-
-        try {
-            p.setStrokeCap(null);
-            fail("Should throw an Exception");
-        } catch (RuntimeException e) {
-            //except here
-        }
     }
 
+    @Test(expected=RuntimeException.class)
+    public void testSetStrokeCapNull() {
+        Paint p = new Paint();
+
+        p.setStrokeCap(null);
+    }
+
+    @Test
     public void testAccessXfermode() {
         Paint p = new Paint();
         Xfermode x = new Xfermode();
@@ -266,6 +269,7 @@
         assertNull(p.getXfermode());
     }
 
+    @Test
     public void testAccessShader() {
         Paint p = new Paint();
         Shader s = new Shader();
@@ -277,6 +281,7 @@
         assertNull(p.getShader());
     }
 
+    @Test
     public void testShaderLocalMatrix() {
         int width = 80;
         int height = 120;
@@ -306,6 +311,7 @@
         assertEquals(m, m3);
     }
 
+    @Test
     public void testSetAntiAlias() {
         Paint p = new Paint();
 
@@ -314,10 +320,9 @@
 
         p.setAntiAlias(false);
         assertFalse(p.isAntiAlias());
-
     }
 
-
+    @Test
     public void testAccessTypeface() {
         Paint p = new Paint();
 
@@ -334,6 +339,7 @@
         assertNull(p.getTypeface());
     }
 
+    @Test
     public void testAccessPathEffect() {
         Paint p = new Paint();
         PathEffect e = new PathEffect();
@@ -345,6 +351,7 @@
         assertNull(p.getPathEffect());
     }
 
+    @Test
     public void testSetFakeBoldText() {
         Paint p = new Paint();
 
@@ -355,6 +362,7 @@
         assertFalse(p.isFakeBoldText());
     }
 
+    @Test
     public void testAccessStrokeJoin() {
         Paint p = new Paint();
 
@@ -366,15 +374,16 @@
 
         p.setStrokeJoin(Join.ROUND);
         assertEquals(Join.ROUND, p.getStrokeJoin());
-
-        try {
-            p.setStrokeJoin(null);
-            fail("Should throw an Exception");
-        } catch (RuntimeException e) {
-            //except here
-        }
     }
 
+    @Test(expected=RuntimeException.class)
+    public void testSetStrokeJoinNull() {
+        Paint p = new Paint();
+
+        p.setStrokeJoin(null);
+    }
+
+    @Test
     public void testAccessStyle() {
         Paint p = new Paint();
 
@@ -386,15 +395,16 @@
 
         p.setStyle(Style.STROKE);
         assertEquals(Style.STROKE, p.getStyle());
-
-        try {
-            p.setStyle(null);
-            fail("Should throw an Exception");
-        } catch (RuntimeException e) {
-            //except here
-        }
     }
 
+    @Test(expected=RuntimeException.class)
+    public void testSetStyleNull() {
+        Paint p = new Paint();
+
+        p.setStyle(null);
+    }
+
+    @Test
     public void testGetFontSpacing() {
         Paint p = new Paint();
 
@@ -411,6 +421,7 @@
         }
     }
 
+    @Test
     public void testSetSubpixelText() {
         Paint p = new Paint();
 
@@ -421,20 +432,22 @@
         assertFalse(p.isSubpixelText());
     }
 
+    @Test
     public void testAccessTextScaleX() {
         Paint p = new Paint();
 
         p.setTextScaleX(2.0f);
-        assertEquals(2.0f, p.getTextScaleX());
+        assertEquals(2.0f, p.getTextScaleX(), 0.0f);
 
         p.setTextScaleX(1.0f);
-        assertEquals(1.0f, p.getTextScaleX());
+        assertEquals(1.0f, p.getTextScaleX(), 0.0f);
 
         p.setTextScaleX(0.0f);
-        assertEquals(0.0f, p.getTextScaleX());
+        assertEquals(0.0f, p.getTextScaleX(), 0.0f);
 
     }
 
+    @Test
     public void testAccessMaskFilter() {
         Paint p = new Paint();
         MaskFilter m = new MaskFilter();
@@ -446,6 +459,7 @@
         assertNull(p.getMaskFilter());
     }
 
+    @Test
     public void testAccessColorFilter() {
         Paint p = new Paint();
         ColorFilter c = new ColorFilter();
@@ -457,17 +471,7 @@
         assertNull(p.getColorFilter());
     }
 
-    public void testAccessRasterizer() {
-        Paint p = new Paint();
-        Rasterizer r = new Rasterizer();
-
-        assertEquals(r, p.setRasterizer(r));
-        assertEquals(r, p.getRasterizer());
-
-        assertNull(p.setRasterizer(null));
-        assertNull(p.getRasterizer());
-    }
-
+    @Test
     public void testSetARGB() {
         Paint p = new Paint();
 
@@ -476,9 +480,9 @@
 
         p.setARGB(3, 3, 3, 3);
         assertEquals((3 << 24) | (3 << 16) | (3 << 8) | 3, p.getColor());
-
     }
 
+    @Test
     public void testAscent() {
         Paint p = new Paint();
 
@@ -495,58 +499,61 @@
         }
     }
 
+    @Test
     public void testAccessTextSkewX() {
         Paint p = new Paint();
 
         p.setTextSkewX(1.0f);
-        assertEquals(1.0f, p.getTextSkewX());
+        assertEquals(1.0f, p.getTextSkewX(), 0.0f);
 
         p.setTextSkewX(0.0f);
-        assertEquals(0.0f, p.getTextSkewX());
+        assertEquals(0.0f, p.getTextSkewX(), 0.0f);
 
         p.setTextSkewX(-0.25f);
-        assertEquals(-0.25f, p.getTextSkewX());
+        assertEquals(-0.25f, p.getTextSkewX(), 0.0f);
     }
 
+    @Test
     public void testAccessTextSize() {
         Paint p = new Paint();
 
         p.setTextSize(1.0f);
-        assertEquals(1.0f, p.getTextSize());
+        assertEquals(1.0f, p.getTextSize(), 0.0f);
 
         p.setTextSize(2.0f);
-        assertEquals(2.0f, p.getTextSize());
+        assertEquals(2.0f, p.getTextSize(), 0.0f);
 
         // text size should be greater than 0, so set -1 has no effect
         p.setTextSize(-1.0f);
-        assertEquals(2.0f, p.getTextSize());
+        assertEquals(2.0f, p.getTextSize(), 0.0f);
 
         // text size should be greater than or equals to 0
         p.setTextSize(0.0f);
-        assertEquals(0.0f, p.getTextSize());
+        assertEquals(0.0f, p.getTextSize(), 0.0f);
     }
 
+    @Test
     public void testGetTextWidths() throws Exception {
         String text = "HIJKLMN";
         char[] textChars = text.toCharArray();
         SpannedString textSpan = new SpannedString(text);
 
         // Test measuring the widths of the entire text
-        assertGetTextWidths(text, textChars, textSpan, 0, 7);
+        verifyGetTextWidths(text, textChars, textSpan, 0, 7);
 
         // Test measuring a substring of the text
-        assertGetTextWidths(text, textChars, textSpan, 1, 3);
+        verifyGetTextWidths(text, textChars, textSpan, 1, 3);
 
         // Test measuring a substring of zero length.
-        assertGetTextWidths(text, textChars, textSpan, 3, 3);
+        verifyGetTextWidths(text, textChars, textSpan, 3, 3);
 
         // Test measuring substrings from the front and back
-        assertGetTextWidths(text, textChars, textSpan, 0, 2);
-        assertGetTextWidths(text, textChars, textSpan, 4, 7);
+        verifyGetTextWidths(text, textChars, textSpan, 0, 2);
+        verifyGetTextWidths(text, textChars, textSpan, 4, 7);
     }
 
     /** Tests all four overloads of getTextWidths are the same. */
-    private void assertGetTextWidths(String text, char[] textChars, SpannedString textSpan,
+    private void verifyGetTextWidths(String text, char[] textChars, SpannedString textSpan,
             int start, int end) {
         Paint p = new Paint();
         int count = end - start;
@@ -565,12 +572,13 @@
 
         // Check that the widths returned by the overloads are the same.
         for (int i = 0; i < count; i++) {
-            assertEquals(widths[0][i], widths[1][i]);
-            assertEquals(widths[1][i], widths[2][i]);
-            assertEquals(widths[2][i], widths[3][i]);
+            assertEquals(widths[0][i], widths[1][i], 0.0f);
+            assertEquals(widths[1][i], widths[2][i], 0.0f);
+            assertEquals(widths[2][i], widths[3][i], 0.0f);
         }
     }
 
+    @Test
     public void testSetStrikeThruText() {
         Paint p = new Paint();
 
@@ -581,6 +589,7 @@
         assertFalse(p.isStrikeThruText());
     }
 
+    @Test
     public void testAccessTextAlign() {
         Paint p = new Paint();
 
@@ -594,6 +603,7 @@
         assertEquals(Align.RIGHT, p.getTextAlign());
     }
 
+    @Test
     public void testAccessTextLocale() {
         Paint p = new Paint();
 
@@ -623,16 +633,16 @@
         p.setTextLocale(defaultLocale);
         assertEquals(defaultLocale, p.getTextLocale());
         assertEquals(new LocaleList(defaultLocale), p.getTextLocales());
-
-        // Check that we cannot pass a null locale
-        try {
-            p.setTextLocale(null);
-            fail("Setting the text locale to null should throw");
-        } catch (Throwable e) {
-            assertEquals(IllegalArgumentException.class, e.getClass());
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetTextLocaleNull() {
+        Paint p = new Paint();
+
+        p.setTextLocale(null);
+    }
+
+    @Test
     public void testAccessTextLocales() {
         Paint p = new Paint();
 
@@ -654,24 +664,25 @@
         // Check reverting back to default
         p.setTextLocales(defaultLocales);
         assertEquals(defaultLocales, p.getTextLocales());
-
-        // Check that we cannot pass a null locale list
-        try {
-            p.setTextLocales(null);
-            fail("Setting the text locale list to null should throw");
-        } catch (Throwable e) {
-            assertEquals(IllegalArgumentException.class, e.getClass());
-        }
-
-        // Check that we cannot pass an empty locale list
-        try {
-            p.setTextLocales(new LocaleList());
-            fail("Setting the text locale list to an empty list should throw");
-        } catch (Throwable e) {
-            assertEquals(IllegalArgumentException.class, e.getClass());
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testAccessTextLocalesNull() {
+        Paint p = new Paint();
+
+        // Check that we cannot pass a null locale list
+        p.setTextLocales(null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testAccessTextLocalesEmpty() {
+        Paint p = new Paint();
+
+        // Check that we cannot pass an empty locale list
+        p.setTextLocales(new LocaleList());
+    }
+
+    @Test
     public void testGetFillPath() {
         Paint p = new Paint();
         Path path1 = new Path();
@@ -684,9 +695,9 @@
         assertTrue(path2.isEmpty());
 
         // No setter
-
     }
 
+    @Test
     public void testAccessAlpha() {
         Paint p = new Paint();
 
@@ -705,6 +716,7 @@
         assertEquals(236, p.getAlpha());
     }
 
+    @Test
     public void testSetFilterBitmap() {
         Paint p = new Paint();
 
@@ -715,6 +727,7 @@
         assertFalse(p.isFilterBitmap());
     }
 
+    @Test
     public void testAccessColor() {
         Paint p = new Paint();
 
@@ -734,10 +747,12 @@
         assertEquals(256, p.getColor());
     }
 
+    @Test
     public void testSetShadowLayer() {
         new Paint().setShadowLayer(10, 1, 1, 0);
     }
 
+    @Test
     public void testGetFontMetrics1() {
         Paint p = new Paint();
         Paint.FontMetrics fm = new Paint.FontMetrics();
@@ -746,17 +761,18 @@
             p.setTypeface(typeface);
 
             p.setTextSize(10);
-            float spacing10 = p.getFontMetrics(fm);
-            assertEquals(p.ascent(), fm.ascent);
-            assertEquals(p.descent(), fm.descent);
+            p.getFontMetrics(fm);
+            assertEquals(p.ascent(), fm.ascent, 0.0f);
+            assertEquals(p.descent(), fm.descent, 0.0f);
 
             p.setTextSize(20);
-            float spacing20 = p.getFontMetrics(fm);
-            assertEquals(p.ascent(), fm.ascent);
-            assertEquals(p.descent(), fm.descent);
+            p.getFontMetrics(fm);
+            assertEquals(p.ascent(), fm.ascent, 0.0f);
+            assertEquals(p.descent(), fm.descent, 0.0f);
         }
     }
 
+    @Test
     public void testGetFontMetrics2() {
         Paint p = new Paint();
 
@@ -765,34 +781,37 @@
 
             p.setTextSize(10);
             Paint.FontMetrics fm = p.getFontMetrics();
-            assertEquals(p.ascent(), fm.ascent);
-            assertEquals(p.descent(), fm.descent);
+            assertEquals(p.ascent(), fm.ascent, 0.0f);
+            assertEquals(p.descent(), fm.descent, 0.0f);
 
             p.setTextSize(20);
             fm = p.getFontMetrics();
-            assertEquals(p.ascent(), fm.ascent);
-            assertEquals(p.descent(), fm.descent);
+            assertEquals(p.ascent(), fm.ascent, 0.0f);
+            assertEquals(p.descent(), fm.descent, 0.0f);
         }
     }
 
+    @Test
     public void testAccessStrokeMiter() {
         Paint p = new Paint();
 
         p.setStrokeMiter(0.0f);
-        assertEquals(0.0f, p.getStrokeMiter());
+        assertEquals(0.0f, p.getStrokeMiter(), 0.0f);
 
         p.setStrokeMiter(10.0f);
-        assertEquals(10.0f, p.getStrokeMiter());
+        assertEquals(10.0f, p.getStrokeMiter(), 0.0f);
 
         // set value should be greater or equal to 0, set to -10.0f has no effect
         p.setStrokeMiter(-10.0f);
-        assertEquals(10.0f, p.getStrokeMiter());
+        assertEquals(10.0f, p.getStrokeMiter(), 0.0f);
     }
 
+    @Test
     public void testClearShadowLayer() {
         new Paint().clearShadowLayer();
     }
 
+    @Test
     public void testSetUnderlineText() {
         Paint p = new Paint();
 
@@ -803,6 +822,7 @@
         assertFalse(p.isUnderlineText());
     }
 
+    @Test
     public void testSetDither() {
         Paint p = new Paint();
 
@@ -813,6 +833,7 @@
         assertFalse(p.isDither());
     }
 
+    @Test
     public void testDescent() {
         Paint p = new Paint();
 
@@ -829,6 +850,7 @@
         }
     }
 
+    @Test
     public void testAccessFlags() {
         Paint p = new Paint();
 
@@ -839,20 +861,22 @@
         assertEquals(Paint.DEV_KERN_TEXT_FLAG, p.getFlags());
     }
 
+    @Test
     public void testAccessStrokeWidth() {
         Paint p = new Paint();
 
         p.setStrokeWidth(0.0f);
-        assertEquals(0.0f, p.getStrokeWidth());
+        assertEquals(0.0f, p.getStrokeWidth(), 0.0f);
 
         p.setStrokeWidth(10.0f);
-        assertEquals(10.0f, p.getStrokeWidth());
+        assertEquals(10.0f, p.getStrokeWidth(), 0.0f);
 
         // set value must greater or equal to 0, set -10.0f has no effect
         p.setStrokeWidth(-10.0f);
-        assertEquals(10.0f, p.getStrokeWidth());
+        assertEquals(10.0f, p.getStrokeWidth(), 0.0f);
     }
 
+    @Test
     public void testSetFontFeatureSettings() {
         Paint p = new Paint();
         // Roboto font (system default) has "fi" ligature
@@ -860,7 +884,7 @@
         float[] widths = new float[text.length()];
         p.getTextWidths(text, widths);
         assertTrue(widths[0] > 0.0f);
-        assertEquals(0.0f, widths[1]);
+        assertEquals(0.0f, widths[1], 0.0f);
 
         // Disable ligature using OpenType feature
         p.setFontFeatureSettings("'liga' off");
@@ -872,9 +896,10 @@
         p.setFontFeatureSettings("'liga' on");
         p.getTextWidths(text, widths);
         assertTrue(widths[0] > 0.0f);
-        assertEquals(0.0f, widths[1]);
+        assertEquals(0.0f, widths[1], 0.0f);
     }
 
+    @Test
     public void testGetTextBounds() {
         Paint p = new Paint();
         p.setTextSize(10);
@@ -904,12 +929,12 @@
         assertTrue(bounds2.bottom - bounds2.top > bounds1.bottom - bounds1.top);
     }
 
+    @Test
     public void testReset() {
         Paint p  = new Paint();
         ColorFilter c = new ColorFilter();
         MaskFilter m  = new MaskFilter();
         PathEffect e  = new PathEffect();
-        Rasterizer r  = new Rasterizer();
         Shader s      = new Shader();
         Typeface t    = Typeface.DEFAULT;
         Xfermode x = new Xfermode();
@@ -917,7 +942,6 @@
         p.setColorFilter(c);
         p.setMaskFilter(m);
         p.setPathEffect(e);
-        p.setRasterizer(r);
         p.setShader(s);
         p.setTypeface(t);
         p.setXfermode(x);
@@ -925,7 +949,6 @@
         assertEquals(c, p.getColorFilter());
         assertEquals(m, p.getMaskFilter());
         assertEquals(e, p.getPathEffect());
-        assertEquals(r, p.getRasterizer());
         assertEquals(s, p.getShader());
         assertEquals(t, p.getTypeface());
         assertEquals(x, p.getXfermode());
@@ -936,12 +959,12 @@
         assertEquals(null, p.getColorFilter());
         assertEquals(null, p.getMaskFilter());
         assertEquals(null, p.getPathEffect());
-        assertEquals(null, p.getRasterizer());
         assertEquals(null, p.getShader());
         assertEquals(null, p.getTypeface());
         assertEquals(null, p.getXfermode());
     }
 
+    @Test
     public void testSetLinearText() {
         Paint p = new Paint();
 
@@ -952,6 +975,7 @@
         assertFalse(p.isLinearText());
     }
 
+    @Test
     public void testGetFontMetricsInt1() {
         Paint p = new Paint();
         Paint.FontMetricsInt fmi = new Paint.FontMetricsInt();
@@ -971,6 +995,7 @@
         }
     }
 
+    @Test
     public void testGetFontMetricsInt2() {
         Paint p = new Paint();
         Paint.FontMetricsInt fmi;
@@ -990,6 +1015,7 @@
         }
     }
 
+    @Test
     public void testMeasureText() {
         String text = "HIJKLMN";
         char[] textChars = text.toCharArray();
@@ -1011,19 +1037,20 @@
         }
 
         // Test measuring the widths of the entire text
-        assertMeasureText(text, textChars, textSpan, 0, 7, totalWidth);
+        verifyMeasureText(text, textChars, textSpan, 0, 7, totalWidth);
 
         // Test measuring a substring of the text
-        assertMeasureText(text, textChars, textSpan, 1, 3, widths[1] + widths[2]);
+        verifyMeasureText(text, textChars, textSpan, 1, 3, widths[1] + widths[2]);
 
         // Test measuring a substring of zero length.
-        assertMeasureText(text, textChars, textSpan, 3, 3, 0);
+        verifyMeasureText(text, textChars, textSpan, 3, 3, 0);
 
         // Test measuring substrings from the front and back
-        assertMeasureText(text, textChars, textSpan, 0, 2, widths[0] + widths[1]);
-        assertMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]);
+        verifyMeasureText(text, textChars, textSpan, 0, 2, widths[0] + widths[1]);
+        verifyMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]);
     }
 
+    @Test
     public void testMeasureTextContext() {
        Paint p = new Paint();
        // Arabic LAM, which is different width depending on context
@@ -1033,17 +1060,13 @@
        SpannedString longSpanned = new SpannedString(longString);
        float width = p.measureText(shortString);
        // Verify that measurement of substring is consistent no matter what surrounds it.
-       assertMeasureText(longString, longChars, longSpanned, 0, 1, width);
-       assertMeasureText(longString, longChars, longSpanned, 1, 2, width);
-       assertMeasureText(longString, longChars, longSpanned, 2, 3, width);
+       verifyMeasureText(longString, longChars, longSpanned, 0, 1, width);
+       verifyMeasureText(longString, longChars, longSpanned, 1, 2, width);
+       verifyMeasureText(longString, longChars, longSpanned, 2, 3, width);
     }
 
+    @Test
     public void testMeasureTextWithLongText() {
-        // This test is not compatible with 4.0.3
-        if ("4.0.3".equals(Build.VERSION.RELEASE)) {
-            return;
-        }
-
         final int MAX_COUNT = 65535;
         char[] longText = new char[MAX_COUNT];
         for (int n = 0; n < MAX_COUNT; n++) {
@@ -1056,7 +1079,7 @@
     }
 
     /** Tests that all four overloads of measureText are the same and match some value. */
-    private void assertMeasureText(String text, char[] textChars, SpannedString textSpan,
+    private void verifyMeasureText(String text, char[] textChars, SpannedString textSpan,
             int start, int end, float expectedWidth) {
         Paint p = new Paint();
 
@@ -1073,75 +1096,69 @@
         widths[3] = p.measureText(text, start, end);
 
         // Check that the widths returned by the overloads are the same.
-        assertEquals(widths[0], widths[1]);
-        assertEquals(widths[1], widths[2]);
-        assertEquals(widths[2], widths[3]);
-        assertEquals(widths[3], expectedWidth);
+        assertEquals(widths[0], widths[1], 0.0f);
+        assertEquals(widths[1], widths[2], 0.0f);
+        assertEquals(widths[2], widths[3], 0.0f);
+        assertEquals(widths[3], expectedWidth, 0.0f);
     }
 
-    public void testGetTextPath1() {
-        Paint p = new Paint();
-        char[] chars = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
+    @Test
+    public void testGetTextPathCharArray() {
         Path path = new Path();
 
         assertTrue(path.isEmpty());
-        p.getTextPath(chars, 0, 7, 0, 0, path);
+        new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, 7, 0, 0, path);
         assertFalse(path.isEmpty());
-
-        try {
-            p.getTextPath(chars, -2, 7, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
-        try {
-            p.getTextPath(chars, 0, -3, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
-        try {
-            p.getTextPath(chars, 3, 7, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
     }
 
-    public void testGetTextPath2() {
-        Paint p = new Paint();
-        String string = "HIJKLMN";
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathCharArrayNegativeIndex() {
+        new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, -2, 7, 0, 0,
+                new Path());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathCharArrayNegativeCount() {
+        new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, -3, 0, 0,
+                new Path());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathCharArrayCountTooHigh() {
+        new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 3, 7, 0, 0,
+                new Path());
+    }
+
+    @Test
+    public void testGetTextPathString() {
         Path path = new Path();
 
         assertTrue(path.isEmpty());
-        p.getTextPath(string, 0, 7, 0, 0, path);
+        new Paint().getTextPath("HIJKLMN", 0, 7, 0, 0, path);
         assertFalse(path.isEmpty());
-
-        try {
-            p.getTextPath(string, -2, 7, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
-        try {
-            p.getTextPath(string, 0, -3, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
-        try {
-            p.getTextPath(string, 7, 3, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
-
-        try {
-            p.getTextPath(string, 3, 9, 0, 0, path);
-            fail("Should throw an exception here");
-        } catch (RuntimeException e) {
-        }
     }
 
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathStringNegativeIndex() {
+        new Paint().getTextPath("HIJKLMN", -2, 7, 0, 0, new Path());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathStringNegativeCount() {
+        new Paint().getTextPath("HIJKLMN", 0, -3, 0, 0, new Path());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathStringStartTooHigh() {
+        new Paint().getTextPath("HIJKLMN", 7, 3, 0, 0, new Path());
+    }
+
+    @Test(expected=RuntimeException.class)
+    public void testGetTextPathStringCountTooHigh() {
+        new Paint().getTextPath("HIJKLMN", 3, 9, 0, 0, new Path());
+    }
+
+    @Test
     public void testHasGlyph() {
         Paint p = new Paint();
 
@@ -1183,9 +1200,9 @@
         // whether VS is present or not.
         assertTrue(p.hasGlyph("\uD83D\uDC69\u200D\u2695") ==  // WOMAN, ZWJ, STAFF OF AESCULAPIUS
                 p.hasGlyph("\uD83D\uDC69\u200D\u2695\uFE0F"));  // above + VS16
-
     }
 
+    @Test
     public void testGetRunAdvance() {
         Paint p = new Paint();
         {
@@ -1194,13 +1211,13 @@
             {
                 final float width = p.getRunAdvance(string, 0, string.length(), 0,
                         string.length(), false, 0);
-                assertEquals(0.0f, width);
+                assertEquals(0.0f, width, 0.0f);
             }
             {
                 for (int i = 0; i < string.length(); i++) {
                     final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
                             false, i);
-                    assertEquals(0.0f, width);
+                    assertEquals(0.0f, width, 0.0f);
                 }
             }
             {
@@ -1234,13 +1251,13 @@
             {
                 final float width = p.getRunAdvance(string, 0, string.length(), 0,
                         string.length(), true, 0);
-                assertEquals(0.0f, width);
+                assertEquals(0.0f, width, 0.0f);
             }
             {
                 for (int i = 0; i < string.length(); i++) {
                     final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
                             true, i);
-                    assertEquals(0.0f, width);
+                    assertEquals(0.0f, width, 0.0f);
                 }
             }
             {
@@ -1261,78 +1278,67 @@
         }
     }
 
-    public void testGetRunAdvance_invalidArguments() {
-        Paint p = new Paint();
-        try {
-            p.getRunAdvance((CharSequence)null, 0, 0, 0, 0, false, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        } catch (Exception e) {
-            fail("Should throw an IllegalArgumentException.");
-        }
-
-        try {
-            p.getRunAdvance((char[])null, 0, 0, 0, 0, false, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        } catch (Exception e) {
-            fail("Should throw an IllegalArgumentException.");
-        }
-
-        final String string = "abcde";
-
-        try {
-            // text length < context end
-            p.getRunAdvance(string, 0, string.length(), 0, string.length() + 1, false,
-                    string.length());
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-        try {
-            // context end < end
-            p.getRunAdvance(string, 0, string.length(), 0, string.length() - 1, false, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-        try {
-            // end < offset
-            p.getRunAdvance(string, 0, string.length() - 1, 0, string.length() - 1, false,
-                    string.length());
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-        try {
-            // offset < start
-            p.getRunAdvance(string, 1, string.length(), 1, string.length(), false, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-        try {
-            // start < context start
-            p.getRunAdvance(string, 0, string.length(), 1, string.length(), false, 1);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-        try {
-            // context start < 0
-            p.getRunAdvance(string, 0, string.length(), -1, string.length(), false, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetRunAdvanceNullCharSequence() {
+        new Paint().getRunAdvance((CharSequence) null, 0, 0, 0, 0, false, 0);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetRunAdvanceNullCharArray() {
+        new Paint().getRunAdvance((char[]) null, 0, 0, 0, 0, false, 0);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceTextLengthLessThenContextEnd() {
+        final String string = "abcde";
+
+        // text length < context end
+        new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() + 1, false,
+                string.length());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceContextEndLessThanEnd() {
+        final String string = "abcde";
+
+        // context end < end
+        new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() - 1, false, 0);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceEndLessThanOffset() {
+        final String string = "abcde";
+
+        // end < offset
+        new Paint().getRunAdvance(string, 0, string.length() - 1, 0, string.length() - 1, false,
+                string.length());
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceOffsetLessThanStart() {
+        final String string = "abcde";
+
+        // offset < start
+        new Paint().getRunAdvance(string, 1, string.length(), 1, string.length(), false, 0);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceStartLessThanContextStart() {
+        final String string = "abcde";
+
+        // start < context start
+        new Paint().getRunAdvance(string, 0, string.length(), 1, string.length(), false, 1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetRunAdvanceContextStartNegative() {
+        final String string = "abcde";
+
+        // context start < 0
+        new Paint().getRunAdvance(string, 0, string.length(), -1, string.length(), false, 0);
+    }
+
+    @Test
     public void testGetRunAdvance_nonzeroIndex() {
         Paint p = new Paint();
         final String text = "Android powers hundreds of millions of mobile " +
@@ -1349,6 +1355,7 @@
         assertTrue(Math.abs(widthAndroidFirst - widthAndroidSecond) < 1);
     }
 
+    @Test
     public void testGetRunAdvance_glyphDependingContext() {
         Paint p = new Paint();
         // Test the context change the character shape.
@@ -1359,6 +1366,7 @@
         assertTrue(isolatedFormWidth > initialFormWidth);
     }
 
+    @Test
     public void testGetRunAdvance_arabic() {
         Paint p = new Paint();
         // Test total width is equals to sum of each character's width.
@@ -1378,6 +1386,7 @@
         assertTrue(Math.abs(totalWidth - sumOfCharactersWidth) < 1);
     }
 
+    @Test
     public void testGetOffsetForAdvance() {
         Paint p = new Paint();
         {
@@ -1432,72 +1441,62 @@
         }
     }
 
-    public void testGetOffsetForAdvance_invalidArguments() {
-        Paint p = new Paint();
-        try {
-            p.getOffsetForAdvance((CharSequence)null, 0, 0, 0, 0, false, 0.0f);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        } catch (Exception e) {
-            fail("Should throw an IllegalArgumentException.");
-        }
-        try {
-            p.getOffsetForAdvance((char[])null, 0, 0, 0, 0, false, 0.0f);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        } catch (Exception e) {
-            fail("Should throw an IllegalArgumentException.");
-        }
-
-        final String string = "abcde";
-
-        try {
-            // context start < 0
-            p.getOffsetForAdvance(string, -1, string.length(), 0, string.length(), false, 0.0f);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-
-        try {
-            // start < context start
-            p.getOffsetForAdvance(string, 0, string.length(), 1, string.length(), false, 0.0f);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-
-        try {
-            // end < start
-            p.getOffsetForAdvance(string, 1, 0, 0, 0, false, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-
-        try {
-            // context end < end
-            p.getOffsetForAdvance(string, 0, string.length(), 0, string.length() - 1, false, 0.0f);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
-
-        try {
-            // text length < context end
-            p.getOffsetForAdvance(string, 0, string.length(), 0, string.length() + 1, false, 0.0f);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        } catch (Exception e) {
-            fail("Should throw an IndexOutOfBoundsException.");
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetOffsetForAdvanceNullCharSequence() {
+        new Paint().getOffsetForAdvance((CharSequence) null, 0, 0, 0, 0, false, 0.0f);
     }
 
-    public void testGetOffsetForAdvance_grahpemeCluster() {
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetOffsetForAdvanceNullCharArray() {
+        new Paint().getOffsetForAdvance((char[]) null, 0, 0, 0, 0, false, 0.0f);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetOffsetForAdvanceContextStartNegative() {
+        final String string = "abcde";
+
+        // context start < 0
+        new Paint().getOffsetForAdvance(string, -1, string.length(), 0, string.length(), false,
+                0.0f);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetOffsetForAdvanceStartLessThanContextStart() {
+        final String string = "abcde";
+
+        // start < context start
+        new Paint().getOffsetForAdvance(string, 0, string.length(), 1, string.length(), false,
+                0.0f);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetOffsetForAdvanceEndLessThanStart() {
+        final String string = "abcde";
+
+        // end < start
+        new Paint().getOffsetForAdvance(string, 1, 0, 0, 0, false, 0);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetOffsetForAdvanceContextEndLessThanEnd() {
+        final String string = "abcde";
+
+        // context end < end
+        new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() - 1, false,
+                0.0f);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetOffsetForAdvanceTextLengthLessThanContextEnd() {
+        final String string = "abcde";
+
+        // text length < context end
+        new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() + 1, false,
+                0.0f);
+    }
+
+    @Test
+    public void testGetOffsetForAdvance_graphemeCluster() {
         Paint p = new Paint();
         {
             String string = "\uD83C\uDF37"; // U+1F337: TULIP
@@ -1555,4 +1554,24 @@
             }
         }
     }
+
+    @Test
+    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/Paint_AlignTest.java b/tests/tests/graphics/src/android/graphics/cts/Paint_AlignTest.java
index ff07f45..08fb649 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Paint_AlignTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Paint_AlignTest.java
@@ -16,18 +16,27 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
-import android.graphics.Paint.Align;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Paint_AlignTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Paint_AlignTest {
+    @Test
     public void testValueOf() {
         assertEquals(Align.LEFT, Align.valueOf("LEFT"));
         assertEquals(Align.CENTER, Align.valueOf("CENTER"));
         assertEquals(Align.RIGHT, Align.valueOf("RIGHT"));
     }
 
+    @Test
     public void testValues() {
         // set the actual value
         Align[] actual = Align.values();
diff --git a/tests/tests/graphics/src/android/graphics/cts/Paint_CapTest.java b/tests/tests/graphics/src/android/graphics/cts/Paint_CapTest.java
index 1c9fe33..b16cf0d 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Paint_CapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Paint_CapTest.java
@@ -16,19 +16,27 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Paint;
 import android.graphics.Paint.Cap;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Paint_CapTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Paint_CapTest {
+    @Test
     public void testValueOf() {
-
         assertEquals(Cap.BUTT, Cap.valueOf("BUTT"));
         assertEquals(Cap.ROUND, Cap.valueOf("ROUND"));
         assertEquals(Cap.SQUARE, Cap.valueOf("SQUARE"));
     }
 
+    @Test
     public void testValues() {
         // set the actual value
         Cap[] actual = Cap.values();
diff --git a/tests/tests/graphics/src/android/graphics/cts/Paint_FontMetricsIntTest.java b/tests/tests/graphics/src/android/graphics/cts/Paint_FontMetricsIntTest.java
index 1b01ecd..56cabe1 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Paint_FontMetricsIntTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Paint_FontMetricsIntTest.java
@@ -16,17 +16,25 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertNotNull;
+
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Paint_FontMetricsIntTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Paint_FontMetricsIntTest {
+    @Test
     public void testConstructor() {
-        // new the FontMetricsInt instance
         new Paint.FontMetricsInt();
     }
 
+    @Test
     public void testToString() {
         // set the expected value
         int top = 1;
diff --git a/tests/tests/graphics/src/android/graphics/cts/Paint_JoinTest.java b/tests/tests/graphics/src/android/graphics/cts/Paint_JoinTest.java
index 0e264f1..c203794 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Paint_JoinTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Paint_JoinTest.java
@@ -16,18 +16,27 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
-import android.graphics.Paint.Join;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Paint;
+import android.graphics.Paint.Join;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Paint_JoinTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Paint_JoinTest {
+    @Test
     public void testValueOf() {
         assertEquals(Join.BEVEL, Join.valueOf("BEVEL"));
         assertEquals(Join.MITER, Join.valueOf("MITER"));
         assertEquals(Join.ROUND, Join.valueOf("ROUND"));
     }
 
+    @Test
     public void testValues() {
         // set the actual value
         Join[] actual = Join.values();
diff --git a/tests/tests/graphics/src/android/graphics/cts/Paint_StyleTest.java b/tests/tests/graphics/src/android/graphics/cts/Paint_StyleTest.java
index d43693f..0752898 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Paint_StyleTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Paint_StyleTest.java
@@ -16,18 +16,27 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Paint_StyleTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Paint_StyleTest {
+    @Test
     public void testValueOf() {
         assertEquals(Style.FILL, Style.valueOf("FILL"));
         assertEquals(Style.STROKE, Style.valueOf("STROKE"));
         assertEquals(Style.FILL_AND_STROKE, Style.valueOf("FILL_AND_STROKE"));
     }
 
+    @Test
     public void testValues() {
         // set the actual value
         Style[] actual = Style.values();
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffectTest.java
index 71e42d2..9cc9c7e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffectTest.java
@@ -16,26 +16,32 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.Path.Direction;
 import android.graphics.PathDashPathEffect;
 import android.graphics.RectF;
-import android.graphics.Bitmap.Config;
-import android.graphics.Path.Direction;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class PathDashPathEffectTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathDashPathEffectTest {
     private static final int SQUARE = 10;
     private static final int ADVANCE = 30;
     private static final int WIDTH = 100;
     private static final int HEIGHT = 100;
 
+    @Test
     public void testPathDashPathEffect() {
         Bitmap b = Bitmap.createBitmap(WIDTH, HEIGHT, Config.ARGB_8888);
         b.eraseColor(Color.BLACK);
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffect_StyleTest.java b/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffect_StyleTest.java
index 93de1ee..d4e95e0 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffect_StyleTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PathDashPathEffect_StyleTest.java
@@ -16,13 +16,19 @@
 
 package android.graphics.cts;
 
-import android.graphics.PathDashPathEffect;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.PathDashPathEffect.Style;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PathDashPathEffect_StyleTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathDashPathEffect_StyleTest {
+    @Test
     public void testValueOf() {
         assertEquals(Style.TRANSLATE, Style.valueOf("TRANSLATE"));
         assertEquals(Style.ROTATE, Style.valueOf("ROTATE"));
@@ -30,17 +36,17 @@
         // Every Style element will be tested somewhere else.
     }
 
+    @Test
     public void testValues() {
         // set the expected value
         Style[] expected = {
                 Style.TRANSLATE,
                 Style.ROTATE,
-                Style.MORPH};
+                Style.MORPH };
         Style[] actual = Style.values();
         assertEquals(expected.length, actual.length);
         for (int i = 0; i < actual.length; i ++) {
             assertEquals(expected[i], actual[i]);
         }
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/PathEffectTest.java
index 28136c3..d7f313b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PathEffectTest.java
@@ -17,12 +17,17 @@
 package android.graphics.cts;
 
 import android.graphics.PathEffect;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PathEffectTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathEffectTest {
+    @Test
     public void testConstructor() {
         new PathEffect();
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathMeasureTest.java b/tests/tests/graphics/src/android/graphics/cts/PathMeasureTest.java
index 8e1fca0..3b0846f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PathMeasureTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PathMeasureTest.java
@@ -16,25 +16,34 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Matrix;
 import android.graphics.Path;
-import android.graphics.PathMeasure;
 import android.graphics.Path.Direction;
-import android.test.AndroidTestCase;
+import android.graphics.PathMeasure;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PathMeasureTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathMeasureTest {
     private PathMeasure mPathMeasure;
     private Path mPath;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mPath = new Path();
         mPathMeasure = new PathMeasure();
-
     }
 
+    @Test
     public void testConstructor() {
         mPathMeasure = new PathMeasure();
 
@@ -46,16 +55,18 @@
         mPathMeasure = new PathMeasure(path, false);
     }
 
-    public void testGetPosTan() {
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetPosTanArraysTooSmall() {
         float distance = 1f;
         float[] pos = { 1f };
         float[] tan = { 1f };
-        try {
-            mPathMeasure.getPosTan(distance, pos, tan);
-            fail("should throw exception");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
+
+        mPathMeasure.getPosTan(distance, pos, tan);
+    }
+
+    @Test
+    public void testGetPosTan() {
+        float distance = 1f;
         float[] pos2 = { 1f, 2f };
         float[] tan2 = { 1f, 3f };
         assertFalse(mPathMeasure.getPosTan(distance, pos2, tan2));
@@ -68,6 +79,7 @@
         assertTrue(mPathMeasure.getPosTan(0f, pos3, tan3));
     }
 
+    @Test
     public void testNextContour() {
         assertFalse(mPathMeasure.nextContour());
         mPath.addRect(1, 2, 3, 4, Path.Direction.CW);
@@ -75,13 +87,15 @@
         assertTrue(mPathMeasure.nextContour());
     }
 
+    @Test
     public void testGetLength() {
-        assertEquals(0f, mPathMeasure.getLength());
+        assertEquals(0f, mPathMeasure.getLength(), 0.0f);
         mPath.addRect(1, 2, 3, 4, Path.Direction.CW);
         mPathMeasure.setPath(mPath, true);
-        assertEquals(8.0f, mPathMeasure.getLength());
+        assertEquals(8.0f, mPathMeasure.getLength(), 0.0f);
     }
 
+    @Test
     public void testIsClosed() {
         Path circle = new Path();
         circle.addCircle(0, 0, 1, Direction.CW);
@@ -100,21 +114,24 @@
         assertTrue(measure.isClosed());
     }
 
+    @Test
     public void testSetPath() {
         mPathMeasure.setPath(mPath, true);
-        //There is no getter and we can't obtain any status about it.
+        // There is no getter and we can't obtain any status about it.
     }
 
+    @Test
     public void testGetSegment() {
-        assertEquals(0f, mPathMeasure.getLength());
+        assertEquals(0f, mPathMeasure.getLength(), 0.0f);
         mPath.addRect(1, 2, 3, 4, Path.Direction.CW);
         mPathMeasure.setPath(mPath, true);
-        assertEquals(8f, mPathMeasure.getLength());
+        assertEquals(8f, mPathMeasure.getLength(), 0.0f);
         Path dst = new Path();
         assertTrue(mPathMeasure.getSegment(0, mPathMeasure.getLength(), dst, true));
         assertFalse(mPathMeasure.getSegment(mPathMeasure.getLength(), 0, dst, true));
     }
 
+    @Test
     public void testGetMatrix() {
         Matrix matrix = new Matrix();
         assertFalse(mPathMeasure.getMatrix(1f, matrix, PathMeasure.POSITION_MATRIX_FLAG));
diff --git a/tests/tests/graphics/src/android/graphics/cts/PathTest.java b/tests/tests/graphics/src/android/graphics/cts/PathTest.java
index 5958a84..db3884c 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.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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,50 +60,51 @@
         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);
+        verifyPathsAreEquivalent(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);
         path.set(path1);
-        assertPathsAreEquivalent(path, path1);
+        verifyPathsAreEquivalent(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);
+        verifyPathsAreEquivalent(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,73 @@
         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);
     }
 
-    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 +268,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 +315,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 +328,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,14 +413,15 @@
         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);
         assertFalse(path.isEmpty());
     }
 
+    @Test
     public void testOffsetTextPath() {
         Paint paint = new Paint();
         Path path = new Path();
@@ -422,7 +440,7 @@
         assertEquals(expectedRect, offsettedRect);
     }
 
-    private static void assertPathsAreEquivalent(Path actual, Path expected) {
+    private static void verifyPathsAreEquivalent(Path actual, Path expected) {
         Bitmap actualBitmap = drawAndGetBitmap(actual);
         Bitmap expectedBitmap = drawAndGetBitmap(expected);
         assertTrue(actualBitmap.sameAs(expectedBitmap));
@@ -441,7 +459,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/Path_DirectionTest.java b/tests/tests/graphics/src/android/graphics/cts/Path_DirectionTest.java
index 5e27b2a..fb9c39f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Path_DirectionTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Path_DirectionTest.java
@@ -16,28 +16,35 @@
 
 package android.graphics.cts;
 
-import android.graphics.Path;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Path.Direction;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Path_DirectionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Path_DirectionTest {
+    @Test
     public void testValueOf() {
         assertEquals(Direction.CW, Direction.valueOf("CW"));
         assertEquals(Direction.CCW, Direction.valueOf("CCW"));
         // Every Direction element will be tested somewhere else.
     }
 
+    @Test
     public void testValues() {
         // set the expected value
         Direction[] expected = {
                 Direction.CW,
-                Direction.CCW};
+                Direction.CCW };
         Direction[] actual = Direction.values();
         assertEquals(expected.length, actual.length);
         for (int i = 0; i < actual.length; i ++) {
             assertEquals(expected[i], actual[i]);
         }
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/Path_FillTypeTest.java b/tests/tests/graphics/src/android/graphics/cts/Path_FillTypeTest.java
index 60b0586..17f5f87 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Path_FillTypeTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Path_FillTypeTest.java
@@ -16,12 +16,19 @@
 
 package android.graphics.cts;
 
-import android.graphics.Path;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Path.FillType;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Path_FillTypeTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Path_FillTypeTest {
+    @Test
     public void testValueOf() {
         assertEquals(FillType.WINDING, FillType.valueOf("WINDING"));
         assertEquals(FillType.EVEN_ODD, FillType.valueOf("EVEN_ODD"));
@@ -30,18 +37,18 @@
         // Every FillType element will be tested somewhere else.
     }
 
+    @Test
     public void testValues() {
         // set the expected value
         FillType[] expected = {
                 FillType.WINDING,
                 FillType.EVEN_ODD,
                 FillType.INVERSE_WINDING,
-                FillType.INVERSE_EVEN_ODD};
+                FillType.INVERSE_EVEN_ODD };
         FillType[] actual = FillType.values();
         assertEquals(expected.length, actual.length);
         for (int i = 0; i < actual.length; i ++) {
             assertEquals(expected[i], actual[i]);
         }
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PictureTest.java b/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
index 912c5a7..017ccb7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PictureTest.java
@@ -16,23 +16,31 @@
 
 package android.graphics.cts;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.Paint.Style;
 import android.graphics.Picture;
 import android.graphics.Rect;
-import android.graphics.Paint.Style;
 import android.graphics.Region.Op;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PictureTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PictureTest {
     private static final int TEST_WIDTH = 4; // must be >= 2
     private static final int TEST_HEIGHT = 3; // must >= 2
 
@@ -44,7 +52,8 @@
     //   - copy constructed picture from actively recording picture
     //   - writeToStream/createFromStream created picture from actively recording picture
     //   - actively recording picture after draw call
-    public void testSaveRestoreBalance() throws Exception {
+    @Test
+    public void testSaveRestoreBalance() {
         Picture original = new Picture();
         Canvas canvas = original.beginRecording(TEST_WIDTH, TEST_HEIGHT);
         assertNotNull(canvas);
@@ -53,7 +62,7 @@
         int expectedSaveCount = canvas.getSaveCount();
 
         Picture copy = new Picture(original);
-        checkBalance(copy);
+        verifyBalance(copy);
 
         assertEquals(expectedSaveCount, canvas.getSaveCount());
 
@@ -64,14 +73,14 @@
 
         Picture serialized = Picture.createFromStream(new ByteArrayInputStream(bout.toByteArray()));
         // The serialization/deserialization process will balance the saves and restores
-        checkBalance(serialized);
+        verifyBalance(serialized);
 
         assertEquals(expectedSaveCount, canvas.getSaveCount());
 
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
         Canvas drawDest = new Canvas(bitmap);
         original.draw(drawDest);
-        checkBalance(original);
+        verifyBalance(original);
     }
 
     // Add an extra save with a transform and clip
@@ -84,7 +93,7 @@
         canvas.drawRect(0, 0, 10, 10, paint);
     }
 
-    private void checkBalance(Picture picture) {
+    private void verifyBalance(Picture picture) {
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
 
@@ -107,7 +116,8 @@
         assertEquals(beforeClip, afterClip);
     }
 
-    public void testPicture() throws Exception {
+    @Test
+    public void testPicture() {
         Picture picture = new Picture();
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
 
@@ -119,8 +129,8 @@
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
         canvas = new Canvas(bitmap);
         picture.draw(canvas);
-        checkSize(picture);
-        checkBitmap(bitmap);
+        verifySize(picture);
+        verifyBitmap(bitmap);
 
         picture.writeToStream(bout);
         picture = Picture.createFromStream(new ByteArrayInputStream(bout.toByteArray()));
@@ -129,18 +139,18 @@
         bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
         canvas = new Canvas(bitmap);
         picture.draw(canvas);
-        checkSize(picture);
-        checkBitmap(bitmap);
+        verifySize(picture);
+        verifyBitmap(bitmap);
 
         Picture pic = new Picture(picture);
         bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Bitmap.Config.ARGB_8888);
         canvas = new Canvas(bitmap);
         pic.draw(canvas);
-        checkSize(pic);
-        checkBitmap(bitmap);
+        verifySize(pic);
+        verifyBitmap(bitmap);
     }
 
-    private void checkSize(Picture picture) {
+    private void verifySize(Picture picture) {
         assertEquals(TEST_WIDTH, picture.getWidth());
         assertEquals(TEST_HEIGHT, picture.getHeight());
     }
@@ -159,7 +169,7 @@
         canvas.drawPoint(0, 0, paint);
     }
 
-    private void checkBitmap(Bitmap bitmap) {
+    private void verifyBitmap(Bitmap bitmap) {
         // first pixel is BLUE, rest of the line is RED
         assertEquals(Color.BLUE, bitmap.getPixel(0, 0));
         for (int x = 1; x < TEST_WIDTH; x++) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/PixelFormatTest.java b/tests/tests/graphics/src/android/graphics/cts/PixelFormatTest.java
index 4809755..e54bef9 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PixelFormatTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PixelFormatTest.java
@@ -16,108 +16,97 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.PixelFormat;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PixelFormatTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private PixelFormat mPixelFormat;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPixelFormat = null;
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PixelFormatTest {
+    @Test
     public void testConstructor() {
-        mPixelFormat = null;
-        // new the PixelFormat instance
-        mPixelFormat = new PixelFormat();
+        new PixelFormat();
     }
 
+    @Test
     public void testGetPixelFormatInfo() {
+        PixelFormat pixelFormat = new PixelFormat();
 
-        // new the PixelFormat instance
-        mPixelFormat = new PixelFormat();
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_8888, pixelFormat);
+        assertEquals(4, pixelFormat.bytesPerPixel);
+        assertEquals(32, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_8888, mPixelFormat);
-        assertEquals(4, mPixelFormat.bytesPerPixel);
-        assertEquals(32, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGBX_8888, pixelFormat);
+        assertEquals(4, pixelFormat.bytesPerPixel);
+        assertEquals(32, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGBX_8888, mPixelFormat);
-        assertEquals(4, mPixelFormat.bytesPerPixel);
-        assertEquals(32, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_888, pixelFormat);
+        assertEquals(3, pixelFormat.bytesPerPixel);
+        assertEquals(24, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_888, mPixelFormat);
-        assertEquals(3, mPixelFormat.bytesPerPixel);
-        assertEquals(24, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_565, pixelFormat);
+        assertEquals(2, pixelFormat.bytesPerPixel);
+        assertEquals(16, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_565, mPixelFormat);
-        assertEquals(2, mPixelFormat.bytesPerPixel);
-        assertEquals(16, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_5551, pixelFormat);
+        assertEquals(2, pixelFormat.bytesPerPixel);
+        assertEquals(16, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_5551, mPixelFormat);
-        assertEquals(2, mPixelFormat.bytesPerPixel);
-        assertEquals(16, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_4444, pixelFormat);
+        assertEquals(2, pixelFormat.bytesPerPixel);
+        assertEquals(16, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_4444, mPixelFormat);
-        assertEquals(2, mPixelFormat.bytesPerPixel);
-        assertEquals(16, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.A_8, pixelFormat);
+        assertEquals(1, pixelFormat.bytesPerPixel);
+        assertEquals(8, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.A_8, mPixelFormat);
-        assertEquals(1, mPixelFormat.bytesPerPixel);
-        assertEquals(8, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.L_8, pixelFormat);
+        assertEquals(1, pixelFormat.bytesPerPixel);
+        assertEquals(8, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.L_8, mPixelFormat);
-        assertEquals(1, mPixelFormat.bytesPerPixel);
-        assertEquals(8, mPixelFormat.bitsPerPixel);
+        PixelFormat.getPixelFormatInfo(PixelFormat.LA_88, pixelFormat);
+        assertEquals(2, pixelFormat.bytesPerPixel);
+        assertEquals(16, pixelFormat.bitsPerPixel);
 
-        PixelFormat.getPixelFormatInfo(PixelFormat.LA_88, mPixelFormat);
-        assertEquals(2, mPixelFormat.bytesPerPixel);
-        assertEquals(16, mPixelFormat.bitsPerPixel);
-
-        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_332, mPixelFormat);
-        assertEquals(1, mPixelFormat.bytesPerPixel);
-        assertEquals(8, mPixelFormat.bitsPerPixel);
-
-        try {
-            PixelFormat.getPixelFormatInfo(PixelFormat.UNKNOWN, mPixelFormat);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            //excepted
-        }
-
-        try {
-            PixelFormat.getPixelFormatInfo(PixelFormat.JPEG, mPixelFormat);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            //excepted
-        }
-
-        try {
-            PixelFormat.getPixelFormatInfo(PixelFormat.TRANSLUCENT, mPixelFormat);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            //excepted
-        }
-
-        try {
-            PixelFormat.getPixelFormatInfo(PixelFormat.TRANSPARENT, mPixelFormat);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            //excepted
-        }
-
-        try {
-            PixelFormat.getPixelFormatInfo(PixelFormat.OPAQUE, mPixelFormat);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            //excepted
-        }
+        PixelFormat.getPixelFormatInfo(PixelFormat.RGB_332, pixelFormat);
+        assertEquals(1, pixelFormat.bytesPerPixel);
+        assertEquals(8, pixelFormat.bitsPerPixel);
     }
 
-    public void testFormatHasAlpha() {
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelFormatInfoUnknown() {
+        PixelFormat.getPixelFormatInfo(PixelFormat.UNKNOWN, new PixelFormat());
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelFormatInfoJpeg() {
+        PixelFormat.getPixelFormatInfo(PixelFormat.JPEG, new PixelFormat());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelFormatInfoTranslucent() {
+        PixelFormat.getPixelFormatInfo(PixelFormat.TRANSLUCENT, new PixelFormat());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelFormatInfoTransparent() {
+        PixelFormat.getPixelFormatInfo(PixelFormat.TRANSPARENT, new PixelFormat());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetPixelFormatInfoOpaque() {
+        PixelFormat.getPixelFormatInfo(PixelFormat.OPAQUE, new PixelFormat());
+    }
+
+    @Test
+    public void testFormatHasAlpha() {
         assertTrue(PixelFormat.formatHasAlpha(PixelFormat.RGBA_8888));
         assertFalse(PixelFormat.formatHasAlpha(PixelFormat.RGBX_8888));
         assertFalse(PixelFormat.formatHasAlpha(PixelFormat.RGB_888));
@@ -130,5 +119,4 @@
         assertFalse(PixelFormat.formatHasAlpha(PixelFormat.RGB_332));
         assertFalse(PixelFormat.formatHasAlpha(PixelFormat.UNKNOWN));
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PointFTest.java b/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
index 77b72d4..eedcb6f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PointFTest.java
@@ -16,79 +16,100 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.test.AndroidTestCase;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PointFTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointFTest {
     private PointF mPointF;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPointF = null;
-    }
-
+    @Test
     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);
-
     }
 
+    @Test
     public void testNegate() {
         mPointF = new PointF(10, 10);
         mPointF.negate();
-        assertEquals(-10.0f, mPointF.x);
-        assertEquals(-10.0f, mPointF.y);
+        assertEquals(-10.0f, mPointF.x, 0.0f);
+        assertEquals(-10.0f, mPointF.y, 0.0f);
     }
 
+    @Test
     public void testLength1() {
         mPointF = new PointF(0.3f, 0.4f);
-        assertEquals(0.5f, mPointF.length());
+        assertEquals(0.5f, mPointF.length(), 0.0f);
     }
 
+    @Test
     public void testLength2() {
-        assertEquals(0.5f, PointF.length(0.3f, 0.4f));
+        assertEquals(0.5f, PointF.length(0.3f, 0.4f), 0.0f);
     }
 
+    @Test
     public void testSet1() {
         mPointF = new PointF();
         mPointF.set(0.3f, 0.4f);
-        assertEquals(0.3f, mPointF.x);
-        assertEquals(0.4f, mPointF.y);
+        assertEquals(0.3f, mPointF.x, 0.0f);
+        assertEquals(0.4f, mPointF.y, 0.0f);
     }
 
+    @Test
     public void testSet2() {
         mPointF = new PointF();
         PointF pointF = new PointF(0.3f, 0.4f);
         mPointF.set(pointF);
-        assertEquals(0.3f, mPointF.x);
-        assertEquals(0.4f, mPointF.y);
+        assertEquals(0.3f, mPointF.x, 0.0f);
+        assertEquals(0.4f, mPointF.y, 0.0f);
     }
 
+    @Test
     public void testEquals() {
         mPointF = new PointF(0.3f, 0.4f);
         assertTrue(mPointF.equals(0.3f, 0.4f));
         assertFalse(mPointF.equals(0.4f, 0.3f));
     }
 
+    @Test
     public void testOffset() {
         mPointF = new PointF(10.0f, 10.0f);
         mPointF.offset(1.0f, 1.1f);
-        assertEquals(11.0f, mPointF.x);
-        assertEquals(11.1f, mPointF.y);
+        assertEquals(11.0f, mPointF.x, 0.0f);
+        assertEquals(11.1f, mPointF.y, 0.0f);
     }
 
+    @Test
+    public void testDescribeContents() {
+        mPointF = new PointF(10.0f, 20.0f);
+        assertEquals(0, mPointF.describeContents());
+    }
+
+    @Test
+    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, 0.0f);
+        assertEquals(20.0f, mPointF.y, 0.0f);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/PointTest.java b/tests/tests/graphics/src/android/graphics/cts/PointTest.java
index e4ede58..d01f551 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PointTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PointTest.java
@@ -16,33 +16,34 @@
 
 package android.graphics.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 android.graphics.Point;
-import android.test.AndroidTestCase;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PointTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointTest {
     private Point mPoint;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mPoint = null;
-    }
-
+    @Test
     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);
-
     }
 
+    @Test
     public void testSet() {
         mPoint = new Point();
         mPoint.set(3, 4);
@@ -50,12 +51,14 @@
         assertEquals(4, mPoint.y);
     }
 
+    @Test
     public void testEquals1() {
         mPoint = new Point(3, 4);
         assertTrue(mPoint.equals(3, 4));
         assertFalse(mPoint.equals(4, 3));
     }
 
+    @Test
     public void testEquals2() {
         mPoint = new Point(3, 4);
         Point point = new Point(3, 4);
@@ -64,17 +67,20 @@
         assertFalse(mPoint.equals(point));
     }
 
+    @Test
     public void testHashCode() {
         mPoint = new Point(10, 10);
         Point p = new Point(100, 10);
         assertTrue(p.hashCode() != mPoint.hashCode());
     }
 
+    @Test
     public void testToString() {
         mPoint = new Point();
         assertNotNull(mPoint.toString());
     }
 
+    @Test
     public void testOffset() {
         mPoint = new Point(10, 10);
         mPoint.offset(1, 1);
@@ -82,6 +88,7 @@
         assertEquals(11, mPoint.y);
     }
 
+    @Test
     public void testNegate() {
         mPoint = new Point(10, 10);
         mPoint.negate();
@@ -89,4 +96,22 @@
         assertEquals(-10, mPoint.y);
     }
 
+    @Test
+    public void testDescribeContents() {
+        mPoint = new Point(10, 20);
+        assertEquals(0, mPoint.describeContents());
+    }
+
+    @Test
+    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/PorterDuffColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
index 301d532..0beadae 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
@@ -15,19 +15,27 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.Bitmap.Config;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PorterDuffColorFilterTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PorterDuffColorFilterTest {
     private static final int TOLERANCE = 5;
 
+    @Test
     public void testPorterDuffColorFilter() {
         int width = 100;
         int height = 100;
diff --git a/tests/tests/graphics/src/android/graphics/cts/PorterDuffXfermodeTest.java b/tests/tests/graphics/src/android/graphics/cts/PorterDuffXfermodeTest.java
index 2e7cca5..1a47f44 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PorterDuffXfermodeTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PorterDuffXfermodeTest.java
@@ -15,22 +15,28 @@
  */
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class PorterDuffXfermodeTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PorterDuffXfermodeTest {
     private static final int WIDTH = 100;
     private static final int HEIGHT = 100;
 
+    @Test
     public void testPorterDuffXfermode() {
         Bitmap target = Bitmap.createBitmap(WIDTH, HEIGHT, Config.ARGB_8888);
         target.eraseColor(Color.TRANSPARENT);
diff --git a/tests/tests/graphics/src/android/graphics/cts/RasterizerTest.java b/tests/tests/graphics/src/android/graphics/cts/RasterizerTest.java
deleted file mode 100644
index c3f7c49..0000000
--- a/tests/tests/graphics/src/android/graphics/cts/RasterizerTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-package android.graphics.cts;
-
-import android.graphics.Rasterizer;
-import android.test.AndroidTestCase;
-
-public class RasterizerTest extends AndroidTestCase {
-
-    public void testFinalize() {
-        MockRasterizer mr = new MockRasterizer();
-        try {
-            mr.finalize();
-        } catch (Throwable e) {
-            fail(e.getMessage());
-        }
-    }
-
-    class MockRasterizer extends Rasterizer {
-        @Override
-        public void finalize() throws Throwable {
-            super.finalize();
-        }
-    }
-}
diff --git a/tests/tests/graphics/src/android/graphics/cts/RectFTest.java b/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
index f5788af..2759d1e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RectFTest.java
@@ -16,115 +16,103 @@
 
 package android.graphics.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 android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RectFTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RectFTest {
     private RectF mRectF;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRectF = null;
-    }
-
+    @Test
     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);
-
     }
 
+    @Test
     public void testSort() {
-
         mRectF = new RectF(10, 10, 5, 5);
-        assertEquals(10.0f, mRectF.left);
-        assertEquals(10.0f, mRectF.top);
-        assertEquals(5.0f, mRectF.right);
-        assertEquals(5.0f, mRectF.bottom);
+        assertEquals(10.0f, mRectF.left, 0.0f);
+        assertEquals(10.0f, mRectF.top, 0.0f);
+        assertEquals(5.0f, mRectF.right, 0.0f);
+        assertEquals(5.0f, mRectF.bottom, 0.0f);
 
         mRectF.sort();
-        assertEquals(5.0f, mRectF.left);
-        assertEquals(5.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
-
+        assertEquals(5.0f, mRectF.left, 0.0f);
+        assertEquals(5.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     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);
-
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.top, 0.0f);
+        assertEquals(3.0f, mRectF.right, 0.0f);
+        assertEquals(4.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testSet2() {
-
         RectF rectF = new RectF(1.0f, 2.0f, 3.0f, 4.0f);
         mRectF = new RectF();
         mRectF.set(rectF);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.top);
-        assertEquals(3.0f, mRectF.right);
-        assertEquals(4.0f, mRectF.bottom);
-
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.top, 0.0f);
+        assertEquals(3.0f, mRectF.right, 0.0f);
+        assertEquals(4.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testSet3() {
-
         Rect rect = new Rect(1, 2, 3, 4);
         mRectF = new RectF();
         mRectF.set(rect);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.top);
-        assertEquals(3.0f, mRectF.right);
-        assertEquals(4.0f, mRectF.bottom);
-
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.top, 0.0f);
+        assertEquals(3.0f, mRectF.right, 0.0f);
+        assertEquals(4.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testIntersects1() {
-
         mRectF = new RectF(0, 0, 10, 10);
         assertTrue(mRectF.intersects(5, 5, 15, 15));
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
 
         mRectF = new RectF(0, 0, 10, 10);
         assertFalse(mRectF.intersects(15, 15, 25, 25));
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testIntersects2() {
-
         RectF rectF1;
         RectF rectF2;
 
@@ -135,101 +123,97 @@
         rectF1 = new RectF(0, 0, 10, 10);
         rectF2 = new RectF(15, 15, 25, 25);
         assertFalse(RectF.intersects(rectF1, rectF2));
-
     }
 
+    @Test
     public void testIntersect1() {
-
         mRectF = new RectF(0, 0, 10, 10);
         assertTrue(mRectF.intersect(5, 5, 15, 15));
-        assertEquals(5.0f, mRectF.left);
-        assertEquals(5.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
+        assertEquals(5.0f, mRectF.left, 0.0f);
+        assertEquals(5.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
 
         mRectF = new RectF(0, 0, 10, 10);
         assertFalse(mRectF.intersect(15, 15, 25, 25));
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testIntersect2() {
-
         RectF rectF;
 
         mRectF = new RectF(0, 0, 10, 10);
         rectF= new RectF(5, 5, 15, 15);
         assertTrue(mRectF.intersect(rectF));
-        assertEquals(5.0f, mRectF.left);
-        assertEquals(5.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
+        assertEquals(5.0f, mRectF.left, 0.0f);
+        assertEquals(5.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
 
         mRectF = new RectF(0, 0, 10, 10);
         rectF= new RectF(15, 15, 25, 25);
         assertFalse(mRectF.intersect(rectF));
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testUnion1() {
-
         // Both rect1 and rect2 are not empty.
         // 1. left < right, top < bottom
         // this.left < this.right, this.top < this.bottom
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         mRectF.union(1.0f, 1.0f, 2.0f, 2.0f);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // 2. left < right, top < bottom
         // this.left > this.right, this.top > this.bottom
         // New rectangle will be set to the new arguments
         mRectF = new RectF(1.0f, 1.0f, 0.0f, 0.0f);
         mRectF.union(1.0f, 1.0f, 2.0f, 2.0f);
-        assertEquals(1.0f, mRectF.top);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // 3. left > right, top > bottom
         // this.left < this.right, this.top < this.bottom
         // Nothing will be done.
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         mRectF.union(2.0f, 2.0f, 1.5f, 1.5f);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(1.0f, mRectF.right);
-        assertEquals(1.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(1.0f, mRectF.right, 0.0f);
+        assertEquals(1.0f, mRectF.bottom, 0.0f);
 
         // rect1 is empty, update to rect2.
         mRectF = new RectF();
         mRectF.union(1.0f, 1.0f, 2.0f, 2.0f);
-        assertEquals(1.0f, mRectF.top);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // rect2 is empty, nothing changed.
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         mRectF.union(2.0f, 2.0f, 2.0f, 2.0f);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(1.0f, mRectF.right);
-        assertEquals(1.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(1.0f, mRectF.right, 0.0f);
+        assertEquals(1.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testUnion2() {
-
         RectF rectF;
 
         // Both rect1 and rect2 are not empty.
@@ -238,10 +222,10 @@
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         rectF = new RectF(1.0f, 1.0f, 2.0f, 2.0f);
         mRectF.union(rectF);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // 2. left < right, top < bottom
         // this.left > this.right, this.top > this.bottom
@@ -249,10 +233,10 @@
         mRectF = new RectF(1.0f, 1.0f, 0.0f, 0.0f);
         rectF = new RectF(1.0f, 1.0f, 2.0f, 2.0f);
         mRectF.union(rectF);
-        assertEquals(1.0f, mRectF.top);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // 3. left > right, top > bottom
         // this.left < this.right, this.top < this.bottom
@@ -260,79 +244,76 @@
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         rectF = new RectF(2.0f, 2.0f, 1.5f, 1.5f);
         mRectF.union(rectF);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(1.0f, mRectF.right);
-        assertEquals(1.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(1.0f, mRectF.right, 0.0f);
+        assertEquals(1.0f, mRectF.bottom, 0.0f);
 
         // rect1 is empty, update to rect2.
         mRectF = new RectF(0.0f, 0.0f, 0.0f, 0.0f);
         rectF = new RectF(1.0f, 1.0f, 2.0f, 2.0f);
         mRectF.union(rectF);
-        assertEquals(1.0f, mRectF.top);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // rect2 is empty, nothing changed.
         mRectF = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
         rectF = new RectF(2.0f, 2.0f, 2.0f, 2.0f);
         mRectF.union(rectF);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(1.0f, mRectF.right);
-        assertEquals(1.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(1.0f, mRectF.right, 0.0f);
+        assertEquals(1.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     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);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // rect1 is not empty (x < left, y < top).
         mRectF = new RectF(1.0f, 1.0f, 2.0f, 2.0f);
         mRectF.union(0.0f, 0.0f);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // rect1 is not empty(point is inside of the rectangle).
         mRectF = new RectF(1.0f, 1.0f, 2.0f, 2.0f);
         mRectF.union(1.5f, 1.5f);
-        assertEquals(1.0f, mRectF.top);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
 
         // rect1 is empty.
         mRectF = new RectF();
         mRectF.union(2.0f, 2.0f);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.right);
-        assertEquals(2.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.right, 0.0f);
+        assertEquals(2.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     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));
-
     }
 
+    @Test
     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));
@@ -340,8 +321,8 @@
         assertFalse(mRectF.contains(0.0f, 0.0f, 19.0f, 19.0f));
     }
 
+    @Test
     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,79 +333,76 @@
         assertFalse(mRectF.contains(rectF));
         rectF = new RectF(0.0f, 0.0f, 19.0f, 19.0f);
         assertFalse(mRectF.contains(rectF));
-
     }
 
+    @Test
     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);
-
+       assertEquals(6.0f, mRectF.left, 0.0f);
+       assertEquals(6.0f, mRectF.top, 0.0f);
+       assertEquals(11.0f, mRectF.right, 0.0f);
+       assertEquals(11.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     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);
-        assertEquals(6.0f, mRectF.top);
-        assertEquals(9.0f, mRectF.right);
-        assertEquals(9.0f, mRectF.bottom);
+        assertEquals(6.0f, mRectF.left, 0.0f);
+        assertEquals(6.0f, mRectF.top, 0.0f);
+        assertEquals(9.0f, mRectF.right, 0.0f);
+        assertEquals(9.0f, mRectF.bottom, 0.0f);
 
         mRectF = new RectF(5.0f, 5.0f, 10.0f, 10.0f);
         mRectF.inset(-1.0f, -1.0f);
-        assertEquals(4.0f, mRectF.left);
-        assertEquals(4.0f, mRectF.top);
-        assertEquals(11.0f, mRectF.right);
-        assertEquals(11.0f, mRectF.bottom);
-
+        assertEquals(4.0f, mRectF.left, 0.0f);
+        assertEquals(4.0f, mRectF.top, 0.0f);
+        assertEquals(11.0f, mRectF.right, 0.0f);
+        assertEquals(11.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testHeight() {
         mRectF = new RectF(1.0f, 1.0f, 20.5f, 20.5f);
-        assertEquals(19.5f, mRectF.height());
+        assertEquals(19.5f, mRectF.height(), 0.0f);
     }
 
+    @Test
     public void testWidth() {
         mRectF = new RectF(1.0f, 1.0f, 20.5f, 20.5f);
-        assertEquals(19.5f, mRectF.width());
+        assertEquals(19.5f, mRectF.width(), 0.0f);
     }
 
+    @Test
     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);
-
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(1.0f, mRectF.top, 0.0f);
+        assertEquals(6.0f, mRectF.right, 0.0f);
+        assertEquals(6.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testSetEmpty() {
-
         // Before setEmpty()
         mRectF = new RectF(1, 2, 3, 4);
-        assertEquals(1.0f, mRectF.left);
-        assertEquals(2.0f, mRectF.top);
-        assertEquals(3.0f, mRectF.right);
-        assertEquals(4.0f, mRectF.bottom);
+        assertEquals(1.0f, mRectF.left, 0.0f);
+        assertEquals(2.0f, mRectF.top, 0.0f);
+        assertEquals(3.0f, mRectF.right, 0.0f);
+        assertEquals(4.0f, mRectF.bottom, 0.0f);
 
         // After setEmpty()
         mRectF.setEmpty();
-        assertEquals(0.0f, mRectF.left);
-        assertEquals(0.0f, mRectF.top);
-        assertEquals(0.0f, mRectF.right);
-        assertEquals(0.0f, mRectF.bottom);
-
+        assertEquals(0.0f, mRectF.left, 0.0f);
+        assertEquals(0.0f, mRectF.top, 0.0f);
+        assertEquals(0.0f, mRectF.right, 0.0f);
+        assertEquals(0.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testIsEmpty() {
-
         mRectF = new RectF();
         assertTrue(mRectF.isEmpty());
         mRectF = new RectF(1.0f, 1.0f, 1.0f, 1.0f);
@@ -433,82 +411,85 @@
         assertTrue(mRectF.isEmpty());
         mRectF = new RectF(1.0f, 1.0f, 20.0f, 20.0f);
         assertFalse(mRectF.isEmpty());
-
     }
 
+    @Test
     public void testCenterX() {
-
         mRectF = new RectF(10.0f, 10.0f, 20.0f, 20.0f);
-        assertEquals(15.0f, mRectF.centerX());
+        assertEquals(15.0f, mRectF.centerX(), 0.0f);
         mRectF = new RectF(10.5f, 10.0f, 20.0f, 20.0f);
-        assertEquals(15.25f, mRectF.centerX());
+        assertEquals(15.25f, mRectF.centerX(), 0.0f);
         mRectF = new RectF(10.4f, 10.0f, 20.0f, 20.0f);
-        assertEquals(15.2f, mRectF.centerX());
-
+        assertEquals(15.2f, mRectF.centerX(), 0.0f);
     }
 
+    @Test
     public void testCenterY() {
-
         mRectF = new RectF(10.0f, 10.0f, 20.0f, 20.0f);
-        assertEquals(15.0f, mRectF.centerY());
+        assertEquals(15.0f, mRectF.centerY(), 0.0f);
         mRectF = new RectF(10.0f, 10.5f, 20.0f, 20.0f);
-        assertEquals(15.25f, mRectF.centerY());
+        assertEquals(15.25f, mRectF.centerY(), 0.0f);
         mRectF = new RectF(10.0f, 10.4f, 20.0f, 20.0f);
-        assertEquals(15.2f, mRectF.centerY());
+        assertEquals(15.2f, mRectF.centerY(), 0.0f);
     }
 
+    @Test
     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 testSetIntersect() {
+    @Test
+    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());
+    }
 
+    @Test
+    public void testSetIntersect() {
         RectF rectF1 = new RectF(0, 0, 10, 10);
         RectF rectF2 = new RectF(5, 5, 15, 15);
 
         // Empty RectF
         mRectF = new RectF();
         assertTrue(mRectF.setIntersect(rectF1, rectF2));
-        assertEquals(5.0f, mRectF.left);
-        assertEquals(5.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
+        assertEquals(5.0f, mRectF.left, 0.0f);
+        assertEquals(5.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
 
         // Not Empty RectF
         mRectF = new RectF(0, 0, 15, 15);
         assertTrue(mRectF.setIntersect(rectF1, rectF2));
-        assertEquals(5.0f, mRectF.left);
-        assertEquals(5.0f, mRectF.top);
-        assertEquals(10.0f, mRectF.right);
-        assertEquals(10.0f, mRectF.bottom);
-
+        assertEquals(5.0f, mRectF.left, 0.0f);
+        assertEquals(5.0f, mRectF.top, 0.0f);
+        assertEquals(10.0f, mRectF.right, 0.0f);
+        assertEquals(10.0f, mRectF.bottom, 0.0f);
     }
 
+    @Test
     public void testRoundOut() {
-
         Rect rect = new Rect();
         mRectF = new RectF(1.2f, 1.8f, 5.2f, 5.8f);
         mRectF.roundOut(rect);
-        assertEquals(1, rect.left);
-        assertEquals(1, rect.top);
-        assertEquals(6, rect.right);
-        assertEquals(6, rect.bottom);
-
+        assertEquals(1, rect.left, 0.0f);
+        assertEquals(1, rect.top, 0.0f);
+        assertEquals(6, rect.right, 0.0f);
+        assertEquals(6, rect.bottom, 0.0f);
     }
 
+    @Test
     public void testRound() {
-
         Rect rect = new Rect();
         mRectF = new RectF(1.2f, 1.8f, 5.2f, 5.8f);
         mRectF.round(rect);
-        assertEquals(1, rect.left);
-        assertEquals(2, rect.top);
-        assertEquals(5, rect.right);
-        assertEquals(6, rect.bottom);
-
+        assertEquals(1, rect.left, 0.0f);
+        assertEquals(2, rect.top, 0.0f);
+        assertEquals(5, rect.right, 0.0f);
+        assertEquals(6, rect.bottom, 0.0f);
     }
 
+    @Test
     public void testWriteReadParcel() {
         RectF rectOut = new RectF(0.0f,0.0f,10.0f,10.0f);
         Parcel out = Parcel.obtain();
@@ -516,10 +497,10 @@
         out.setDataPosition(0);
         RectF rectIn = new RectF(1.0f,1.0f,1.0f,1.0f);
         rectIn.readFromParcel(out);
-        assertEquals(rectOut.left, rectIn.left);
-        assertEquals(rectOut.bottom, rectIn.bottom);
-        assertEquals(rectOut.right, rectIn.right);
-        assertEquals(rectOut.top, rectIn.top);
+        assertEquals(rectOut.left, rectIn.left, 0.0f);
+        assertEquals(rectOut.bottom, rectIn.bottom, 0.0f);
+        assertEquals(rectOut.right, rectIn.right, 0.0f);
+        assertEquals(rectOut.top, rectIn.top, 0.0f);
         assertNotNull(rectIn.toString());
 
         assertEquals(0, rectIn.describeContents());
diff --git a/tests/tests/graphics/src/android/graphics/cts/RectTest.java b/tests/tests/graphics/src/android/graphics/cts/RectTest.java
index c29ec0d..cb12cb5 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RectTest.java
@@ -16,49 +16,46 @@
 
 package android.graphics.cts;
 
+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.assertTrue;
+
 import android.graphics.Rect;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RectTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RectTest {
     private Rect mRect;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mRect = null;
-    }
-
+    @Test
     public void testConstructor() {
-
-        mRect = null;
-        // new the Rect instance
         mRect = new Rect();
 
-        mRect = null;
-        // new the Rect instance
         mRect = new Rect(10, 10, 20, 20);
 
-        mRect = null;
-        Rect rect = new Rect(10, 10, 20, 20);
-        // new the Rect instance
-        mRect = new Rect(rect);
-
+        mRect = new Rect(new Rect(10, 10, 20, 20));
     }
 
+    @Test
     public void testSet1() {
-
         mRect = new Rect();
         mRect.set(1, 2, 3, 4);
         assertEquals(1, mRect.left);
         assertEquals(2, mRect.top);
         assertEquals(3, mRect.right);
         assertEquals(4, mRect.bottom);
-
     }
 
+    @Test
     public void testSet2() {
-
         Rect rect = new Rect(1, 2, 3, 4);
         mRect = new Rect();
         mRect.set(rect);
@@ -68,8 +65,8 @@
         assertEquals(4, mRect.bottom);
     }
 
+    @Test
     public void testIntersects1() {
-
         mRect = new Rect(0, 0, 10, 10);
         assertTrue(mRect.intersects(5, 5, 15, 15));
         assertEquals(0, mRect.left);
@@ -83,11 +80,10 @@
         assertEquals(0, mRect.top);
         assertEquals(10, mRect.right);
         assertEquals(10, mRect.bottom);
-
     }
 
+    @Test
     public void testIntersects2() {
-
         Rect rect1;
         Rect rect2;
 
@@ -98,27 +94,26 @@
         rect1 = new Rect(0, 0, 10, 10);
         rect2 = new Rect(15, 15, 25, 25);
         assertFalse(Rect.intersects(rect1, rect2));
-
     }
 
+    @Test
     public void testHeight() {
         mRect = new Rect(6, 6, 10, 10);
         assertEquals(4, mRect.height());
     }
 
+    @Test
     public void testOffsetTo() {
-
         mRect = new Rect(5, 5, 10, 10);
         mRect.offsetTo(1, 1);
         assertEquals(1, mRect.left);
         assertEquals(1, mRect.top);
         assertEquals(6, mRect.right);
         assertEquals(6, mRect.bottom);
-
     }
 
+    @Test
     public void testSetIntersect() {
-
         Rect rect1 = new Rect(0, 0, 10, 10);
         Rect rect2 = new Rect(5, 5, 15, 15);
 
@@ -137,11 +132,10 @@
         assertEquals(5, mRect.top);
         assertEquals(10, mRect.right);
         assertEquals(10, mRect.bottom);
-
     }
 
+    @Test
     public void testUnion1() {
-
         // Both rect1 and rect2 are not empty.
         // 1. left < right, top < bottom
         // this.left < this.right, this.top < this.bottom
@@ -189,8 +183,8 @@
         assertEquals(1, mRect.bottom);
     }
 
+    @Test
     public void testUnion2() {
-
         Rect rect;
 
         // Both rect1 and rect2 are not empty.
@@ -245,8 +239,8 @@
         assertEquals(1, mRect.bottom);
     }
 
+    @Test
     public void testUnion3() {
-
         // rect1 is not empty (x > right, y > bottom).
         mRect = new Rect(0, 0, 1, 1);
         mRect.union(2, 2);
@@ -278,31 +272,28 @@
         assertEquals(0, mRect.left);
         assertEquals(2, mRect.right);
         assertEquals(2, mRect.bottom);
-
     }
 
+    @Test
     public void testContains1() {
-
         mRect = new Rect(1, 1, 20, 20);
         assertFalse(mRect.contains(0, 0));
         assertTrue(mRect.contains(1, 1));
         assertTrue(mRect.contains(19, 19));
         assertFalse(mRect.contains(20, 20));
-
     }
 
+    @Test
     public void testContains2() {
-
         mRect = new Rect(1, 1, 20, 20);
         assertTrue(mRect.contains(1, 1, 20, 20));
         assertTrue(mRect.contains(2, 2, 19, 19));
         assertFalse(mRect.contains(21, 21, 22, 22));
         assertFalse(mRect.contains(0, 0, 19, 19));
-
     }
 
+    @Test
     public void testContains3() {
-
         Rect rect;
         mRect = new Rect(1, 1, 20, 20);
         rect = new Rect(1, 1, 20, 20);
@@ -315,13 +306,14 @@
         assertFalse(mRect.contains(rect));
     }
 
+    @Test
     public void testWidth() {
         mRect = new Rect(6, 6, 10, 10);
         assertEquals(4, mRect.width());
     }
 
+    @Test
     public void testIsEmpty() {
-
         mRect = new Rect();
         assertTrue(mRect.isEmpty());
         mRect = new Rect(1, 1, 1, 1);
@@ -332,8 +324,8 @@
         assertFalse(mRect.isEmpty());
     }
 
+    @Test
     public void testIntersect1() {
-
         mRect = new Rect(0, 0, 10, 10);
         assertTrue(mRect.intersect(5, 5, 15, 15));
         assertEquals(5, mRect.left);
@@ -349,8 +341,8 @@
         assertEquals(10, mRect.bottom);
     }
 
+    @Test
     public void testIntersect2() {
-
         Rect rect;
 
         mRect = new Rect(0, 0, 10, 10);
@@ -370,8 +362,8 @@
         assertEquals(10, mRect.bottom);
     }
 
+    @Test
     public void testCenterY() {
-
         mRect = new Rect(10, 10, 20, 20);
         assertEquals(15, mRect.centerY());
         mRect = new Rect(10, 11, 20, 20);
@@ -380,6 +372,7 @@
         assertEquals(16, mRect.centerY());
     }
 
+    @Test
     public void testToString() {
         mRect = new Rect();
         assertNotNull(mRect.toString());
@@ -390,8 +383,8 @@
         assertNotNull(mRect.toShortString());
     }
 
+    @Test
     public void testSort() {
-
         mRect = new Rect(10, 10, 5, 5);
         assertEquals(10, mRect.left);
         assertEquals(10, mRect.top);
@@ -403,43 +396,39 @@
         assertEquals(5, mRect.top);
         assertEquals(10, mRect.right);
         assertEquals(10, mRect.bottom);
-
     }
 
+    @Test
     public void testCenterX() {
-
         mRect = new Rect(10, 10, 20, 20);
         assertEquals(15, mRect.centerX());
         mRect = new Rect(11, 10, 20, 20);
         assertEquals(15, mRect.centerX());
         mRect = new Rect(12, 10, 20, 20);
         assertEquals(16, mRect.centerX());
-
     }
 
+    @Test
     public void testEquals() {
-
         mRect = new Rect(1, 2, 3, 4);
         Rect rect = new Rect(1, 2, 3, 4);
         assertTrue(mRect.equals(rect));
         rect = new Rect(2, 2, 3, 4);
         assertFalse(mRect.equals(rect));
-
     }
 
+    @Test
     public void testOffset() {
-
         mRect = new Rect(5, 5, 10, 10);
         mRect.offset(1, 1);
         assertEquals(6, mRect.left);
         assertEquals(6, mRect.top);
         assertEquals(11, mRect.right);
         assertEquals(11, mRect.bottom);
-
     }
 
+    @Test
     public void testInset() {
-
         mRect = new Rect(5, 5, 10, 10);
         mRect.inset(1, 1);
         assertEquals(6, mRect.left);
@@ -453,11 +442,10 @@
         assertEquals(4, mRect.top);
         assertEquals(11, mRect.right);
         assertEquals(11, mRect.bottom);
-
     }
 
+    @Test
     public void testSetEmpty() {
-
         // Before setEmpty()
         mRect = new Rect(1, 2, 3, 4);
         assertEquals(1, mRect.left);
@@ -471,21 +459,22 @@
         assertEquals(0, mRect.top);
         assertEquals(0, mRect.right);
         assertEquals(0, mRect.bottom);
-
     }
 
+    @Test
     public void testExactCenterX() {
         mRect = new Rect(11, 10, 20, 20);
-        assertEquals(15.5f, mRect.exactCenterX());
+        assertEquals(15.5f, mRect.exactCenterX(), 0.0f);
     }
 
+    @Test
     public void testExactCenterY() {
         mRect = new Rect(10, 11, 20, 20);
-        assertEquals(15.5f, mRect.exactCenterY());
+        assertEquals(15.5f, mRect.exactCenterY(), 0.0f);
     }
 
+    @Test
     public void testAccessParcel() {
-
         Rect rect;
         Parcel p = Parcel.obtain();
         rect = new Rect(1, 2, 3, 4);
@@ -498,9 +487,9 @@
         assertEquals(2, mRect.top);
         assertEquals(3, mRect.right);
         assertEquals(4, mRect.bottom);
-
     }
 
+    @Test
     public void testFlattenToString() {
         Rect mRect = new Rect(1, 2, 3, 4);
         String flattenString = mRect.flattenToString();
@@ -508,14 +497,13 @@
         String unDefinedFormat = "TOPLEFT";
         Rect rect = Rect.unflattenFromString(flattenString);
         assertEquals(mRect, rect);
-        rect = null;
         rect = Rect.unflattenFromString(unDefinedFormat);
         assertNull(rect);
     }
 
+    @Test
     public void testDescribeContents() {
         mRect = new Rect();
         assertEquals(0, mRect.describeContents());
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/RegionIteratorTest.java b/tests/tests/graphics/src/android/graphics/cts/RegionIteratorTest.java
index 35ce621..6ac3552 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RegionIteratorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RegionIteratorTest.java
@@ -16,17 +16,29 @@
 
 package android.graphics.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 android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.RegionIterator;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RegionIteratorTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RegionIteratorTest {
+    @Test
     public void testConstructor() {
         new RegionIterator(new Region());
     }
 
+    @Test
     public void testNext() {
         Region region = new Region();
         region.set(1, 1, 10, 10);
@@ -35,8 +47,8 @@
         RegionIterator regionIterator = new RegionIterator(region);
         try {
             regionIterator.next(null);
-            fail("should throw exception");
-        } catch (Exception e) {
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
         }
         assertTrue(regionIterator.next(rect));
         assertEquals(1, rect.left);
@@ -170,5 +182,4 @@
         assertEquals(1, rect.right);
         assertEquals(1, rect.bottom);
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/RegionTest.java b/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
index 10e277b..0eff6cf 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
@@ -16,13 +16,25 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RegionTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RegionTest {
 
     // DIFFERENCE
     private final static int[][] DIFFERENCE_WITH1 = {{0, 0}, {4, 4},
@@ -99,18 +111,24 @@
 
     private Region mRegion;
 
-    private void assertPointsInsideRegion(int[][] area) {
+    private void verifyPointsInsideRegion(int[][] area) {
         for (int i = 0; i < area.length; i ++) {
             assertTrue(mRegion.contains(area[i][0], area[i][1]));
         }
     }
 
-    private void assertPointsOutsideRegion(int[][] area) {
+    private void verifyPointsOutsideRegion(int[][] area) {
         for (int i = 0; i < area.length; i ++) {
             assertFalse(mRegion.contains(area[i][0], area[i][1]));
         }
     }
 
+    @Before
+    public void setup() {
+        mRegion = new Region();
+    }
+
+    @Test
     public void testConstructor() {
         // Test Region()
         new Region();
@@ -127,9 +145,8 @@
         new Region(0, 0, 100, 100);
     }
 
+    @Test
     public void testSet1() {
-
-        mRegion = new Region();
         Rect rect = new Rect(1, 2, 3, 4);
         Region oriRegion = new Region(rect);
         assertTrue(mRegion.set(oriRegion));
@@ -139,9 +156,8 @@
         assertEquals(4, mRegion.getBounds().bottom);
     }
 
+    @Test
     public void testSet2() {
-
-        mRegion = new Region();
         Rect rect = new Rect(1, 2, 3, 4);
         assertTrue(mRegion.set(rect));
         assertEquals(1, mRegion.getBounds().left);
@@ -150,9 +166,8 @@
         assertEquals(4, mRegion.getBounds().bottom);
     }
 
+    @Test
     public void testSet3() {
-
-        mRegion = new Region();
         assertTrue(mRegion.set(1, 2, 3, 4));
         assertEquals(1, mRegion.getBounds().left);
         assertEquals(2, mRegion.getBounds().top);
@@ -160,18 +175,16 @@
         assertEquals(4, mRegion.getBounds().bottom);
     }
 
+    @Test
     public void testIsRect() {
-
-        mRegion = new Region();
         assertFalse(mRegion.isRect());
         mRegion = new Region(1, 2, 3, 4);
         assertTrue(mRegion.isRect());
     }
 
+    @Test
     public void testIsComplex() {
-
-        // Region is null
-        mRegion = new Region();
+        // Region is empty
         assertFalse(mRegion.isComplex());
 
         // Only one rectangle
@@ -186,9 +199,8 @@
         assertTrue(mRegion.isComplex());
     }
 
+    @Test
     public void testQuickContains1() {
-
-        mRegion = new Region();
         Rect rect = new Rect(1, 2, 3, 4);
         // This region not contains expected rectangle.
         assertFalse(mRegion.quickContains(rect));
@@ -200,9 +212,8 @@
         assertFalse(mRegion.quickContains(rect));
     }
 
+    @Test
     public void testQuickContains2() {
-
-        mRegion = new Region();
         // This region not contains expected rectangle.
         assertFalse(mRegion.quickContains(1, 2, 3, 4));
         mRegion.set(1, 2, 3, 4);
@@ -213,8 +224,8 @@
         assertFalse(mRegion.quickContains(1, 2, 3, 4));
     }
 
+    @Test
     public void testUnion() {
-
         Rect rect1 = new Rect();
         Rect rect2 = new Rect(0, 0, 20, 20);
         Rect rect3 = new Rect(5, 5, 10, 10);
@@ -222,8 +233,6 @@
         Rect rect5 = new Rect(40, 40, 60, 60);
 
         // union (inclusive-or) the two regions
-        mRegion = null;
-        mRegion = new Region();
         mRegion.set(rect2);
         // union null rectangle
         assertTrue(mRegion.contains(6, 6));
@@ -235,29 +244,28 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.union(rect3));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.union(rect4));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.union(rect5));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
+    @Test
     public void testContains() {
-
-        mRegion = new Region();
         mRegion.set(2, 2, 5, 5);
         // Not contain (1, 1).
         assertFalse(mRegion.contains(1, 1));
@@ -288,9 +296,8 @@
         assertTrue(mRegion.contains(7, 7));
     }
 
+    @Test
     public void testEmpty() {
-
-        mRegion = new Region();
         assertTrue(mRegion.isEmpty());
         mRegion = null;
         mRegion = new Region(1, 2, 3, 4);
@@ -299,16 +306,13 @@
         assertTrue(mRegion.isEmpty());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetBoundsNull() {
+        mRegion.getBounds(null);
+    }
+
+    @Test
     public void testGetBounds() {
-
-        // Exception
-        try {
-            mRegion.getBounds(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            //except here
-        }
-
         // Normal, return true.
         Rect rect1 = new Rect(1, 2, 3, 4);
         mRegion = new Region(rect1);
@@ -319,26 +323,25 @@
         assertFalse(mRegion.getBounds(rect2));
     }
 
+    @Test
     public void testOp1() {
-
         Rect rect1 = new Rect();
         Rect rect2 = new Rect(0, 0, 20, 20);
         Rect rect3 = new Rect(5, 5, 10, 10);
         Rect rect4 = new Rect(10, 10, 30, 30);
         Rect rect5 = new Rect(40, 40, 60, 60);
 
-        assertNullRegionOp1(rect1);
-        assertDifferenceOp1(rect1, rect2, rect3, rect4, rect5);
-        assertIntersectOp1(rect1, rect2, rect3, rect4, rect5);
-        assertUnionOp1(rect1, rect2, rect3, rect4, rect5);
-        assertXorOp1(rect1, rect2, rect3, rect4, rect5);
-        assertReverseDifferenceOp1(rect1, rect2, rect3, rect4, rect5);
-        assertReplaceOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyNullRegionOp1(rect1);
+        verifyDifferenceOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyIntersectOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyUnionOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyXorOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyReverseDifferenceOp1(rect1, rect2, rect3, rect4, rect5);
+        verifyReplaceOp1(rect1, rect2, rect3, rect4, rect5);
     }
 
-    private void assertNullRegionOp1(Rect rect1) {
+    private void verifyNullRegionOp1(Rect rect1) {
         // Region without rectangle
-        mRegion = null;
         mRegion = new Region();
         assertFalse(mRegion.op(rect1, Region.Op.DIFFERENCE));
         assertFalse(mRegion.op(rect1, Region.Op.INTERSECT));
@@ -348,11 +351,10 @@
         assertFalse(mRegion.op(rect1, Region.Op.REPLACE));
     }
 
-    private void assertDifferenceOp1(Rect rect1, Rect rect2, Rect rect3,
+    private void verifyDifferenceOp1(Rect rect1, Rect rect2, Rect rect3,
             Rect rect4, Rect rect5) {
         // DIFFERENCE, Region with rectangle
         // subtract the op region from the first region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(rect2);
@@ -362,28 +364,27 @@
         mRegion.set(rect2);
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(rect3, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH1);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT1);
+        verifyPointsInsideRegion(DIFFERENCE_WITH1);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT1);
 
         // 2. subtract rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(11, 11));
         assertTrue(mRegion.op(rect4, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT2);
 
         // 3. subtract rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.op(rect5, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT3);
     }
 
-    private void assertIntersectOp1(Rect rect1, Rect rect2, Rect rect3,
+    private void verifyIntersectOp1(Rect rect1, Rect rect2, Rect rect3,
             Rect rect4, Rect rect5) {
         // INTERSECT, Region with rectangle
         // intersect the two regions
-        mRegion = null;
         mRegion = new Region();
         // intersect null rectangle
         mRegion.set(rect2);
@@ -393,26 +394,24 @@
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.op(rect3, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH1);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT1);
+        verifyPointsInsideRegion(INTERSECT_WITH1);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT1);
 
         // 2. intersect rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(9, 9));
         assertTrue(mRegion.op(rect4, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH2);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT2);
+        verifyPointsInsideRegion(INTERSECT_WITH2);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT2);
 
         // 3. intersect rectangle out of this region
         mRegion.set(rect2);
         assertFalse(mRegion.op(rect5, Region.Op.INTERSECT));
     }
 
-    private void assertUnionOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4,
-            Rect rect5) {
+    private void verifyUnionOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
         // UNION, Region with rectangle
         // union (inclusive-or) the two regions
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // union null rectangle
@@ -425,31 +424,29 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(rect3, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(rect4, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(rect5, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
-    private void assertXorOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4,
-            Rect rect5) {
+    private void verifyXorOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
         // XOR, Region with rectangle
         // exclusive-or the two regions
-        mRegion = null;
         mRegion = new Region();
         // xor null rectangle
         mRegion.set(rect2);
@@ -460,8 +457,8 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(rect3, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH1);
-        assertPointsOutsideRegion(XOR_WITHOUT1);
+        verifyPointsInsideRegion(XOR_WITH1);
+        verifyPointsOutsideRegion(XOR_WITHOUT1);
 
         // 2. xor rectangle overlap this region
         mRegion.set(rect2);
@@ -469,23 +466,21 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(rect4, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH2);
-        assertPointsOutsideRegion(XOR_WITHOUT2);
+        verifyPointsInsideRegion(XOR_WITH2);
+        verifyPointsOutsideRegion(XOR_WITHOUT2);
 
         // 3. xor rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(rect5, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH3);
-        assertPointsOutsideRegion(XOR_WITHOUT3);
+        verifyPointsInsideRegion(XOR_WITH3);
+        verifyPointsOutsideRegion(XOR_WITHOUT3);
     }
 
-    private void assertReverseDifferenceOp1(Rect rect1, Rect rect2, Rect rect3,
-            Rect rect4, Rect rect5) {
+    private void verifyReverseDifferenceOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
         // REVERSE_DIFFERENCE, Region with rectangle
         // reverse difference the first region from the op region
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // reverse difference null rectangle
@@ -503,23 +498,21 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(rect4, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
 
         // 3. reverse difference rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(rect5, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
     }
 
-    private void assertReplaceOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4,
-            Rect rect5) {
+    private void verifyReplaceOp1(Rect rect1, Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
         // REPLACE, Region with rectangle
         // replace the dst region with the op region
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // subtract null rectangle
@@ -544,25 +537,24 @@
         assertEquals(rect5, mRegion.getBounds());
     }
 
+    @Test
     public void testOp2() {
-
         Rect rect2 = new Rect(0, 0, 20, 20);
         Rect rect3 = new Rect(5, 5, 10, 10);
         Rect rect4 = new Rect(10, 10, 30, 30);
         Rect rect5 = new Rect(40, 40, 60, 60);
 
-        assertNullRegionOp2();
-        assertDifferenceOp2(rect2);
-        assertIntersectOp2(rect2);
-        assertUnionOp2(rect2);
-        assertXorOp2(rect2);
-        assertReverseDifferenceOp2(rect2);
-        assertReplaceOp2(rect2, rect3, rect4, rect5);
+        verifyNullRegionOp2();
+        verifyDifferenceOp2(rect2);
+        verifyIntersectOp2(rect2);
+        verifyUnionOp2(rect2);
+        verifyXorOp2(rect2);
+        verifyReverseDifferenceOp2(rect2);
+        verifyReplaceOp2(rect2, rect3, rect4, rect5);
     }
 
-    private void assertNullRegionOp2() {
+    private void verifyNullRegionOp2() {
         // Region without rectangle
-        mRegion = null;
         mRegion = new Region();
         assertFalse(mRegion.op(0, 0, 0, 0, Region.Op.DIFFERENCE));
         assertFalse(mRegion.op(0, 0, 0, 0, Region.Op.INTERSECT));
@@ -572,10 +564,9 @@
         assertFalse(mRegion.op(0, 0, 0, 0, Region.Op.REPLACE));
     }
 
-    private void assertDifferenceOp2(Rect rect2) {
+    private void verifyDifferenceOp2(Rect rect2) {
         // DIFFERENCE, Region with rectangle
         // subtract the op region from the first region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(rect2);
@@ -585,27 +576,26 @@
         mRegion.set(rect2);
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(5, 5, 10, 10, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH1);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT1);
+        verifyPointsInsideRegion(DIFFERENCE_WITH1);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT1);
 
         // 2. subtract rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(11, 11));
         assertTrue(mRegion.op(10, 10, 30, 30, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT2);
 
         // 3. subtract rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.op(40, 40, 60, 60, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT3);
     }
 
-    private void assertIntersectOp2(Rect rect2) {
+    private void verifyIntersectOp2(Rect rect2) {
         // INTERSECT, Region with rectangle
         // intersect the two regions
-        mRegion = null;
         mRegion = new Region();
         // intersect null rectangle
         mRegion.set(rect2);
@@ -615,25 +605,24 @@
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.op(5, 5, 10, 10, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH1);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT1);
+        verifyPointsInsideRegion(INTERSECT_WITH1);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT1);
 
         // 2. intersect rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(9, 9));
         assertTrue(mRegion.op(10, 10, 30, 30, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH2);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT2);
+        verifyPointsInsideRegion(INTERSECT_WITH2);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT2);
 
         // 3. intersect rectangle out of this region
         mRegion.set(rect2);
         assertFalse(mRegion.op(40, 40, 60, 60, Region.Op.INTERSECT));
     }
 
-    private void assertUnionOp2(Rect rect2) {
+    private void verifyUnionOp2(Rect rect2) {
         // UNION, Region with rectangle
         // union (inclusive-or) the two regions
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // union null rectangle
@@ -646,30 +635,29 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(5, 5, 10, 10, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(10, 10, 30, 30, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(40, 40, 60, 60, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
-    private void assertXorOp2(Rect rect2) {
+    private void verifyXorOp2(Rect rect2) {
         // XOR, Region with rectangle
         // exclusive-or the two regions
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // xor null rectangle
@@ -680,8 +668,8 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(5, 5, 10, 10, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH1);
-        assertPointsOutsideRegion(XOR_WITHOUT1);
+        verifyPointsInsideRegion(XOR_WITH1);
+        verifyPointsOutsideRegion(XOR_WITHOUT1);
 
         // 2. xor rectangle overlap this region
         mRegion.set(rect2);
@@ -689,22 +677,21 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(10, 10, 30, 30, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH2);
-        assertPointsOutsideRegion(XOR_WITHOUT2);
+        verifyPointsInsideRegion(XOR_WITH2);
+        verifyPointsOutsideRegion(XOR_WITHOUT2);
 
         // 3. xor rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(40, 40, 60, 60, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH3);
-        assertPointsOutsideRegion(XOR_WITHOUT3);
+        verifyPointsInsideRegion(XOR_WITH3);
+        verifyPointsOutsideRegion(XOR_WITHOUT3);
     }
 
-    private void assertReverseDifferenceOp2(Rect rect2) {
+    private void verifyReverseDifferenceOp2(Rect rect2) {
         // REVERSE_DIFFERENCE, Region with rectangle
         // reverse difference the first region from the op region
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // reverse difference null rectangle
@@ -720,21 +707,20 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(10, 10, 30, 30, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
         // reverse difference rectangle out of this region
         mRegion.set(rect2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(40, 40, 60, 60, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
     }
 
-    private void assertReplaceOp2(Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
+    private void verifyReplaceOp2(Rect rect2, Rect rect3, Rect rect4, Rect rect5) {
         // REPLACE, Region w1ith rectangle
         // replace the dst region with the op region
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(rect2);
         // subtract null rectangle
@@ -759,26 +745,25 @@
         assertEquals(rect5, mRegion.getBounds());
     }
 
+    @Test
     public void testOp3() {
-
         Region region1 = new Region();
         Region region2 = new Region(0, 0, 20, 20);
         Region region3 = new Region(5, 5, 10, 10);
         Region region4 = new Region(10, 10, 30, 30);
         Region region5 = new Region(40, 40, 60, 60);
 
-        assertNullRegionOp3(region1);
-        assertDifferenceOp3(region1, region2, region3, region4, region5);
-        assertIntersectOp3(region1, region2, region3, region4, region5);
-        assertUnionOp3(region1, region2, region3, region4, region5);
-        assertXorOp3(region1, region2, region3, region4, region5);
-        assertReverseDifferenceOp3(region1, region2, region3, region4, region5);
-        assertReplaceOp3(region1, region2, region3, region4, region5);
+        verifyNullRegionOp3(region1);
+        verifyDifferenceOp3(region1, region2, region3, region4, region5);
+        verifyIntersectOp3(region1, region2, region3, region4, region5);
+        verifyUnionOp3(region1, region2, region3, region4, region5);
+        verifyXorOp3(region1, region2, region3, region4, region5);
+        verifyReverseDifferenceOp3(region1, region2, region3, region4, region5);
+        verifyReplaceOp3(region1, region2, region3, region4, region5);
     }
 
-    private void assertNullRegionOp3(Region region1) {
+    private void verifyNullRegionOp3(Region region1) {
         // Region without rectangle
-        mRegion = null;
         mRegion = new Region();
         assertFalse(mRegion.op(region1, Region.Op.DIFFERENCE));
         assertFalse(mRegion.op(region1, Region.Op.INTERSECT));
@@ -788,11 +773,10 @@
         assertFalse(mRegion.op(region1, Region.Op.REPLACE));
     }
 
-    private void assertDifferenceOp3(Region region1, Region region2,
+    private void verifyDifferenceOp3(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // DIFFERENCE, Region with rectangle
         // subtract the op region from the first region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(region2);
@@ -802,28 +786,27 @@
         mRegion.set(region2);
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(region3, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH1);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT1);
+        verifyPointsInsideRegion(DIFFERENCE_WITH1);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT1);
 
         // 2. subtract rectangle overlap this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(11, 11));
         assertTrue(mRegion.op(region4, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT2);
 
         // 3. subtract rectangle out of this region
         mRegion.set(region2);
         assertTrue(mRegion.op(region5, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT3);
     }
 
-    private void assertIntersectOp3(Region region1, Region region2,
+    private void verifyIntersectOp3(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // INTERSECT, Region with rectangle
         // intersect the two regions
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(region2);
         // intersect null rectangle
@@ -833,26 +816,25 @@
         mRegion.set(region2);
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.op(region3, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH1);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT1);
+        verifyPointsInsideRegion(INTERSECT_WITH1);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT1);
 
         // 2. intersect rectangle overlap this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(9, 9));
         assertTrue(mRegion.op(region4, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH2);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT2);
+        verifyPointsInsideRegion(INTERSECT_WITH2);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT2);
 
         // 3. intersect rectangle out of this region
         mRegion.set(region2);
         assertFalse(mRegion.op(region5, Region.Op.INTERSECT));
     }
 
-    private void assertUnionOp3(Region region1, Region region2, Region region3,
+    private void verifyUnionOp3(Region region1, Region region2, Region region3,
             Region region4, Region region5) {
         // UNION, Region with rectangle
         // union (inclusive-or) the two regions
-        mRegion = null;
         mRegion = new Region();
         // union null rectangle
         mRegion.set(region2);
@@ -865,31 +847,30 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(region3, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(region4, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(region5, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
-    private void assertXorOp3(Region region1, Region region2, Region region3,
+    private void verifyXorOp3(Region region1, Region region2, Region region3,
             Region region4, Region region5) {
         // XOR, Region with rectangle
         // exclusive-or the two regions
-        mRegion = null;
         mRegion = new Region();
         // xor null rectangle
         mRegion.set(region2);
@@ -900,8 +881,8 @@
         assertTrue(mRegion.contains(2, 2));
         assertTrue(mRegion.contains(6, 6));
         assertTrue(mRegion.op(region3, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH1);
-        assertPointsOutsideRegion(XOR_WITHOUT1);
+        verifyPointsInsideRegion(XOR_WITH1);
+        verifyPointsOutsideRegion(XOR_WITHOUT1);
 
         // 2. xor rectangle overlap this region
         mRegion.set(region2);
@@ -909,23 +890,22 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(region4, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH2);
-        assertPointsOutsideRegion(XOR_WITHOUT2);
+        verifyPointsInsideRegion(XOR_WITH2);
+        verifyPointsOutsideRegion(XOR_WITHOUT2);
 
         // 3. xor rectangle out of this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(region5, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH3);
-        assertPointsOutsideRegion(XOR_WITHOUT3);
+        verifyPointsInsideRegion(XOR_WITH3);
+        verifyPointsOutsideRegion(XOR_WITHOUT3);
     }
 
-    private void assertReverseDifferenceOp3(Region region1, Region region2,
+    private void verifyReverseDifferenceOp3(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // REVERSE_DIFFERENCE, Region with rectangle
         // reverse difference the first region from the op region
-        mRegion = null;
         mRegion = new Region();
         // reverse difference null rectangle
         mRegion.set(region2);
@@ -943,23 +923,22 @@
         assertTrue(mRegion.contains(11, 11));
         assertFalse(mRegion.contains(21, 21));
         assertTrue(mRegion.op(region4, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
 
         // 3. reverse difference rectangle out of this region
         mRegion.set(region2);
         assertTrue(mRegion.contains(2, 2));
         assertFalse(mRegion.contains(41, 41));
         assertTrue(mRegion.op(region5, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
     }
 
-    private void assertReplaceOp3(Region region1, Region region2, Region region3,
+    private void verifyReplaceOp3(Region region1, Region region2, Region region3,
             Region region4, Region region5) {
         // REPLACE, Region with rectangle
         // replace the dst region with the op region
-        mRegion = null;
         mRegion = new Region();
         mRegion.set(region2);
         // subtract null rectangle
@@ -984,8 +963,8 @@
         assertEquals(region5.getBounds(), mRegion.getBounds());
     }
 
+    @Test
     public void testOp4() {
-
         Rect rect1 = new Rect();
         Rect rect2 = new Rect(0, 0, 20, 20);
 
@@ -995,20 +974,19 @@
         Region region4 = new Region(10, 10, 30, 30);
         Region region5 = new Region(40, 40, 60, 60);
 
-        assertNullRegionOp4(rect1, region1);
-        assertDifferenceOp4(rect1, rect2, region1, region3, region4, region5);
-        assertIntersectOp4(rect1, rect2, region1, region3, region4, region5);
-        assertUnionOp4(rect1, rect2, region1, region3, region4, region5);
-        assertXorOp4(rect1, rect2, region1, region3, region4, region5);
-        assertReverseDifferenceOp4(rect1, rect2, region1, region3, region4,
+        verifyNullRegionOp4(rect1, region1);
+        verifyDifferenceOp4(rect1, rect2, region1, region3, region4, region5);
+        verifyIntersectOp4(rect1, rect2, region1, region3, region4, region5);
+        verifyUnionOp4(rect1, rect2, region1, region3, region4, region5);
+        verifyXorOp4(rect1, rect2, region1, region3, region4, region5);
+        verifyReverseDifferenceOp4(rect1, rect2, region1, region3, region4,
                 region5);
-        assertReplaceOp4(rect1, rect2, region1, region2, region3, region4,
+        verifyReplaceOp4(rect1, rect2, region1, region2, region3, region4,
                 region5);
     }
 
-    private void assertNullRegionOp4(Rect rect1, Region region1) {
+    private void verifyNullRegionOp4(Rect rect1, Region region1) {
         // Region without rectangle
-        mRegion = null;
         mRegion = new Region();
         assertFalse(mRegion.op(rect1, region1, Region.Op.DIFFERENCE));
         assertFalse(mRegion.op(rect1, region1, Region.Op.INTERSECT));
@@ -1019,11 +997,10 @@
         assertFalse(mRegion.op(rect1, region1, Region.Op.REPLACE));
     }
 
-    private void assertDifferenceOp4(Rect rect1, Rect rect2, Region region1,
+    private void verifyDifferenceOp4(Rect rect1, Rect rect2, Region region1,
             Region region3, Region region4, Region region5) {
         // DIFFERENCE, Region with rectangle
         // subtract the op region from the first region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         assertTrue(mRegion.op(rect2, region1, Region.Op.DIFFERENCE));
@@ -1031,27 +1008,26 @@
         // 1. subtract rectangle inside this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region3, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH1);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT1);
+        verifyPointsInsideRegion(DIFFERENCE_WITH1);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT1);
 
         // 2. subtract rectangle overlap this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region4, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT2);
 
         // 3. subtract rectangle out of this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region5, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT3);
     }
 
-    private void assertIntersectOp4(Rect rect1, Rect rect2, Region region1,
+    private void verifyIntersectOp4(Rect rect1, Rect rect2, Region region1,
             Region region3, Region region4, Region region5) {
         // INTERSECT, Region with rectangle
         // intersect the two regions
-        mRegion = null;
         mRegion = new Region();
         // intersect null rectangle
         mRegion.set(rect1);
@@ -1060,25 +1036,24 @@
         // 1. intersect rectangle inside this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region3, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH1);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT1);
+        verifyPointsInsideRegion(INTERSECT_WITH1);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT1);
 
         // 2. intersect rectangle overlap this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region4, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH2);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT2);
+        verifyPointsInsideRegion(INTERSECT_WITH2);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT2);
 
         // 3. intersect rectangle out of this region
         mRegion.set(rect1);
         assertFalse(mRegion.op(rect2, region5, Region.Op.INTERSECT));
     }
 
-    private void assertUnionOp4(Rect rect1, Rect rect2, Region region1,
+    private void verifyUnionOp4(Rect rect1, Rect rect2, Region region1,
             Region region3, Region region4, Region region5) {
         // UNION, Region with rectangle
         // union (inclusive-or) the two regions
-        mRegion = null;
         mRegion = new Region();
         // union null rectangle
         mRegion.set(rect1);
@@ -1088,27 +1063,26 @@
         // 1. union rectangle inside this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region3, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region4, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region5, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
-    private void assertXorOp4(Rect rect1, Rect rect2, Region region1,
+    private void verifyXorOp4(Rect rect1, Rect rect2, Region region1,
             Region region3, Region region4, Region region5) {
         // XOR, Region with rectangle
         // exclusive-or the two regions
-        mRegion = null;
         mRegion = new Region();
         // xor null rectangle
         mRegion.set(rect1);
@@ -1117,27 +1091,26 @@
         // 1. xor rectangle inside this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region3, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH1);
-        assertPointsOutsideRegion(XOR_WITHOUT1);
+        verifyPointsInsideRegion(XOR_WITH1);
+        verifyPointsOutsideRegion(XOR_WITHOUT1);
 
         // 2. xor rectangle overlap this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region4, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH2);
-        assertPointsOutsideRegion(XOR_WITHOUT2);
+        verifyPointsInsideRegion(XOR_WITH2);
+        verifyPointsOutsideRegion(XOR_WITHOUT2);
 
         // 3. xor rectangle out of this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region5, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH3);
-        assertPointsOutsideRegion(XOR_WITHOUT3);
+        verifyPointsInsideRegion(XOR_WITH3);
+        verifyPointsOutsideRegion(XOR_WITHOUT3);
     }
 
-    private void assertReverseDifferenceOp4(Rect rect1, Rect rect2,
+    private void verifyReverseDifferenceOp4(Rect rect1, Rect rect2,
             Region region1, Region region3, Region region4, Region region5) {
         // REVERSE_DIFFERENCE, Region with rectangle
         // reverse difference the first region from the op region
-        mRegion = null;
         mRegion = new Region();
         // reverse difference null rectangle
         mRegion.set(rect1);
@@ -1150,21 +1123,20 @@
         // 2. reverse difference rectangle overlap this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region4, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
 
         // 3. reverse difference rectangle out of this region
         mRegion.set(rect1);
         assertTrue(mRegion.op(rect2, region5, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
     }
 
-    private void assertReplaceOp4(Rect rect1, Rect rect2, Region region1,
+    private void verifyReplaceOp4(Rect rect1, Rect rect2, Region region1,
             Region region2, Region region3, Region region4, Region region5) {
         // REPLACE, Region with rectangle
         // replace the dst region with the op region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(rect1);
@@ -1186,26 +1158,25 @@
         assertEquals(region5.getBounds(), mRegion.getBounds());
     }
 
+    @Test
     public void testOp5() {
-
         Region region1 = new Region();
         Region region2 = new Region(0, 0, 20, 20);
         Region region3 = new Region(5, 5, 10, 10);
         Region region4 = new Region(10, 10, 30, 30);
         Region region5 = new Region(40, 40, 60, 60);
 
-        assertNullRegionOp5(region1);
-        assertDifferenceOp5(region1, region2, region3, region4, region5);
-        assertIntersectOp5(region1, region2, region3, region4, region5);
-        assertUnionOp5(region1, region2, region3, region4, region5);
-        assertXorOp5(region1, region2, region3, region4, region5);
-        assertReverseDifferenceOp5(region1, region2, region3, region4, region5);
-        assertReplaceOp5(region1, region2, region3, region4, region5);
+        verifyNullRegionOp5(region1);
+        verifyDifferenceOp5(region1, region2, region3, region4, region5);
+        verifyIntersectOp5(region1, region2, region3, region4, region5);
+        verifyUnionOp5(region1, region2, region3, region4, region5);
+        verifyXorOp5(region1, region2, region3, region4, region5);
+        verifyReverseDifferenceOp5(region1, region2, region3, region4, region5);
+        verifyReplaceOp5(region1, region2, region3, region4, region5);
     }
 
-    private void assertNullRegionOp5(Region region1) {
+    private void verifyNullRegionOp5(Region region1) {
         // Region without rectangle
-        mRegion = null;
         mRegion = new Region();
         assertFalse(mRegion.op(mRegion, region1, Region.Op.DIFFERENCE));
         assertFalse(mRegion.op(mRegion, region1, Region.Op.INTERSECT));
@@ -1215,11 +1186,10 @@
         assertFalse(mRegion.op(mRegion, region1, Region.Op.REPLACE));
     }
 
-    private void assertDifferenceOp5(Region region1, Region region2,
+    private void verifyDifferenceOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // DIFFERENCE, Region with rectangle
         // subtract the op region from the first region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(region1);
@@ -1228,27 +1198,26 @@
         // 1. subtract rectangle inside this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region3, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH1);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT1);
+        verifyPointsInsideRegion(DIFFERENCE_WITH1);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT1);
 
         // 2. subtract rectangle overlap this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region4, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT2);
 
         // 3. subtract rectangle out of this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region5, Region.Op.DIFFERENCE));
-        assertPointsInsideRegion(DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(DIFFERENCE_WITHOUT3);
     }
 
-    private void assertIntersectOp5(Region region1, Region region2,
+    private void verifyIntersectOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // INTERSECT, Region with rectangle
         // intersect the two regions
-        mRegion = null;
         mRegion = new Region();
         // intersect null rectangle
         mRegion.set(region1);
@@ -1257,25 +1226,24 @@
         // 1. intersect rectangle inside this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region3, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH1);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT1);
+        verifyPointsInsideRegion(INTERSECT_WITH1);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT1);
 
         // 2. intersect rectangle overlap this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region4, Region.Op.INTERSECT));
-        assertPointsInsideRegion(INTERSECT_WITH2);
-        assertPointsOutsideRegion(INTERSECT_WITHOUT2);
+        verifyPointsInsideRegion(INTERSECT_WITH2);
+        verifyPointsOutsideRegion(INTERSECT_WITHOUT2);
 
         // 3. intersect rectangle out of this region
         mRegion.set(region1);
         assertFalse(mRegion.op(region2, region5, Region.Op.INTERSECT));
     }
 
-    private void assertUnionOp5(Region region1, Region region2,
+    private void verifyUnionOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // UNION, Region with rectangle
         // union (inclusive-or) the two regions
-        mRegion = null;
         mRegion = new Region();
         // union null rectangle
         mRegion.set(region1);
@@ -1285,27 +1253,26 @@
         // 1. union rectangle inside this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region3, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH1);
-        assertPointsOutsideRegion(UNION_WITHOUT1);
+        verifyPointsInsideRegion(UNION_WITH1);
+        verifyPointsOutsideRegion(UNION_WITHOUT1);
 
         // 2. union rectangle overlap this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region4, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH2);
-        assertPointsOutsideRegion(UNION_WITHOUT2);
+        verifyPointsInsideRegion(UNION_WITH2);
+        verifyPointsOutsideRegion(UNION_WITHOUT2);
 
         // 3. union rectangle out of this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region5, Region.Op.UNION));
-        assertPointsInsideRegion(UNION_WITH3);
-        assertPointsOutsideRegion(UNION_WITHOUT3);
+        verifyPointsInsideRegion(UNION_WITH3);
+        verifyPointsOutsideRegion(UNION_WITHOUT3);
     }
 
-    private void assertXorOp5(Region region1, Region region2,
+    private void verifyXorOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // XOR, Region with rectangle
         // exclusive-or the two regions
-        mRegion = null;
         mRegion = new Region();
         // xor null rectangle
         mRegion.set(region1);
@@ -1314,27 +1281,26 @@
         // 1. xor rectangle inside this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region3, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH1);
-        assertPointsOutsideRegion(XOR_WITHOUT1);
+        verifyPointsInsideRegion(XOR_WITH1);
+        verifyPointsOutsideRegion(XOR_WITHOUT1);
 
         // 2. xor rectangle overlap this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region4, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH2);
-        assertPointsOutsideRegion(XOR_WITHOUT2);
+        verifyPointsInsideRegion(XOR_WITH2);
+        verifyPointsOutsideRegion(XOR_WITHOUT2);
 
         // 3. xor rectangle out of this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region5, Region.Op.XOR));
-        assertPointsInsideRegion(XOR_WITH3);
-        assertPointsOutsideRegion(XOR_WITHOUT3);
+        verifyPointsInsideRegion(XOR_WITH3);
+        verifyPointsOutsideRegion(XOR_WITHOUT3);
     }
 
-    private void assertReverseDifferenceOp5(Region region1, Region region2,
+    private void verifyReverseDifferenceOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // REVERSE_DIFFERENCE, Region with rectangle
         // reverse difference the first region from the op region
-        mRegion = null;
         mRegion = new Region();
         // reverse difference null rectangle
         mRegion.set(region1);
@@ -1347,21 +1313,20 @@
         // 2. reverse difference rectangle overlap this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region4, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH2);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT2);
 
         // 3. reverse difference rectangle out of this region
         mRegion.set(region1);
         assertTrue(mRegion.op(region2, region5, Region.Op.REVERSE_DIFFERENCE));
-        assertPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
-        assertPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
+        verifyPointsInsideRegion(REVERSE_DIFFERENCE_WITH3);
+        verifyPointsOutsideRegion(REVERSE_DIFFERENCE_WITHOUT3);
     }
 
-    private void assertReplaceOp5(Region region1, Region region2,
+    private void verifyReplaceOp5(Region region1, Region region2,
             Region region3, Region region4, Region region5) {
         // REPLACE, Region with rectangle
         // replace the dst region with the op region
-        mRegion = null;
         mRegion = new Region();
         // subtract null rectangle
         mRegion.set(region1);
@@ -1383,8 +1348,8 @@
         assertEquals(region5.getBounds(), mRegion.getBounds());
     }
 
+    @Test
     public void testGetBoundaryPath1() {
-        mRegion = new Region();
         assertTrue(mRegion.getBoundaryPath().isEmpty());
 
         // Both clip and path are non-null.
@@ -1395,9 +1360,8 @@
         assertFalse(mRegion.getBoundaryPath().isEmpty());
     }
 
+    @Test
     public void testGetBoundaryPath2() {
-
-        mRegion = new Region();
         Path path = new Path();
         assertFalse(mRegion.getBoundaryPath(path));
 
@@ -1419,9 +1383,8 @@
         assertTrue(mRegion.getBoundaryPath(path));
     }
 
+    @Test
     public void testSetPath() {
-
-        mRegion = new Region();
         // Both clip and path are null.
         Region clip = new Region();
         Path path = new Path();
@@ -1468,8 +1431,8 @@
         assertNotSame(unexpected.right, actual.right);
     }
 
+    @Test
     public void testTranslate1() {
-
         Rect rect1 = new Rect(0, 0, 20, 20);
         Rect rect2 = new Rect(10, 10, 30, 30);
         mRegion = new Region(0, 0, 20, 20);
@@ -1478,8 +1441,8 @@
         assertEquals(rect2, mRegion.getBounds());
     }
 
+    @Test
     public void testTranslate2() {
-
         Region dst = new Region();
         Rect rect1 = new Rect(0, 0, 20, 20);
         Rect rect2 = new Rect(10, 10, 30, 30);
@@ -1491,11 +1454,10 @@
         assertEquals(rect2, dst.getBounds());
     }
 
+    @Test
     public void testWriteToParcel() {
-
         int flags = 0;
         Rect oriRect = new Rect(0, 0, 10, 10);
-        mRegion = new Region();
 
         // test reading/writing an empty parcel
         Parcel p = Parcel.obtain();
@@ -1535,13 +1497,13 @@
         assertEquals(15, dst.getBounds().right);
     }
 
+    @Test
     public void testDescribeContents() {
-
-        mRegion = new Region();
         int actual = mRegion.describeContents();
         assertEquals(0, actual);
     }
 
+    @Test
     public void testQuickReject1() {
         Rect oriRect = new Rect(0, 0, 20, 20);
         Rect rect1 = new Rect();
@@ -1549,7 +1511,6 @@
         Rect rect3 = new Rect(0, 0, 10, 10);
         Rect rect4 = new Rect(10, 10, 30, 30);
 
-        mRegion = new Region();
         // Return true if the region is empty
         assertTrue(mRegion.quickReject(rect1));
         mRegion.set(oriRect);
@@ -1560,8 +1521,8 @@
         assertFalse(mRegion.quickReject(rect4));
     }
 
+    @Test
     public void testQuickReject2() {
-        mRegion = new Region();
         // Return true if the region is empty
         assertTrue(mRegion.quickReject(0, 0, 0, 0));
         mRegion.set(0, 0, 20, 20);
@@ -1572,6 +1533,7 @@
         assertFalse(mRegion.quickReject(10, 10, 30, 30));
     }
 
+    @Test
     public void testQuickReject3() {
         Region oriRegion = new Region(0, 0, 20, 20);
         Region region1 = new Region();
@@ -1579,7 +1541,6 @@
         Region region3 = new Region(0, 0, 10, 10);
         Region region4 = new Region(10, 10, 30, 30);
 
-        mRegion = new Region();
         // Return true if the region is empty
         assertTrue(mRegion.quickReject(region1));
         mRegion.set(oriRegion);
@@ -1589,5 +1550,4 @@
         mRegion.set(oriRegion);
         assertFalse(mRegion.quickReject(region4));
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/Region_OpTest.java b/tests/tests/graphics/src/android/graphics/cts/Region_OpTest.java
index daa7181..be31672 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Region_OpTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Region_OpTest.java
@@ -16,12 +16,19 @@
 
 package android.graphics.cts;
 
-import android.graphics.Region;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Region.Op;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Region_OpTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Region_OpTest {
+    @Test
     public void testValueOf() {
         assertEquals(Op.DIFFERENCE, Op.valueOf("DIFFERENCE"));
         assertEquals(Op.INTERSECT, Op.valueOf("INTERSECT"));
@@ -30,10 +37,11 @@
         assertEquals(Op.REVERSE_DIFFERENCE, Op.valueOf("REVERSE_DIFFERENCE"));
         assertEquals(Op.REPLACE, Op.valueOf("REPLACE"));
         // Every Op element has been tested in testOp1(), testOp2(), testOp3(),
-        // testOp4() and testOp5(), {@link RegionTest}.
+        // testOp4() and testOp5() in the {@link RegionTest}.
         // Every Op element indicates one operation type.
     }
 
+    @Test
     public void testValues() {
         // set the expected value
         Op[] expected = {
@@ -42,7 +50,7 @@
                 Op.UNION,
                 Op.XOR,
                 Op.REVERSE_DIFFERENCE,
-                Op.REPLACE};
+                Op.REPLACE };
         Op[] actual = Op.values();
         assertEquals(expected.length, actual.length);
         assertEquals(expected[0], actual[0]);
@@ -52,5 +60,4 @@
         assertEquals(expected[4], actual[4]);
         assertEquals(expected[5], actual[5]);
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/ShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ShaderTest.java
index 5b093d2..9a21bc6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ShaderTest.java
@@ -16,17 +16,27 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertFalse;
+
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Matrix;
 import android.graphics.Shader;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class ShaderTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShaderTest {
+    @Test
     public void testConstructor() {
         new Shader();
     }
 
+    @Test
     public void testAccessLocalMatrix() {
         int width = 80;
         int height = 120;
diff --git a/tests/tests/graphics/src/android/graphics/cts/Shader_TileModeTest.java b/tests/tests/graphics/src/android/graphics/cts/Shader_TileModeTest.java
index d66f9a8..47c49de 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Shader_TileModeTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Shader_TileModeTest.java
@@ -16,18 +16,26 @@
 
 package android.graphics.cts;
 
-import junit.framework.TestCase;
-import android.graphics.Shader;
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Shader.TileMode;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Shader_TileModeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Shader_TileModeTest {
+    @Test
     public void testValueOf() {
         assertEquals(TileMode.CLAMP, TileMode.valueOf("CLAMP"));
         assertEquals(TileMode.MIRROR, TileMode.valueOf("MIRROR"));
         assertEquals(TileMode.REPEAT, TileMode.valueOf("REPEAT"));
     }
 
+    @Test
     public void testValues() {
         TileMode[] tileMode = TileMode.values();
         assertEquals(3, tileMode.length);
diff --git a/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
index 73c034c..d6eac97 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SumPathEffectTest.java
@@ -17,25 +17,32 @@
 package android.graphics.cts;
 
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.CornerPathEffect;
 import android.graphics.DashPathEffect;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.Path.Direction;
 import android.graphics.PathEffect;
 import android.graphics.SumPathEffect;
-import android.graphics.Bitmap.Config;
-import android.graphics.Path.Direction;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SumPathEffectTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SumPathEffectTest {
     private static final int WIDTH = 100;
     private static final int HEIGHT = 100;
 
+    @Test
     public void testSumPathEffect() {
         Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Config.ARGB_8888);
         bitmap.eraseColor(Color.BLACK);
diff --git a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
index 9007816..7da3810 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
@@ -16,48 +16,56 @@
 
 package android.graphics.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.SweepGradient;
-import android.graphics.Bitmap.Config;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SweepGradientTest extends TestCase {
-
-    private Paint mPaint;
-    private Canvas mCanvas;
-    private Bitmap mBitmap;
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SweepGradientTest {
     private static final int SIZE = 200;
     private static final int CENTER = SIZE / 2;
     private static final int RADIUS = 80;
     private static final int NUM_STEPS = 100;
     private static final int TOLERANCE = 10;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    private Paint mPaint;
+    private Canvas mCanvas;
+    private Bitmap mBitmap;
+
+    @Before
+    public void setup() {
         mPaint = new Paint();
         mBitmap = Bitmap.createBitmap(SIZE, SIZE, Config.ARGB_8888);
         mBitmap.eraseColor(Color.TRANSPARENT);
         mCanvas = new Canvas(mBitmap);
     }
 
+    @Test
     public void test2Colors() {
         final int[] colors = new int[] { Color.GREEN, Color.RED };
         final float[] positions = new float[] { 0f, 1f };
         Shader shader = new SweepGradient(CENTER, CENTER, colors[0], colors[1]);
         mPaint.setShader(shader);
         mCanvas.drawRect(new Rect(0, 0, SIZE, SIZE), mPaint);
-        checkColors(colors, positions, TOLERANCE);
+        verifyColors(colors, positions, TOLERANCE);
     }
 
+    @Test
     public void testColorArray() {
         final int[] colors = new int[] { Color.GREEN, Color.RED, Color.BLUE };
         final float[] positions = new float[] { 0f, 0.3f, 1f };
@@ -65,9 +73,10 @@
         mPaint.setShader(shader);
         mCanvas.drawRect(new Rect(0, 0, SIZE, SIZE), mPaint);
 
-        checkColors(colors, positions, TOLERANCE);
+        verifyColors(colors, positions, TOLERANCE);
     }
 
+    @Test
     public void testMultiColor() {
         final int[] colors = new int[] { Color.GREEN, Color.RED, Color.BLUE, Color.GREEN };
         final float[] positions = new float[] { 0f, 0.25f, 0.5f, 1f };
@@ -76,10 +85,10 @@
         mPaint.setShader(shader);
         mCanvas.drawRect(new Rect(0, 0, SIZE, SIZE), mPaint);
 
-        checkColors(colors, positions, TOLERANCE);
+        verifyColors(colors, positions, TOLERANCE);
     }
 
-    private void checkColors(int[] colors, float[] positions, int tolerance) {
+    private void verifyColors(int[] colors, float[] positions, int tolerance) {
         final double twoPi = Math.PI * 2;
         final double step = twoPi / NUM_STEPS;
 
@@ -121,19 +130,18 @@
             int pixel = mBitmap.getPixel(x, y);
 
             try {
-            assertEquals(Color.alpha(color), Color.alpha(pixel), tolerance);
-            assertEquals(Color.red(color), Color.red(pixel), tolerance);
-            assertEquals(Color.green(color), Color.green(pixel), tolerance);
-            assertEquals(Color.blue(color), Color.blue(pixel), tolerance);
+                assertEquals(Color.alpha(color), Color.alpha(pixel), tolerance);
+                assertEquals(Color.red(color), Color.red(pixel), tolerance);
+                assertEquals(Color.green(color), Color.green(pixel), tolerance);
+                assertEquals(Color.blue(color), Color.blue(pixel), tolerance);
             } catch (Error e) {
-                System.out.println("***************");
-                System.out.println(rad);
-                System.out.println(x);
-                System.out.println(y);
-                System.out.println(Integer.toHexString(pixel));
-                System.out.println(Integer.toHexString(color));
+                Log.w(getClass().getName(), "rad=" + rad + ", x=" + x + ", y=" + y
+                    + "pixel=" + Integer.toHexString(pixel) + ", color="
+                    + Integer.toHexString(color));
                 throw e;
             }
         }
     }
+
+
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index e5a610c..8c16193 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -16,19 +16,33 @@
 
 package android.graphics.cts;
 
+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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.content.Context;
 import android.graphics.Paint;
 import android.graphics.Typeface;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+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.IOException;
 import java.io.InputStream;
 
-public class TypefaceTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceTest {
     // generic family name for monospaced fonts
     private static final String MONO = "monospace";
     private static final String DEFAULT = (String)null;
@@ -38,12 +52,14 @@
     private static final String[] FAMILIES =
             { (String) null, "monospace", "serif", "sans-serif", "cursive", "arial", "times" };
 
+    private Context mContext;
+
     /**
      * Create a typeface of the given style. If the default font does not support the style,
      * a number of generic families are tried.
      * @return The typeface or null, if no typeface with the given style can be found.
      */
-    private Typeface createTypeface(int style) {
+    private static Typeface createTypeface(int style) {
         for (String family : FAMILIES) {
             Typeface tf = Typeface.create(family, style);
             if (tf.getStyle() == style) {
@@ -53,7 +69,12 @@
         return null;
     }
 
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
 
+    @Test
     public void testIsBold() {
         Typeface typeface = createTypeface(Typeface.BOLD);
         if (typeface != null) {
@@ -84,6 +105,7 @@
         }
     }
 
+    @Test
     public void testCreate() {
         Typeface typeface = Typeface.create(DEFAULT, Typeface.NORMAL);
         assertNotNull(typeface);
@@ -98,6 +120,7 @@
         assertNotNull(typeface);
     }
 
+    @Test
     public void testDefaultFromStyle() {
         Typeface typeface = Typeface.defaultFromStyle(Typeface.NORMAL);
         assertNotNull(typeface);
@@ -109,6 +132,7 @@
         assertNotNull(typeface);
     }
 
+    @Test
     public void testConstants() {
         assertNotNull(Typeface.DEFAULT);
         assertNotNull(Typeface.DEFAULT_BOLD);
@@ -117,47 +141,45 @@
         assertNotNull(Typeface.SERIF);
     }
 
-    public void testCreateFromAsset() {
+    @Test(expected=NullPointerException.class)
+    public void testCreateFromAssetNull() {
         // input abnormal params.
-        try {
-            Typeface.createFromAsset(null, null);
-            fail("Should throw a NullPointerException.");
-        } catch (NullPointerException e) {
-            // except here
-        }
+        Typeface.createFromAsset(null, null);
+    }
 
-        Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "samplefont.ttf");
+    @Test
+    public void testCreateFromAsset() {
+        Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf");
         assertNotNull(typeface);
     }
 
-    public void testCreateFromFile1() throws IOException {
+    @Test(expected=NullPointerException.class)
+    public void testCreateFromFileByFileReferenceNull() {
         // input abnormal params.
-        try {
-            Typeface.createFromFile((File)null);
-            fail("Should throw a NullPointerException.");
-        } catch (NullPointerException e) {
-            // except here
-        }
+        Typeface.createFromFile((File) null);
+    }
+
+    @Test
+    public void testCreateFromFileByFileReference() throws IOException {
         File file = new File(obtainPath());
         Typeface typeface = Typeface.createFromFile(file);
         assertNotNull(typeface);
     }
 
-    public void testCreateFromFile2() throws IOException {
+    @Test(expected=NullPointerException.class)
+    public void testCreateFromFileByFileNameNull() throws IOException {
         // input abnormal params.
-        try {
-            Typeface.createFromFile((String)null);
-            fail("Should throw a NullPointerException.");
-        } catch (NullPointerException e) {
-            // except here
-        }
+        Typeface.createFromFile((String) null);
+    }
 
+    @Test
+    public void testCreateFromFileByFileName() throws IOException {
         Typeface typeface = Typeface.createFromFile(obtainPath());
         assertNotNull(typeface);
     }
 
     private String obtainPath() throws IOException {
-        File dir = getContext().getFilesDir();
+        File dir = mContext.getFilesDir();
         dir.mkdirs();
         File file = new File(dir, "test.jpg");
         if (!file.createNewFile()) {
@@ -165,7 +187,7 @@
                 fail("Failed to create new File!");
             }
         }
-        InputStream is = getContext().getAssets().open("samplefont.ttf");
+        InputStream is = mContext.getAssets().open("samplefont.ttf");
         FileOutputStream fOutput = new FileOutputStream(file);
         byte[] dataBuffer = new byte[1024];
         int readLength = 0;
@@ -177,8 +199,9 @@
         return (file.getPath());
     }
 
+    @Test
     public void testInvalidCmapFont() {
-        Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "bombfont.ttf");
+        Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont.ttf");
         assertNotNull(typeface);
         Paint p = new Paint();
         final String testString = "abcde";
@@ -188,8 +211,9 @@
         assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
     }
 
+    @Test
     public void testInvalidCmapFont2() {
-        Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "bombfont2.ttf");
+        Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf");
         assertNotNull(typeface);
         Paint p = new Paint();
         final String testString = "abcde";
@@ -199,26 +223,25 @@
         assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
     }
 
-    @SmallTest
+    @Test
     public void testCreateFromAsset_cachesTypeface() {
-        Typeface typeface1 = Typeface.createFromAsset(getContext().getAssets(), "bombfont2.ttf");
+        Typeface typeface1 = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf");
         assertNotNull(typeface1);
 
-        Typeface typeface2 = Typeface.createFromAsset(getContext().getAssets(), "bombfont2.ttf");
+        Typeface typeface2 = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf");
         assertNotNull(typeface2);
         assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
 
-        Typeface typeface3 = Typeface.createFromAsset(getContext().getAssets(), "bombfont.ttf");
+        Typeface typeface3 = Typeface.createFromAsset(mContext.getAssets(), "bombfont.ttf");
         assertNotNull(typeface3);
         assertNotSame("Different font asset should return different Typeface object",
                 typeface2, typeface3);
 
-        Typeface typeface4 = Typeface.createFromAsset(getContext().getAssets(), "samplefont.ttf");
+        Typeface typeface4 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf");
         assertNotNull(typeface4);
         assertNotSame("Different font asset should return different Typeface object",
                 typeface2, typeface4);
         assertNotSame("Different font asset should return different Typeface object",
                 typeface3, typeface4);
     }
-
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
index d3edcbe..531549e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
@@ -16,21 +16,34 @@
 
 package android.graphics.cts;
 
-import android.content.Context;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
-import java.io.UnsupportedEncodingException;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.UnsupportedEncodingException;
 
 /**
  * Test that the Vulkan loader is present, supports the required extensions, and that system
  * features accurately indicate the capabilities of the Vulkan driver if one exists.
  */
-public class VulkanFeaturesTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VulkanFeaturesTest {
 
     static {
         System.loadLibrary("ctsgraphics_jni");
@@ -43,20 +56,14 @@
     // and there was an important bugfix relative to 1.0.2.
     private static final int VULKAN_1_0 = 0x00400003; // 1.0.3
 
-    PackageManager mPm;
-    FeatureInfo mVulkanHardwareLevel = null;
-    FeatureInfo mVulkanHardwareVersion = null;
-    JSONObject mVulkanDevices[];
+    private PackageManager mPm;
+    private FeatureInfo mVulkanHardwareLevel = null;
+    private FeatureInfo mVulkanHardwareVersion = null;
+    private JSONObject mVulkanDevices[];
 
-    public VulkanFeaturesTest() {
-        super();
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mPm = getContext().getPackageManager();
+    @Before
+    public void setup() throws Throwable {
+        mPm = InstrumentationRegistry.getTargetContext().getPackageManager();
         FeatureInfo features[] = mPm.getSystemAvailableFeatures();
         if (features != null) {
             for (FeatureInfo feature : features) {
@@ -77,6 +84,7 @@
         mVulkanDevices = getVulkanDevices();
     }
 
+    @Test
     public void testVulkanHardwareFeatures() throws JSONException {
         if (DEBUG) {
             Log.d(TAG, "Inspecting " + mVulkanDevices.length + " devices");
@@ -138,6 +146,7 @@
             isVersionCompatible(bestDeviceVersion, mVulkanHardwareVersion.version));
     }
 
+    @Test
     public void testVulkanVersionForVrHighPerformance() {
         if (!mPm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE))
             return;
diff --git a/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java b/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
index a2038b4..bebdc58 100644
--- a/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/YuvImageTest.java
@@ -15,29 +15,33 @@
  */
 package android.graphics.cts;
 
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.lang.Math;
-import java.io.IOException;
-import java.util.Arrays;
+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 android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.Color;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ImageFormat;
-import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.YuvImage;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import android.graphics.cts.R;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
 
-public class YuvImageTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class YuvImageTest {
     // Coefficients are taken from jcolor.c in libjpeg.
     private static final int CSHIFT = 16;
     private static final int CYR = 19595;
@@ -50,55 +54,52 @@
     private static final int CVG = -27439;
     private static final int CVB = -5329;
 
-    private static String TAG = "YuvImageTest";
+    private static final String TAG = "YuvImageTest";
 
-    private int[] mFormats = { ImageFormat.NV21, ImageFormat.YUY2 };
+    private static final int[] FORMATS = { ImageFormat.NV21, ImageFormat.YUY2 };
 
     private static final int WIDTH = 256;
     private static final int HEIGHT = 128;
-    private Bitmap[] mTestBitmaps = new Bitmap[1];
 
-    private int[] mRectWidths = { 128, 124, 123 };
-    private int[] mRectHeights = { 64, 60, 59 };
+    private static final int[] RECT_WIDTHS = { 128, 124, 123 };
+    private static final int[] RECT_HEIGHTS = { 64, 60, 59 };
 
     // Various rectangles:
     // mRects[0] : a normal one.
     // mRects[1] : same size to that of mRects[1], but its left-top point is shifted
     // mRects[2] : sides are not multiples of 16
     // mRects[3] : the left-top point is at an odd position
-    private Rect[] mRects = { new Rect(0, 0, 0 + mRectWidths[0],  0 + mRectHeights[0]),
-            new Rect(10, 10, 10 + mRectWidths[0], 10 + mRectHeights[0]),
-            new Rect(0, 0, 0 + mRectWidths[1], 0 + mRectHeights[1]),
-            new Rect(11, 11, 11 + mRectWidths[1], 11 + mRectHeights[1]) };
+    private static final Rect[] RECTS = { new Rect(0, 0, 0 + RECT_WIDTHS[0],  0 + RECT_HEIGHTS[0]),
+            new Rect(10, 10, 10 + RECT_WIDTHS[0], 10 + RECT_HEIGHTS[0]),
+            new Rect(0, 0, 0 + RECT_WIDTHS[1], 0 + RECT_HEIGHTS[1]),
+            new Rect(11, 11, 11 + RECT_WIDTHS[1], 11 + RECT_HEIGHTS[1]) };
 
     // Two rectangles of same size but at different positions
-    private Rect[] mRectsShifted = { mRects[0], mRects[1] };
+    private static final Rect[] RECTS_SHIFTED = { RECTS[0], RECTS[1] };
 
     // A rect whose side lengths are odd.
-    private Rect mRectOddSides = new Rect(10, 10, 10 + mRectWidths[2],
-            10 + mRectHeights[2]);
+    private static final Rect RECT_ODD_SIDES = new Rect(10, 10, 10 + RECT_WIDTHS[2],
+            10 + RECT_HEIGHTS[2]);
 
-    private int[] mPaddings = { 0, 32 };
+    private static final int[] PADDINGS = { 0, 32 };
 
     // There are three color components and
     // each should be within a square difference of 15 * 15.
-    private int mMseMargin = 3 * (15 * 15);
+    private static final int MSE_MARGIN = 3 * (15 * 15);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
+    private Bitmap[] mTestBitmaps = new Bitmap[1];
 
-    public void testYuvImage(){
+    @Test
+    public void testYuvImage() {
         int width = 100;
         int height = 100;
         byte[] yuv = new byte[width * height * 2];
         YuvImage image;
 
         // normal case: test that the required formats are all supported
-        for (int i = 0; i < mFormats.length; ++i) {
+        for (int i = 0; i < FORMATS.length; ++i) {
             try {
-                image = new YuvImage(yuv, mFormats[i], width, height, null);
+                new YuvImage(yuv, FORMATS[i], width, height, null);
             } catch (Exception e) {
                 Log.e(TAG, "unexpected exception", e);
                 fail("unexpected exception");
@@ -106,88 +107,78 @@
         }
 
         // normal case: test that default strides are returned correctly
-        for (int i = 0; i < mFormats.length; ++i) {
+        for (int i = 0; i < FORMATS.length; ++i) {
             int[] expected = null;
             int[] actual = null;
-            if (mFormats[i] == ImageFormat.NV21) {
-                expected = new int[] {width, width};
-            } else if (mFormats[i] == ImageFormat.YUY2) {
-                expected = new int[] {width * 2};
+            if (FORMATS[i] == ImageFormat.NV21) {
+                expected = new int[]{width, width};
+            } else if (FORMATS[i] == ImageFormat.YUY2) {
+                expected = new int[]{width * 2};
             }
 
             try {
-                image = new YuvImage(yuv, mFormats[i], width, height, null);
+                image = new YuvImage(yuv, FORMATS[i], width, height, null);
                 actual = image.getStrides();
                 assertTrue("default strides not calculated correctly",
                         Arrays.equals(expected, actual));
-            } catch (Exception e){
+            } catch (Exception e) {
                 Log.e(TAG, "unexpected exception", e);
                 fail("unexpected exception");
             }
         }
+    }
 
-        int format = mFormats[0];
+    @Test(expected=IllegalArgumentException.class)
+    public void testYuvImageNegativeWidth(){
+        new YuvImage(new byte[100 * 100 * 2], FORMATS[0], -1, 100, null);
+    }
 
-        // abnormal case: width is non-positive
-        try {
-            image = new YuvImage(yuv, format, -1, height, null);
-            fail("not catching illegal width");
-        } catch(IllegalArgumentException e) {
-          // expected
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testYuvImageNegativeHeight(){
+        new YuvImage(new byte[100 * 100 * 2], FORMATS[0], 100, -1, null);
+    }
 
-        // abnormal case: height is non-positive
-        try {
-            image = new YuvImage(yuv, format, width, -1, null);
-            fail("not catching illegal height");
-        } catch(IllegalArgumentException e) {
-          // expected
-        }
-
-        // abnormal case: yuv array is null
-        try {
-            image = new YuvImage(null, format, width, height, null);
-            fail("not catching null yuv data");
-        } catch(IllegalArgumentException e) {
-          // expected
-        }
-
+    @Test(expected=IllegalArgumentException.class)
+    public void testYuvImageNullArray(){
+        new YuvImage(null, FORMATS[0], 100, 100, null);
    }
 
+    @Test
     public void testCompressYuvToJpeg() {
         generateTestBitmaps(WIDTH, HEIGHT);
 
         // test if handling compression parameters correctly
-        checkParameters();
+        verifyParameters();
 
         // test various cases by varing
         // <ImageFormat, Bitmap, HasPaddings, Rect>
-        for (int i = 0; i < mFormats.length; ++i) {
+        for (int i = 0; i < FORMATS.length; ++i) {
             for (int j = 0; j < mTestBitmaps.length; ++j) {
-                for (int k = 0; k < mPaddings.length; ++k) {
-                    YuvImage image = generateYuvImage(mFormats[i],
-                        mTestBitmaps[j], mPaddings[k]);
-                    for (int l = 0; l < mRects.length; ++l) {
+                for (int k = 0; k < PADDINGS.length; ++k) {
+                    YuvImage image = generateYuvImage(FORMATS[i],
+                        mTestBitmaps[j], PADDINGS[k]);
+                    for (int l = 0; l < RECTS.length; ++l) {
 
                         // test compressing the same rect in
                         // mTestBitmaps[j] and image.
                         compressRects(mTestBitmaps[j], image,
-                                mRects[l], mRects[l]);
+                                RECTS[l], RECTS[l]);
                     }
 
                     // test compressing different rects in
                     // mTestBitmap[j] and image.
-                    compressRects(mTestBitmaps[j], image, mRectsShifted[0],
-                            mRectsShifted[1]);
+                    compressRects(mTestBitmaps[j], image, RECTS_SHIFTED[0],
+                            RECTS_SHIFTED[1]);
 
                     // test compressing a rect whose side lengths are odd.
-                    compressOddRect(mTestBitmaps[j], image, mRectOddSides);
+                    compressOddRect(mTestBitmaps[j], image, RECT_ODD_SIDES);
                 }
             }
         }
 
     }
 
+    @Test
     public void testGetHeight() {
         generateTestBitmaps(WIDTH, HEIGHT);
         YuvImage image = generateYuvImage(ImageFormat.YUY2, mTestBitmaps[0], 0);
@@ -195,6 +186,7 @@
         assertEquals(mTestBitmaps[0].getWidth(), image.getWidth());
     }
 
+    @Test
     public void testGetYuvData() {
         generateTestBitmaps(WIDTH, HEIGHT);
         int width = mTestBitmaps[0].getWidth();
@@ -210,6 +202,7 @@
         assertEquals(yuv, image.getYuvData());
     }
 
+    @Test
     public void testGetYuvFormat() {
         generateTestBitmaps(WIDTH, HEIGHT);
         YuvImage image = generateYuvImage(ImageFormat.YUY2, mTestBitmaps[0], 0);
@@ -221,7 +214,7 @@
         Canvas c = new Canvas(dst);
 
         // mTestBitmap[0] = scaled testimage.jpg
-        Resources res = getContext().getResources();
+        Resources res = InstrumentationRegistry.getTargetContext().getResources();
         Bitmap src = BitmapFactory.decodeResource(res, R.drawable.testimage);
         c.drawBitmap(src, null, new Rect(0, 0, WIDTH, HEIGHT), null);
         mTestBitmaps[0] = dst;
@@ -263,8 +256,9 @@
         actual = compressDecompress(image, actualRect);
 
         Rect expectedRect = sameRect ? actualRect : rect1;
-        expected = Bitmap.createBitmap(testBitmap, expectedRect.left, expectedRect.top, expectedRect.width(), expectedRect.height());
-        compareBitmaps(expected, actual, mMseMargin, sameRect);
+        expected = Bitmap.createBitmap(testBitmap, expectedRect.left, expectedRect.top,
+                expectedRect.width(), expectedRect.height());
+        compareBitmaps(expected, actual, MSE_MARGIN, sameRect);
     }
 
     // Compress rect in image.
@@ -280,7 +274,7 @@
         expected = Bitmap.createBitmap(testBitmap, newRect.left, newRect.top,
               newRect.width(), newRect.height());
 
-        compareBitmaps(expected, actual, mMseMargin, true);
+        compareBitmaps(expected, actual, MSE_MARGIN, true);
     }
 
     // Compress rect in image to a jpeg and then decode the jpeg to a bitmap.
@@ -392,7 +386,7 @@
         yuv[2] = (byte) (((CVR * r + CVG * g + CVB * b) >> CSHIFT) + 128);
     }
 
-    private void checkParameters() {
+    private void verifyParameters() {
         int format = ImageFormat.NV21;
         int[] argb = new int[WIDTH * HEIGHT];
         mTestBitmaps[0].getPixels(argb, 0, WIDTH, 0, 0, WIDTH, HEIGHT);
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..0266e34
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/Animatable2_AnimationCallbackTest.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.graphics.drawable.cts;
+
+import android.graphics.drawable.Animatable2.AnimationCallback;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Animatable2_AnimationCallbackTest {
+    @Test
+    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/AnimatedStateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
index 12f9828..f8cd816 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
@@ -16,10 +16,15 @@
 
 package android.graphics.drawable.cts;
 
-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.mock;
 
-import android.R.attr;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -32,31 +37,38 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
 import android.graphics.drawable.StateListDrawable;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.StateSet;
 import android.util.Xml;
 
+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;
 import java.util.Arrays;
 import java.util.HashSet;
 
-import static org.mockito.Mockito.mock;
-
-public class AnimatedStateListDrawableTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatedStateListDrawableTest {
     private static final int[] STATE_EMPTY = new int[] { };
-    private static final int[] STATE_FOCUSED = new int[] { attr.state_focused };
+    private static final int[] STATE_FOCUSED = new int[] { android.R.attr.state_focused };
 
     private Context mContext;
     private Resources mResources;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mResources = mContext.getResources();
     }
 
+    @Test
     public void testStateListDrawable() {
         new AnimatedStateListDrawable();
 
@@ -64,6 +76,7 @@
         assertNotNull(new AnimatedStateListDrawable().getConstantState());
     }
 
+    @Test
     public void testAddState() {
         AnimatedStateListDrawable asld = new AnimatedStateListDrawable();
         DrawableContainerState cs = (DrawableContainerState) asld.getConstantState();
@@ -85,6 +98,7 @@
         assertEquals(2, cs.getChildCount());
     }
 
+    @Test
     public void testAddTransition() {
         AnimatedStateListDrawable asld = new AnimatedStateListDrawable();
         DrawableContainerState cs = (DrawableContainerState) asld.getConstantState();
@@ -114,10 +128,12 @@
         assertEquals(5, cs.getChildCount());
     }
 
+    @Test
     public void testIsStateful() {
         assertTrue(new AnimatedStateListDrawable().isStateful());
     }
 
+    @Test
     public void testOnStateChange() {
         AnimatedStateListDrawable asld = new AnimatedStateListDrawable();
 
@@ -141,11 +157,13 @@
         assertSame(unfocusedToFocused, asld.getCurrent());
     }
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
         runPreloadDensityTestForDrawable(
                 R.drawable.animated_state_list_density, false);
     }
 
+    @Test
     public void testPreloadDensityConstantSize() throws XmlPullParserException, IOException {
         runPreloadDensityTestForDrawable(
                 R.drawable.animated_state_list_density_constant_size, true);
@@ -212,8 +230,7 @@
 
     private XmlResourceParser getResourceParser(int resId) throws XmlPullParserException,
             IOException {
-        XmlResourceParser parser = getInstrumentation().getTargetContext().getResources().getXml(
-                resId);
+        XmlResourceParser parser = mResources.getXml(resId);
         int type;
         while ((type = parser.next()) != XmlPullParser.START_TAG
                 && type != XmlPullParser.END_DOCUMENT) {
@@ -222,6 +239,7 @@
         return parser;
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         AnimatedStateListDrawable asld = (AnimatedStateListDrawable) mContext.getDrawable(
                 R.drawable.animated_state_list_density);
@@ -232,6 +250,16 @@
         assertEquals(4, asldState.getChildCount());
     }
 
+    @Test
+    public void testParsingTransitionDefinedWithAVD() {
+        AnimatedStateListDrawable asld = (AnimatedStateListDrawable) mContext.getDrawable(
+                R.drawable.animated_state_list_with_avd);
+        DrawableContainerState asldState = (DrawableContainerState) asld.getConstantState();
+        // Ensure that everything defined in xml after the definition of a transition with AVD is
+        // parsed by checking the total drawables parsed.
+        assertEquals(6, asldState.getChildCount());
+    }
+
     public abstract class MockTransition extends MockDrawable implements Animatable, Animatable2 {
         private HashSet<AnimationCallback> mCallbacks = new HashSet<>();
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
new file mode 100644
index 0000000..c52cd25
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
@@ -0,0 +1,313 @@
+/*
+ * 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 com.android.compatibility.common.util.SystemUtil;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static android.graphics.drawable.cts.AnimatedVectorDrawableTest.saveVectorDrawableIntoPNG;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class AnimatedVectorDrawableParameterizedTest {
+    @Rule
+    public ActivityTestRule<DrawableStubActivity> mActivityRule =
+            new ActivityTestRule<>(DrawableStubActivity.class);
+
+    private static final int IMAGE_WIDTH = 64;
+    private static final int IMAGE_HEIGHT = 64;
+    private static final long MAX_TIMEOUT_MS = 1000;
+
+    private static float sTransitionScaleBefore = Float.NaN;
+
+    private Activity mActivity = null;
+    private Resources mResources = null;
+    private final int mLayerType;
+
+    @Parameterized.Parameters
+    public static Object[] data() {
+        return new Object[] {
+                View.LAYER_TYPE_HARDWARE,
+                View.LAYER_TYPE_NONE,
+                View.LAYER_TYPE_SOFTWARE
+        };
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        try {
+            sTransitionScaleBefore = Float.parseFloat(SystemUtil.runShellCommand(
+                    InstrumentationRegistry.getInstrumentation(),
+                    "settings get global transition_animation_scale"));
+
+            SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                    "settings put global transition_animation_scale 0");
+        } catch (NumberFormatException e) {
+            Log.e("AnimatedVectorDrawableTest", "Could not read transition_animation_scale", e);
+            sTransitionScaleBefore = Float.NaN;
+        }
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+        if (sTransitionScaleBefore != Float.NaN) {
+            SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                    "settings put global transition_animation_scale " +
+                            sTransitionScaleBefore);
+        }
+    }
+
+    public AnimatedVectorDrawableParameterizedTest(final int layerType) throws Throwable {
+        mLayerType = layerType;
+    }
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mResources = mActivity.getResources();
+    }
+
+    @Test
+    public void testAnimationOnLayer() throws Throwable {
+        final AnimatedVectorDrawableTest.MyCallback callback
+                = new AnimatedVectorDrawableTest.MyCallback();
+        final Rect imageViewRect = new Rect();
+        final int size = mResources.getDimensionPixelSize(R.dimen.imageview_fixed_size);
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(R.layout.fixed_sized_imageview);
+            final ImageView imageView = (ImageView) mActivity.findViewById(R.id.imageview);
+            imageView.setLayerType(mLayerType, null);
+            AnimatedVectorDrawable avd = (AnimatedVectorDrawable) imageView.getDrawable();
+            avd.registerAnimationCallback(callback);
+            int[] locationOnScreen = new int[2];
+            imageView.getLocationOnScreen(locationOnScreen);
+            imageViewRect.set(locationOnScreen[0], locationOnScreen[1],
+                    locationOnScreen[0] + size, locationOnScreen[1] + size);
+            avd.start();
+        });
+        callback.waitForStart();
+
+        // Wait another few frames to make sure that RT has started and rendered the animation, and
+        // the frame buffer with the started animation is being rendered on screen.
+        waitWhilePumpingFrames(5, mActivity.findViewById(R.id.imageview), 200);
+        Bitmap lastScreenShot = null;
+        int counter = 0;
+        while (!callback.endIsCalled()) {
+            // Take a screen shot every 50ms, and compare with previous screenshot for the ImageView
+            // content, to make sure the AVD is animating when set on HW layer.
+            Bitmap screenShot = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .takeScreenshot();
+            if (callback.endIsCalled()) {
+                // Animation already ended, the screenshot may not contain valid animation content,
+                // skip the comparison.
+                break;
+            }
+            counter++;
+            boolean isIdentical = isAlmostIdenticalInRect(screenShot, lastScreenShot, imageViewRect);
+            if (isIdentical) {
+                saveVectorDrawableIntoPNG(screenShot, "screenshot_" + counter);
+                saveVectorDrawableIntoPNG(lastScreenShot, "screenshot_" + (counter - 1));
+                fail("Two consecutive screenshots of AVD are identical, AVD is " +
+                        "likely not animating");
+            }
+            lastScreenShot = screenShot;
+
+            // Wait 50ms before the next screen shot. If animation ended during the wait, exit the
+            // loop.
+            if (callback.waitForEnd(50)) {
+                break;
+            }
+        }
+        // In this test, we want to make sure that we at least have 5 screenshots.
+        assertTrue(counter >= 5);
+    }
+
+    // Pump frames by repeatedly invalidating the given view. Return true if successfully pumped
+    // the given number of frames before timeout, false otherwise.
+    private boolean waitWhilePumpingFrames(int frameCount, final View view, long timeout)
+            throws Throwable {
+        final CountDownLatch frameLatch = new CountDownLatch(frameCount);
+        mActivityRule.runOnUiThread(() -> {
+            view.getViewTreeObserver().addOnPreDrawListener(() -> {
+                if (frameLatch.getCount() > 0) {
+                    frameLatch.countDown();
+                    view.postInvalidate();
+                }
+                return true;
+            });
+        });
+        return frameLatch.await(timeout, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void testSingleFrameAnimation() throws Throwable {
+        int resId = R.drawable.avd_single_frame;
+        final AnimatedVectorDrawable d1 =
+                (AnimatedVectorDrawable) mResources.getDrawable(resId);
+        // The AVD has a duration as 16ms.
+        mActivityRule.runOnUiThread(() -> {
+            Bitmap bitmap =
+                    Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+
+            mActivity.setContentView(R.layout.animated_vector_drawable_source);
+            ImageView imageView = (ImageView) mActivity.findViewById(R.id.avd_view);
+            imageView.setLayerType(mLayerType, null);
+            imageView.setImageDrawable(d1);
+            d1.start();
+            d1.stop();
+            d1.setBounds(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+            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);
+        });
+    }
+
+    @Test
+    public void testEmptyAnimatorSet() throws Throwable {
+        int resId = R.drawable.avd_empty_animator;
+        final AnimatedVectorDrawableTest.MyCallback callback =
+                new AnimatedVectorDrawableTest.MyCallback();
+        final AnimatedVectorDrawable d1 =
+                (AnimatedVectorDrawable) mResources.getDrawable(resId);
+        d1.registerAnimationCallback(callback);
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(R.layout.animated_vector_drawable_source);
+            ImageView imageView = (ImageView) mActivity.findViewById(R.id.avd_view);
+            imageView.setLayerType(mLayerType, null);
+            imageView.setImageDrawable(d1);
+            d1.registerAnimationCallback(callback);
+            d1.start();
+        });
+        Assert.assertTrue(callback.waitForStart());
+        AnimatedVectorDrawableTest.waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        // Check that the AVD with empty AnimatorSet has finished
+        callback.assertEnded(true);
+        callback.assertAVDRuntime(0, TimeUnit.MILLISECONDS.toNanos(64)); // 4 frames
+    }
+
+    // Does a fuzzy comparison between two images in the given rect. Returns true if the rect area
+    // is within acceptable delta, false otherwise.
+    private static boolean isAlmostIdenticalInRect(Bitmap image1, Bitmap image2, Rect rangeRect) {
+        if (image1 == null || image2 == null) {
+            return false;
+        }
+        for (int x = rangeRect.left; x < rangeRect.right; x++) {
+            for (int y = rangeRect.top; y < rangeRect.bottom; y++) {
+                if (image1.getPixel(x, y) != image2.getPixel(x, y)) {
+                    return false;
+                }
+                int color1 = image1.getPixel(x, y);
+                int color2 = image2.getPixel(x, y);
+                int rDiff = Math.abs(Color.red(color1) - Color.red(color2));
+                int gDiff = Math.abs(Color.green(color1) - Color.green(color2));
+                int bDiff = Math.abs(Color.blue(color1) - Color.blue(color2));
+                if (rDiff + gDiff + bDiff > 8) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Test
+    public void testInfiniteAVD() throws Throwable {
+        final AnimatedVectorDrawableTest.MyCallback callback
+                = new AnimatedVectorDrawableTest.MyCallback();
+        final Rect imageViewRect = new Rect();
+        final int size = mResources.getDimensionPixelSize(R.dimen.imageview_fixed_size);
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(R.layout.fixed_sized_imageview);
+            final ImageView imageView = (ImageView) mActivity.findViewById(R.id.imageview);
+            imageView.setImageDrawable(mResources.getDrawable(R.drawable.infinite_avd));
+            imageView.setLayerType(mLayerType, null);
+            AnimatedVectorDrawable avd = (AnimatedVectorDrawable) imageView.getDrawable();
+            avd.registerAnimationCallback(callback);
+            int[] locationOnScreen = new int[2];
+            imageView.getLocationOnScreen(locationOnScreen);
+            imageViewRect.set(locationOnScreen[0], locationOnScreen[1],
+                    locationOnScreen[0] + size, locationOnScreen[1] + size);
+            avd.start();
+        });
+        callback.waitForStart();
+
+        // Wait another few frames to make sure that RT has started and rendered the animation, and
+        // the frame buffer with the started animation is being rendered on screen.
+        waitWhilePumpingFrames(5, mActivity.findViewById(R.id.imageview), 200);
+        Bitmap lastScreenShot = null;
+
+        for (int counter = 0; counter < 10; counter++) {
+            // Take a screen shot every 100ms, and compare with previous screenshot for the ImageView
+            // content, to make sure the AVD is animating when set on HW layer.
+            Bitmap screenShot = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .takeScreenshot();
+            boolean isIdentical = isAlmostIdenticalInRect(screenShot, lastScreenShot, imageViewRect);
+            if (isIdentical) {
+                saveVectorDrawableIntoPNG(screenShot, "inf_avd_screenshot_" + mLayerType + "_" +
+                        counter);
+                saveVectorDrawableIntoPNG(lastScreenShot, "inf_avd_screenshot_" + mLayerType + "_" +
+                        (counter - 1));
+                fail("Two consecutive screenshots of AVD are identical, AVD is " +
+                        "likely not animating");
+            }
+            lastScreenShot = screenShot;
+            counter++;
+
+            // Wait 100ms before the next screen shot. If animation ended during the wait, fail the
+            // test, as the infinite avd should not end until we call stop().
+            if (callback.waitForEnd(100)) {
+                fail("Infinite AnimatedVectorDrawable should not end on its own.");
+            }
+        }
+        Assert.assertFalse(callback.endIsCalled());
+        mActivityRule.runOnUiThread(() -> {
+            ImageView imageView = (ImageView) mActivity.findViewById(R.id.imageview);
+            AnimatedVectorDrawable avd = (AnimatedVectorDrawable) imageView.getDrawable();
+            avd.stop();
+        });
+    }
+
+}
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..e383ec2 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable.cts;
 
+import android.app.Activity;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -28,14 +29,18 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
 import android.widget.ImageView;
 
+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;
 
@@ -43,41 +48,51 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-import static java.lang.Thread.sleep;
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
-public class AnimatedVectorDrawableTest extends ActivityInstrumentationTestCase2<DrawableStubActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatedVectorDrawableTest {
     private static final String LOGTAG = AnimatedVectorDrawableTest.class.getSimpleName();
 
     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;
+    @Rule
+    public ActivityTestRule<DrawableStubActivity> mActivityRule =
+            new ActivityTestRule<DrawableStubActivity>(DrawableStubActivity.class);
+    private Activity 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;
     private final int mImageViewId = R.id.avd_view;
 
-
-    public AnimatedVectorDrawableTest() {
-        super(DrawableStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mBitmap = Bitmap.createBitmap(IMAGE_WIDTH, IMAGE_HEIGHT, Bitmap.Config.ARGB_8888);
-        mCanvas = new Canvas(mBitmap);
-
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mResources = mActivity.getResources();
     }
 
     // This is only for debugging or golden image (re)generation purpose.
     private void saveVectorDrawableIntoPNG(Bitmap bitmap, int resId) throws IOException {
+        String originalFilePath = mResources.getString(resId);
+        File originalFile = new File(originalFilePath);
+        String fileFullName = originalFile.getName();
+        String fileTitle = fileFullName.substring(0, fileFullName.lastIndexOf("."));
+        saveVectorDrawableIntoPNG(bitmap, fileTitle);
+    }
+
+    // Save a bitmap to the given name under /sdcard/temp/
+    static void saveVectorDrawableIntoPNG(Bitmap bitmap, String fileFullName)
+            throws IOException {
         // Save the image to the disk.
         FileOutputStream out = null;
         try {
@@ -86,11 +101,7 @@
             if (!folder.exists()) {
                 folder.mkdir();
             }
-            String originalFilePath = mResources.getString(resId);
-            File originalFile = new File(originalFilePath);
-            String fileFullName = originalFile.getName();
-            String fileTitle = fileFullName.substring(0, fileFullName.lastIndexOf("."));
-            String outputFilename = outputFolder + fileTitle + "_golden.png";
+            String outputFilename = outputFolder + fileFullName + "_golden.png";
             File outputFile = new File(outputFilename);
             if (!outputFile.exists()) {
                 outputFile.createNewFile();
@@ -108,7 +119,7 @@
         }
     }
 
-    @MediumTest
+    @Test
     public void testInflate() throws Exception {
         // Setup AnimatedVectorDrawable from xml file
         XmlPullParser parser = mResources.getXml(mResId);
@@ -123,52 +134,24 @@
         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 {
-        int resId = R.drawable.avd_single_frame;
-        final AnimatedVectorDrawable d1 =
-                (AnimatedVectorDrawable) mResources.getDrawable(resId);
-        // The AVD has a duration as 16ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                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);
-            }
-        });
-
-        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
+    @Test
     public void testGetChangingConfigurations() {
         AnimatedVectorDrawable avd = new AnimatedVectorDrawable();
         ConstantState constantState = avd.getConstantState();
@@ -192,7 +175,7 @@
         assertEquals(0xffff,  avd.getChangingConfigurations());
     }
 
-    @SmallTest
+    @Test
     public void testGetConstantState() {
         AnimatedVectorDrawable AnimatedVectorDrawable = new AnimatedVectorDrawable();
         ConstantState constantState = AnimatedVectorDrawable.getConstantState();
@@ -205,7 +188,7 @@
         assertEquals(1, constantState.getChangingConfigurations());
     }
 
-    @SmallTest
+    @Test
     public void testMutate() {
         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
         AnimatedVectorDrawable d2 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -233,7 +216,7 @@
         assertEquals(originalAlpha, d3.getAlpha());
     }
 
-    @SmallTest
+    @Test
     public void testGetOpacity() {
         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
         assertEquals("Default is translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
@@ -241,7 +224,7 @@
         assertEquals("Still translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
     }
 
-    @SmallTest
+    @Test
     public void testColorFilter() {
         PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -250,158 +233,218 @@
         assertEquals(filter, d1.getColorFilter());
     }
 
-    @MediumTest
-    public void testReset() {
+    @Test
+    public void testReset() throws Throwable {
+        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.start();
-                d1.reset();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            d1.registerAnimationCallback(callback);
+            d1.start();
+            d1.reset();
         });
-        getInstrumentation().waitForIdleSync();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
         assertFalse(d1.isRunning());
 
     }
 
-    @MediumTest
-    public void testStop() {
+    @Test
+    public void testStop() throws Throwable {
+        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.start();
-                d1.stop();
-
-            }
+        mActivityRule.runOnUiThread(() -> {
+            d1.registerAnimationCallback(callback);
+            d1.start();
+            d1.stop();
         });
-        getInstrumentation().waitForIdleSync();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
         assertFalse(d1.isRunning());
     }
 
-    @MediumTest
-    public void testAddCallbackBeforeStart() throws InterruptedException {
+    @Test
+    public void testAddCallbackBeforeStart() throws Throwable {
         final MyCallback callback = new MyCallback();
         // The AVD has a duration as 100ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(mLayoutId);
-                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
-                AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
-                d1.registerAnimationCallback(callback);
-                d1.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mLayoutId);
+            ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+            AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+            d1.registerAnimationCallback(callback);
+            d1.start();
         });
-        getInstrumentation().waitForIdleSync();
-        sleep(200);
-        assertTrue(callback.mStart);
-        assertTrue(callback.mEnd);
+        callback.waitForStart();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        callback.assertStarted(true);
+        callback.assertEnded(true);
     }
 
-    @MediumTest
-    public void testAddCallbackAfterTrigger() throws InterruptedException {
+    @Test
+    public void testAddCallbackAfterTrigger() throws Throwable {
         final MyCallback callback = new MyCallback();
         // The AVD has a duration as 100ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(mLayoutId);
-                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
-                AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
-                // This reset call can enforce the AnimatorSet is setup properly in AVD, when
-                // running on UI thread.
-                d1.reset();
-                d1.registerAnimationCallback(callback);
-                d1.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mLayoutId);
+            ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+            AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+            // This reset call can enforce the AnimatorSet is setup properly in AVD, when
+            // running on UI thread.
+            d1.reset();
+            d1.registerAnimationCallback(callback);
+            d1.start();
         });
-        getInstrumentation().waitForIdleSync();
-        sleep(200);
-        assertTrue(callback.mStart);
-        assertTrue(callback.mEnd);
+        callback.waitForStart();
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+
+        callback.assertStarted(true);
+        callback.assertEnded(true);
     }
 
-    @MediumTest
-    public void testAddCallbackAfterStart() throws InterruptedException {
+    @Test
+    public void testAddCallbackAfterStart() throws Throwable {
         final MyCallback callback = new MyCallback();
         // The AVD has a duration as 100ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(mLayoutId);
-                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
-                AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
-                d1.start();
-                d1.registerAnimationCallback(callback);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mLayoutId);
+            ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+            AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+            d1.start();
+            d1.registerAnimationCallback(callback);
         });
-        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() {
+    @Test
+    public void testRemoveCallback() throws Throwable {
         final MyCallback callback = new MyCallback();
         // The AVD has a duration as 100ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(mLayoutId);
-                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
-                AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
-                d1.registerAnimationCallback(callback);
-                assertTrue(d1.unregisterAnimationCallback(callback));
-                d1.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mLayoutId);
+            ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+            AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+            d1.registerAnimationCallback(callback);
+            assertTrue(d1.unregisterAnimationCallback(callback));
+            d1.start();
         });
-        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() {
+    @Test
+    public void testClearCallback() throws Throwable {
         final MyCallback callback = new MyCallback();
 
         // The AVD has a duration as 100ms.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(mLayoutId);
-                ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
-                AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
-                d1.registerAnimationCallback(callback);
-                d1.clearAnimationCallbacks();
-                d1.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mLayoutId);
+            ImageView imageView = (ImageView) mActivity.findViewById(mImageViewId);
+            AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) imageView.getDrawable();
+            d1.registerAnimationCallback(callback);
+            d1.clearAnimationCallbacks();
+            d1.start();
         });
+        callback.waitForStart();
 
-        getInstrumentation().waitForIdleSync();
-
-        assertFalse(callback.mStart);
-        assertFalse(callback.mEnd);
+        waitForAVDStop(callback, MAX_TIMEOUT_MS);
+        callback.assertStarted(false);
+        callback.assertEnded(false);
     }
 
-    class MyCallback extends Animatable2.AnimationCallback {
-        boolean mStart = false;
-        boolean mEnd = false;
+    // The time out is expected when the listener is removed successfully.
+    // Such that we don't get the end event.
+    static 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.
+    static class MyCallback extends Animatable2.AnimationCallback {
+        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 boolean waitForEnd(long timeoutMs) throws InterruptedException {
+            synchronized (mEndLock) {
+                if (!mEnded) {
+                    // Return immediately if the AVD has already ended.
+                    mEndLock.wait(timeoutMs);
+                }
+                return mEnded;
+            }
+        }
+
+        public boolean waitForStart() throws InterruptedException {
+            synchronized(mStartLock) {
+                if (!mStarted) {
+                    // Return immediately if the AVD has already started.
+                    mStartLock.wait(MAX_START_TIMEOUT_MS);
+                }
+                return mStarted;
+            }
+        }
 
         @Override
         public void onAnimationStart(Drawable drawable) {
-            mStart = true;
+            mStartNs = System.nanoTime();
+            synchronized(mStartLock) {
+                mStarted = true;
+                mStartLock.notify();
+            }
         }
 
         @Override
         public void onAnimationEnd(Drawable drawable) {
-            mEnd = true;
+            mEndNs = System.nanoTime();
+            synchronized (mEndLock) {
+                mEnded = true;
+                mEndLock.notify();
+            }
+        }
+
+        public boolean endIsCalled() {
+            synchronized (mEndLock) {
+                return mEnded;
+            }
+        }
+
+        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/AnimationDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
index 33b99a4..7b3cab9 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
@@ -16,27 +16,43 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.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 android.app.Activity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.cts.util.PollingCheck;
+import android.graphics.cts.ImageViewCtsActivity;
+import android.graphics.cts.R;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Xml;
 import android.widget.ImageView;
-import android.graphics.cts.ImageViewCtsActivity;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+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;
 
-public class AnimationDrawableTest extends ActivityInstrumentationTestCase2<ImageViewCtsActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AnimationDrawableTest {
     private static final int FRAMES_COUNT        = 3;
     private static final int FIRST_FRAME_INDEX   = 0;
     private static final int SECOND_FRAME_INDEX  = 1;
@@ -49,158 +65,112 @@
     private AnimationDrawable mAnimationDrawable;
     private Resources mResources;
 
-    public AnimationDrawableTest() {
-        super("android.graphics.cts", ImageViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ImageViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ImageViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        final Activity activity = getActivity();
+    @UiThreadTest
+    @Before
+    public void setup() throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
         mResources = activity.getResources();
-        try {
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                    ImageView imageView = (ImageView) activity.findViewById(R.id.imageview);
-                    imageView.setBackgroundResource(R.drawable.animationdrawable);
-                    mAnimationDrawable = (AnimationDrawable) imageView.getBackground();
-                }
-            });
-        } catch (Throwable t) {
-            throw new Exception(t);
-        }
+
+        ImageView imageView = (ImageView) activity.findViewById(R.id.imageview);
+        imageView.setBackgroundResource(R.drawable.animationdrawable);
+        mAnimationDrawable = (AnimationDrawable) imageView.getBackground();
     }
 
+    @Test
     public void testConstructor() {
-        mAnimationDrawable = new AnimationDrawable();
+        AnimationDrawable animationDrawable = new AnimationDrawable();
         // Check the values set in the constructor
-        assertNotNull(mAnimationDrawable.getConstantState());
-        assertFalse(mAnimationDrawable.isRunning());
-        assertFalse(mAnimationDrawable.isOneShot());
+        assertNotNull(animationDrawable.getConstantState());
+        assertFalse(animationDrawable.isRunning());
+        assertFalse(animationDrawable.isOneShot());
     }
 
+    @Test
     public void testSetVisible() throws Throwable {
         assertTrue(mAnimationDrawable.isVisible());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.start();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::start);
         assertTrue(mAnimationDrawable.isRunning());
-        assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX),
-                mAnimationDrawable.getCurrent());
+        assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX), mAnimationDrawable.getCurrent());
 
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mAnimationDrawable.setVisible(false, false));
-            }
-        });
+        mActivityRule.runOnUiThread(() -> assertTrue(mAnimationDrawable.setVisible(false, false)));
         assertFalse(mAnimationDrawable.isVisible());
         assertFalse(mAnimationDrawable.isRunning());
-        assertStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
+        verifyStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
 
         // restart animation
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mAnimationDrawable.setVisible(true, true));
-            }
-        });
+        mActivityRule.runOnUiThread(() -> assertTrue(mAnimationDrawable.setVisible(true, true)));
         assertTrue(mAnimationDrawable.isVisible());
         assertTrue(mAnimationDrawable.isRunning());
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
     }
 
+    @Test
     public void testStart() throws Throwable {
         // animation should play repeat if do not stop it.
         assertFalse(mAnimationDrawable.isOneShot());
         assertFalse(mAnimationDrawable.isRunning());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.start();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::start);
 
         assertTrue(mAnimationDrawable.isRunning());
         assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX),
                 mAnimationDrawable.getCurrent());
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // This method has no effect if the animation is running.
-                mAnimationDrawable.start();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::start);
         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.stop();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::stop);
         assertFalse(mAnimationDrawable.isRunning());
-        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // This method has no effect if the animation is not running.
-                mAnimationDrawable.stop();
-            }
-        });
+        // This method has no effect if the animation is not running.
+        mActivityRule.runOnUiThread(mAnimationDrawable::stop);
         assertFalse(mAnimationDrawable.isRunning());
-        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
     }
 
+    @Test
     public void testRun() throws Throwable {
         assertFalse(mAnimationDrawable.isRunning());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.run();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::run);
 
         assertTrue(mAnimationDrawable.isRunning());
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.unscheduleSelf(mAnimationDrawable);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mAnimationDrawable.unscheduleSelf(mAnimationDrawable));
     }
 
+    @Test
     public void testUnscheduleSelf() throws Throwable {
         assertFalse(mAnimationDrawable.isRunning());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.start();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::start);
 
         assertTrue(mAnimationDrawable.isRunning());
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.unscheduleSelf(mAnimationDrawable);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mAnimationDrawable.unscheduleSelf(mAnimationDrawable));
         assertFalse(mAnimationDrawable.isRunning());
-        assertStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
+        verifyStoppedAnimation(SECOND_FRAME_INDEX, SECOND_FRAME_DURATION);
     }
 
+    @Test
     public void testGetNumberOfFrames() {
-        assertEquals(FRAMES_COUNT, mAnimationDrawable.getNumberOfFrames());
+        AnimationDrawable mutated = (AnimationDrawable) mAnimationDrawable.mutate();
+        assertEquals(FRAMES_COUNT, mutated.getNumberOfFrames());
 
         Drawable frame = mResources.getDrawable(R.drawable.failed);
         mAnimationDrawable.addFrame(frame, 2000);
-        assertEquals(FRAMES_COUNT + 1, mAnimationDrawable.getNumberOfFrames());
+        assertEquals(FRAMES_COUNT + 1, mutated.getNumberOfFrames());
 
         // add same frame with same duration
         mAnimationDrawable.addFrame(frame, 2000);
-        assertEquals(FRAMES_COUNT + 2, mAnimationDrawable.getNumberOfFrames());
+        assertEquals(FRAMES_COUNT + 2, mutated.getNumberOfFrames());
 
         try {
             mAnimationDrawable.addFrame(null, 1000);
@@ -210,6 +180,7 @@
         }
     }
 
+    @Test
     public void testGetFrame() {
         Drawable frame = mAnimationDrawable.getFrame(FIRST_FRAME_INDEX);
         Drawable drawable = mResources.getDrawable(R.drawable.testimage);
@@ -227,87 +198,68 @@
         assertEquals(drawable.getIntrinsicHeight(), frame.getIntrinsicHeight());
 
         assertNull(mAnimationDrawable.getFrame(THIRD_FRAME_INDEX + 1));
-
-        try {
-            mAnimationDrawable.getFrame(-1);
-            fail("Should throw ArrayIndexOutOfBoundsException.");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            mAnimationDrawable.getFrame(10);
-            fail("Should throw ArrayIndexOutOfBoundsException.");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetFrameTooLow() {
+        mAnimationDrawable.getFrame(-1);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetFrameTooHigh() {
+        mAnimationDrawable.getFrame(10);
+    }
+
+    @Test
     public void testGetDuration() {
         assertEquals(FIRST_FRAME_DURATION, mAnimationDrawable.getDuration(FIRST_FRAME_INDEX));
         assertEquals(SECOND_FRAME_DURATION, mAnimationDrawable.getDuration(SECOND_FRAME_INDEX));
         assertEquals(THIRD_FRAME_DURATION, mAnimationDrawable.getDuration(THIRD_FRAME_INDEX));
         assertEquals(0, mAnimationDrawable.getDuration(THIRD_FRAME_INDEX + 1));
-
-        try {
-            mAnimationDrawable.getDuration(-1);
-            fail("Should throw ArrayIndexOutOfBoundsException.");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            mAnimationDrawable.getDuration(10);
-            fail("Should throw ArrayIndexOutOfBoundsException.");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetDurationTooLow() {
+        mAnimationDrawable.getDuration(-1);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetDurationTooHigh() {
+        mAnimationDrawable.getDuration(10);
+    }
+
+    @Test
     public void testAccessOneShot() throws Throwable {
         // animation should play repeat if do not stop it.
         assertFalse(mAnimationDrawable.isOneShot());
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.start();
-            }
-        });
+        mActivityRule.runOnUiThread(mAnimationDrawable::start);
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
         // begin to repeat
         pollingCheckDrawable(FIRST_FRAME_INDEX, THIRD_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAnimationDrawable.stop();
-                mAnimationDrawable.setOneShot(true);
-                assertTrue(mAnimationDrawable.isOneShot());
-                mAnimationDrawable.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mAnimationDrawable.stop();
+            mAnimationDrawable.setOneShot(true);
+            assertTrue(mAnimationDrawable.isOneShot());
+            mAnimationDrawable.start();
         });
         pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
         pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
         // do not repeat
-        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // Set visible to false and restart to false
-                mAnimationDrawable.setVisible(false, false);
-            }
-        });
+        verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        // Set visible to false and restart to false
+        mActivityRule.runOnUiThread(() -> mAnimationDrawable.setVisible(false, false));
         // Check that animation drawable stays on the same frame
-        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // Set visible to true and restart to false
-                mAnimationDrawable.setVisible(true, false);
-            }
-        });
+        // Set visible to true and restart to false
+        mActivityRule.runOnUiThread(() -> mAnimationDrawable.setVisible(true, false));
         // Check that animation drawable stays on the same frame
-        assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
+        verifyStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
     }
 
+    @Test
     public void testInflateCorrect() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.anim_list_correct);
         AnimationDrawable dr = new AnimationDrawable();
@@ -326,6 +278,7 @@
         assertSame(dr.getFrame(0), dr.getCurrent());
     }
 
+    @Test
     public void testInflateMissingDrawable() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.anim_list_missing_item_drawable);
         AnimationDrawable dr = new AnimationDrawable();
@@ -337,39 +290,31 @@
         }
     }
 
+    @Test(expected=NullPointerException.class)
     public void testInflateNullResources() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
         AnimationDrawable dr = new AnimationDrawable();
-        try {
-            dr.inflate(null, parser, Xml.asAttributeSet(parser));
-            fail("Should throw NullPointerException if resource is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        // Should throw NullPointerException if resource is null
+        dr.inflate(null, parser, Xml.asAttributeSet(parser));
     }
 
+    @Test(expected=NullPointerException.class)
     public void testInflateNullXmlPullParser() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
         AnimationDrawable dr = new AnimationDrawable();
-        try {
-            dr.inflate(mResources, null, Xml.asAttributeSet(parser));
-            fail("Should throw NullPointerException if parser is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        // Should throw NullPointerException if parser is null
+        dr.inflate(mResources, null, Xml.asAttributeSet(parser));
     }
 
+    @Test(expected=NullPointerException.class)
     public void testInflateNullAttributeSet() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.drawable.animationdrawable);
         AnimationDrawable dr = new AnimationDrawable();
-        try {
-            dr.inflate(mResources, parser, null);
-            fail("Should throw NullPointerException if AttributeSet is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        // Should throw NullPointerException if AttributeSet is null
+        dr.inflate(mResources, parser, null);
     }
 
+    @Test
     public void testMutate() {
         AnimationDrawable d1 = (AnimationDrawable) mResources
                 .getDrawable(R.drawable.animationdrawable);
@@ -395,13 +340,9 @@
      * @param timeout - timeout.
      */
     private void pollingCheckDrawable(final int index, long timeout) {
-        new PollingCheck(timeout + TOLERANCE) {
-            Drawable expected = mAnimationDrawable.getFrame(index);
-            @Override
-            protected boolean check() {
-                return mAnimationDrawable.getCurrent().equals(expected);
-            }
-        }.run();
+        final Drawable expected = mAnimationDrawable.getFrame(index);
+        PollingCheck.waitFor(timeout + TOLERANCE,
+                () -> mAnimationDrawable.getCurrent().equals(expected));
     }
 
     /**
@@ -410,7 +351,7 @@
      * @param index - index of current frame.
      * @param duration - duration of current frame.
      */
-    private void assertStoppedAnimation(int index, long duration) throws InterruptedException {
+    private void verifyStoppedAnimation(int index, long duration) throws InterruptedException {
         Thread.sleep(duration + TOLERANCE);
         assertSame(mAnimationDrawable.getFrame(index), mAnimationDrawable.getCurrent());
     }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index f9592dc..4197bf0 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -16,11 +16,23 @@
 
 package android.graphics.drawable.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.content.res.Resources.Theme;
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.cts.R;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
@@ -39,7 +51,9 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.LayoutDirection;
 import android.util.Xml;
@@ -51,7 +65,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-public class BitmapDrawableTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitmapDrawableTest {
     // A small value is actually making sure that the values are matching
     // exactly with the golden image.
     // We can increase the threshold if the Skia is drawing with some variance
@@ -65,13 +81,13 @@
     // The target context.
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
         // TODO: should default paint flags be left as an untested implementation detail?
         final int defaultPaintFlags = Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG |
@@ -109,6 +125,7 @@
         new BitmapDrawable((InputStream) null);
     }
 
+    @Test
     public void testAccessGravity() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -125,6 +142,7 @@
         assertEquals(Integer.MAX_VALUE, bitmapDrawable.getGravity());
     }
 
+    @Test
     public void testAccessMipMap() {
         Bitmap source = BitmapFactory.decodeResource(mContext.getResources(), R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -136,6 +154,7 @@
         assertFalse(source.hasMipMap());
     }
 
+    @Test
     public void testSetAntiAlias() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -149,6 +168,7 @@
         assertFalse(bitmapDrawable.getPaint().isAntiAlias());
     }
 
+    @Test
     public void testSetFilterBitmap() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -162,6 +182,7 @@
         assertTrue(bitmapDrawable.getPaint().isFilterBitmap());
     }
 
+    @Test
     public void testIsFilterBitmap() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -178,6 +199,7 @@
         assertEquals(bitmapDrawable.isFilterBitmap(), bitmapDrawable.getPaint().isFilterBitmap());
     }
 
+    @Test
     public void testSetDither() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -192,6 +214,7 @@
 
     }
 
+    @Test
     public void testAccessTileMode() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -232,6 +255,7 @@
         assertNotSame(oldShader, bitmapDrawable.getPaint().getShader());
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -245,12 +269,7 @@
         assertEquals(2, bitmapDrawable.getChangingConfigurations());
     }
 
-    public void testOnBoundsChange() {
-        // Do not test this API. it is 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 testSetAlpha() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -271,6 +290,7 @@
         assertEquals(0, bitmapDrawable.getPaint().getAlpha());
     }
 
+    @Test
     public void testSetColorFilter() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -285,6 +305,7 @@
         assertNull(bitmapDrawable.getPaint().getColorFilter());
     }
 
+    @Test
     public void testSetTint() {
         final InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         final BitmapDrawable d = new BitmapDrawable(source);
@@ -297,6 +318,7 @@
         d.setTintMode(null);
     }
 
+    @Test
     public void testGetOpacity() {
         BitmapDrawable bitmapDrawable = new BitmapDrawable();
         assertEquals(Gravity.FILL, bitmapDrawable.getGravity());
@@ -317,6 +339,7 @@
         assertEquals(PixelFormat.TRANSLUCENT, bitmapDrawable.getOpacity());
     }
 
+    @Test
     public void testGetConstantState() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -331,6 +354,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetIntrinsicSize() {
         BitmapDrawable bitmapDrawable = new BitmapDrawable();
         assertEquals(0, bitmapDrawable.getIntrinsicWidth());
@@ -350,6 +374,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testSetTargetDensity() {
         int sourceWidth, targetWidth;
         int sourceHeight, targetHeight;
@@ -403,6 +428,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testInflate() throws IOException, XmlPullParserException {
         BitmapDrawable bitmapDrawable = new BitmapDrawable();
 
@@ -465,6 +491,7 @@
         }
     }
 
+    @Test
     public void testDraw() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
@@ -480,6 +507,7 @@
         }
     }
 
+    @Test
     public void testMutate() {
         Resources resources = mContext.getResources();
         BitmapDrawable d1 = (BitmapDrawable) resources.getDrawable(R.drawable.testimage);
@@ -512,19 +540,20 @@
             R.drawable.bitmap_shader_am_density,
     };
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
         final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
             for (int i = 0; i < DENSITY_IMAGES.length; i++) {
-                testPreloadDensityInner(res, DENSITY_IMAGES[i], DENSITY_VALUES);
+                verifyPreloadDensityInner(res, DENSITY_IMAGES[i], DENSITY_VALUES);
             }
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int sourceResId, int[] densities)
+    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities)
             throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
index 074cbd9..2a41fbe 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ClipDrawableTest.java
@@ -16,32 +16,57 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.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.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+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 android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ClipDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.StateSet;
+import android.util.Xml;
+import android.view.Gravity;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.Arrays;
 
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ClipDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.StateSet;
-import android.util.Xml;
-import android.view.Gravity;
-
-public class ClipDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClipDrawableTest {
     @SuppressWarnings("deprecation")
+    @Test
     public void testClipDrawable() {
         new ClipDrawable((Drawable) null, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
 
@@ -49,16 +74,17 @@
         new ClipDrawable(bmpDrawable, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
     }
 
+    @Test
     public void testDraw() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN));
         mockDrawable.setLevel(5000);
         ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         clipDrawable.setBounds(new Rect(0, 0, 100, 100));
         clipDrawable.setLevel(5000);
-        assertFalse(mockDrawable.getCalledDraw());
+        verify(mockDrawable, never()).draw(any());
         clipDrawable.draw(new Canvas());
-        assertTrue(mockDrawable.getCalledDraw());
+        verify(mockDrawable, times(1)).draw(any());
 
         try {
             clipDrawable.draw(null);
@@ -67,17 +93,18 @@
         }
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         final int SUPER_CONFIG = 1;
         final int CONTAINED_DRAWABLE_CONFIG = 2;
 
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
 
         assertEquals(0, clipDrawable.getChangingConfigurations());
 
-        mockDrawable.setChangingConfigurations(CONTAINED_DRAWABLE_CONFIG);
+        colorDrawable.setChangingConfigurations(CONTAINED_DRAWABLE_CONFIG);
         assertEquals(CONTAINED_DRAWABLE_CONFIG, clipDrawable.getChangingConfigurations());
 
         clipDrawable.setChangingConfigurations(SUPER_CONFIG);
@@ -85,13 +112,15 @@
                 clipDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetConstantState() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN));
+        doReturn(null).when(mockDrawable).getConstantState();
         ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertNull(clipDrawable.getConstantState());
 
-        mockDrawable.setConstantState(new MockConstantState());
+        doReturn(new MockConstantState()).when(mockDrawable).getConstantState();
         clipDrawable = new ClipDrawable(mockDrawable, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         clipDrawable.setChangingConfigurations(1);
         assertNotNull(clipDrawable.getConstantState());
@@ -99,9 +128,10 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetIntrinsicHeight() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertEquals(-1, clipDrawable.getIntrinsicHeight());
 
@@ -113,9 +143,10 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetIntrinsicWidth() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertEquals(-1, clipDrawable.getIntrinsicWidth());
 
@@ -127,13 +158,12 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetOpacity() {
-        MockDrawable dr;
-        ClipDrawable clipDrawable;
+        Drawable dr = spy(new ColorDrawable(Color.GREEN));
+        doReturn(PixelFormat.OPAQUE).when(dr).getOpacity();
 
-        dr = new MockDrawable();
-        dr.setOpacity(PixelFormat.OPAQUE);
-        clipDrawable = new ClipDrawable(dr, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
+        ClipDrawable clipDrawable = new ClipDrawable(dr, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         clipDrawable.setLevel(0);
         assertEquals("Fully-clipped opaque drawable is transparent",
                 PixelFormat.TRANSPARENT, clipDrawable.getOpacity());
@@ -144,17 +174,17 @@
         assertEquals("Unclipped opaque drawable is opaque",
                 PixelFormat.OPAQUE, clipDrawable.getOpacity());
 
-        dr = new MockDrawable();
-        dr.setOpacity(PixelFormat.TRANSLUCENT);
+        doReturn(PixelFormat.TRANSLUCENT).when(dr).getOpacity();
         clipDrawable = new ClipDrawable(dr, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         clipDrawable.setLevel(10000);
         assertEquals("Unclipped translucent drawable is translucent",
                 PixelFormat.TRANSLUCENT, clipDrawable.getOpacity());
     }
 
+    @Test
     public void testGetPadding() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         Rect padding = new Rect(10, 10, 100, 100);
         assertFalse(clipDrawable.getPadding(padding));
@@ -171,32 +201,36 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         BitmapDrawable bmpDrawable = new BitmapDrawable();
         ClipDrawable clipDrawable = new ClipDrawable(bmpDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
 
-        XmlPullParser parser = mContext.getResources().getXml(R.drawable.gradientdrawable);
+        Resources resources = InstrumentationRegistry.getTargetContext().getResources();
+        XmlPullParser parser = resources.getXml(R.drawable.gradientdrawable);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        clipDrawable.inflate(mContext.getResources(), parser, attrs);
+        clipDrawable.inflate(resources, parser, attrs);
     }
 
+    @Test
     public void testInvalidateDrawable() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         clipDrawable.setCallback(callback);
-        clipDrawable.invalidateDrawable(mockDrawable);
-        assertSame(clipDrawable, callback.getInvalidateDrawable());
+        clipDrawable.invalidateDrawable(colorDrawable);
+        verify(callback, times(1)).invalidateDrawable(clipDrawable);
 
         clipDrawable.invalidateDrawable(null);
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testIsStateful() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertFalse(clipDrawable.isStateful());
 
@@ -206,19 +240,20 @@
         assertFalse(clipDrawable.isStateful());
     }
 
+    @Test
     public void testOnBoundsChange() {
-        MockDrawable mockDrawable = new MockDrawable();
-        MockClipDrawable mockClipDrawable = new MockClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        MockClipDrawable mockClipDrawable = new MockClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        assertEquals(0, mockDrawable.getBounds().left);
-        assertEquals(0, mockDrawable.getBounds().top);
-        assertEquals(0, mockDrawable.getBounds().bottom);
-        assertEquals(0, mockDrawable.getBounds().right);
+        assertEquals(0, colorDrawable.getBounds().left);
+        assertEquals(0, colorDrawable.getBounds().top);
+        assertEquals(0, colorDrawable.getBounds().bottom);
+        assertEquals(0, colorDrawable.getBounds().right);
         mockClipDrawable.onBoundsChange(new Rect(10, 10, 100, 100));
-        assertEquals(10, mockDrawable.getBounds().left);
-        assertEquals(10, mockDrawable.getBounds().top);
-        assertEquals(100, mockDrawable.getBounds().bottom);
-        assertEquals(100, mockDrawable.getBounds().right);
+        assertEquals(10, colorDrawable.getBounds().left);
+        assertEquals(10, colorDrawable.getBounds().top);
+        assertEquals(100, colorDrawable.getBounds().bottom);
+        assertEquals(100, colorDrawable.getBounds().right);
 
         try {
             mockClipDrawable.onBoundsChange(null);
@@ -227,27 +262,30 @@
         }
     }
 
+    @Test
     public void testOnLevelChange() {
-        MockDrawable mockDrawable = new MockDrawable();
-        MockClipDrawable mockClipDrawable = new MockClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        MockClipDrawable mockClipDrawable = new MockClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         mockClipDrawable.setCallback(callback);
 
-        assertEquals("Default level is 0", 0, mockDrawable.getLevel());
+        assertEquals("Default level is 0", 0, colorDrawable.getLevel());
         mockClipDrawable.onLevelChange(1000);
-        assertEquals(1000, mockDrawable.getLevel());
-        assertSame(mockClipDrawable, callback.getInvalidateDrawable());
+        assertEquals(1000, colorDrawable.getLevel());
+        verify(callback, times(1)).invalidateDrawable(mockClipDrawable);
 
         mockClipDrawable.onLevelChange(0);
-        assertEquals(0, mockDrawable.getLevel());
+        assertEquals(0, colorDrawable.getLevel());
 
         mockClipDrawable.onLevelChange(10000);
-        assertEquals(10000, mockDrawable.getLevel());
+        assertEquals(10000, colorDrawable.getLevel());
     }
 
+    @Test
     public void testOnStateChange() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
+        Context context = InstrumentationRegistry.getTargetContext();
+        Drawable d = context.getDrawable(R.drawable.pass);
         MockClipDrawable clipDrawable = new MockClipDrawable(d,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
@@ -256,7 +294,7 @@
         assertFalse("child did not change", clipDrawable.onStateChange(state));
         assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD);
 
-        d = mContext.getDrawable(R.drawable.statelistdrawable);
+        d = context.getDrawable(R.drawable.statelistdrawable);
         clipDrawable = new MockClipDrawable(d, Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
         clipDrawable.onStateChange(state);
@@ -267,49 +305,52 @@
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testScheduleDrawable() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         clipDrawable.setCallback(callback);
-        clipDrawable.scheduleDrawable(mockDrawable, null, 1000L);
-        assertEquals(clipDrawable, callback.getScheduleDrawable());
-        assertNull(callback.getRunnable());
-        assertEquals(1000L, callback.getWhen());
+        clipDrawable.scheduleDrawable(colorDrawable, null, 1000L);
+        verify(callback, times(1)).scheduleDrawable(clipDrawable, null, 1000L);
     }
 
+    @Test
     public void testSetAlpha() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
 
         clipDrawable.setAlpha(0);
-        assertEquals(0, mockDrawable.getAlpha());
+        assertEquals(0, colorDrawable.getAlpha());
 
         clipDrawable.setAlpha(128);
-        assertEquals(128, mockDrawable.getAlpha());
+        assertEquals(128, colorDrawable.getAlpha());
 
         clipDrawable.setAlpha(255);
-        assertEquals(255, mockDrawable.getAlpha());
+        assertEquals(255, colorDrawable.getAlpha());
     }
 
+    @Test
     public void testSetColorFilter() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN));
         ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
 
         ColorFilter cf = new ColorFilter();
         clipDrawable.setColorFilter(cf);
-        assertSame(cf, mockDrawable.getColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(cf);
 
+        reset(mockDrawable);
         clipDrawable.setColorFilter(null);
-        assertNull(mockDrawable.getColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(null);
     }
 
+    @Test
     public void testSetVisible() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
         assertTrue(clipDrawable.isVisible());
 
@@ -323,15 +364,15 @@
         assertTrue(clipDrawable.isVisible());
     }
 
+    @Test
     public void testUnscheduleDrawable() {
-        MockDrawable mockDrawable = new MockDrawable();
-        ClipDrawable clipDrawable = new ClipDrawable(mockDrawable,
+        Drawable colorDrawable = new ColorDrawable(Color.GREEN);
+        ClipDrawable clipDrawable = new ClipDrawable(colorDrawable,
                 Gravity.BOTTOM, ClipDrawable.HORIZONTAL);
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         clipDrawable.setCallback(callback);
-        clipDrawable.unscheduleDrawable(mockDrawable, null);
-        assertEquals(clipDrawable, callback.getScheduleDrawable());
-        assertNull(callback.getRunnable());
+        clipDrawable.unscheduleDrawable(colorDrawable, null);
+        verify(callback, times(1)).unscheduleDrawable(clipDrawable, null);
     }
 
     private class MockClipDrawable extends ClipDrawable {
@@ -355,66 +396,6 @@
         }
     }
 
-    private class MockDrawable extends Drawable {
-        private ColorFilter mColorFilter;
-        private ConstantState mConstantState;
-        private int mOpacity;
-        private boolean mCalledDraw = false;
-        private int mAlpha;
-
-        public boolean getCalledDraw() {
-            return mCalledDraw;
-        }
-
-        public void draw(Canvas canvas) {
-            mCalledDraw = true;
-        }
-
-        public void setAlpha(int alpha) {
-            mAlpha = alpha;
-        }
-
-        public int getAlpha() {
-            return mAlpha;
-        }
-
-        public void setColorFilter(ColorFilter cf) {
-            mColorFilter = cf;
-        }
-
-        public ColorFilter getColorFilter() {
-            return mColorFilter;
-        }
-
-        public int getOpacity() {
-            return mOpacity;
-        }
-
-        public void setOpacity(int opacity) {
-            mOpacity = opacity;
-        }
-
-        protected void onBoundsChange(Rect bounds) {
-            super.onBoundsChange(bounds);
-        }
-
-        protected boolean onLevelChange(int level) {
-            return super.onLevelChange(level);
-        }
-
-        protected boolean onStateChange(int[] state) {
-            return super.onStateChange(state);
-        }
-
-        public ConstantState getConstantState() {
-            return mConstantState;
-        }
-
-        public void setConstantState(ConstantState cs) {
-            mConstantState = cs;
-        }
-    }
-
     private class MockConstantState extends ConstantState {
         public Drawable newDrawable() {
             return null;
@@ -424,46 +405,4 @@
             return 0;
         }
     }
-
-    private class MockCallback implements Drawable.Callback {
-        private Drawable mInvalidateDrawable;
-        private Drawable mScheduleDrawable;
-        private Runnable mRunnable;
-        private long mWhen;
-
-        public Drawable getInvalidateDrawable() {
-            return mInvalidateDrawable;
-        }
-
-        public Drawable getScheduleDrawable() {
-            return mScheduleDrawable;
-        }
-
-        public Runnable getRunnable() {
-            return mRunnable;
-        }
-
-        public long getWhen() {
-            return mWhen;
-        }
-
-        public void invalidateDrawable(Drawable who) {
-            mInvalidateDrawable = who;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mScheduleDrawable = who;
-            mRunnable = what;
-            mWhen = when;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mScheduleDrawable = who;
-            mRunnable = what;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
index 4be0046..ee34254 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ColorDrawableTest.java
@@ -16,6 +16,11 @@
 
 package android.graphics.drawable.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -24,25 +29,32 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.cts.R;
 import android.graphics.drawable.ColorDrawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 
-import android.graphics.cts.R;
-
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
-public class ColorDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorDrawableTest {
+    @Test
     public void testConstructors() {
         new ColorDrawable();
         new ColorDrawable(0);
         new ColorDrawable(1);
     }
 
+    @Test
     public void testAccessAlpha() {
         ColorDrawable colorDrawable = new ColorDrawable();
         assertEquals(0, colorDrawable.getAlpha());
@@ -60,6 +72,7 @@
         assertEquals(1, colorDrawable.getAlpha());
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         final ColorDrawable colorDrawable = new ColorDrawable();
         assertEquals(0, colorDrawable.getChangingConfigurations());
@@ -74,6 +87,7 @@
         assertEquals(Integer.MAX_VALUE, colorDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetConstantState() {
         final ColorDrawable colorDrawable = new ColorDrawable();
         assertNotNull(colorDrawable.getConstantState());
@@ -81,6 +95,7 @@
                 colorDrawable.getConstantState().getChangingConfigurations());
     }
 
+    @Test
     public void testGetOpacity() {
         ColorDrawable colorDrawable = new ColorDrawable();
         assertEquals(PixelFormat.TRANSPARENT, colorDrawable.getOpacity());
@@ -92,11 +107,13 @@
         assertEquals(PixelFormat.TRANSLUCENT, colorDrawable.getOpacity());
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         int eventType = -1;
         final ColorDrawable colorDrawable = new ColorDrawable();
 
-        final XmlPullParser parser = mContext.getResources().getXml(R.drawable.colordrawable_test);
+        Resources resources = InstrumentationRegistry.getTargetContext().getResources();
+        final XmlPullParser parser = resources.getXml(R.drawable.colordrawable_test);
         // start to parse XML document
         while (eventType != XmlResourceParser.START_TAG
                 && eventType != XmlResourceParser.END_DOCUMENT) {
@@ -110,7 +127,7 @@
         }
         if (eventType == XmlResourceParser.START_TAG) {
             final AttributeSet attrs = Xml.asAttributeSet(parser);
-            colorDrawable.inflate(mContext.getResources(), parser, attrs);
+            colorDrawable.inflate(resources, parser, attrs);
             // set the alpha to 2 in colordrawable_test.xml
             assertEquals(2, colorDrawable.getAlpha());
         } else {
@@ -118,6 +135,7 @@
         }
     }
 
+    @Test
     public void testSetColorFilter() {
         final ColorDrawable d = new ColorDrawable(Color.WHITE);
         assertEquals(Color.WHITE, DrawableTestUtils.getPixel(d, 0, 0));
@@ -129,6 +147,7 @@
         assertEquals(Color.BLACK, DrawableTestUtils.getPixel(d, 0, 0));
     }
 
+    @Test
     public void testSetTint() {
         final ColorDrawable d = new ColorDrawable(Color.WHITE);
         assertEquals(Color.WHITE, DrawableTestUtils.getPixel(d, 0, 0));
@@ -138,6 +157,7 @@
         assertEquals(Color.BLACK, DrawableTestUtils.getPixel(d, 0, 0));
     }
 
+    @Test
     public void testDraw() {
         final ColorDrawable d = new ColorDrawable(Color.WHITE);
         final Bitmap b = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
index 3445641..136ae2d 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
@@ -17,37 +17,66 @@
 package android.graphics.drawable.cts;
 
 import android.animation.ValueAnimator;
+import android.content.Context;
 import android.graphics.cts.R;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 
 /**
  * This test is used to verify that the CustomAnimationScaleListDrawable's current drawable depends
  * on animation duration scale. When the scale is 0, it is a static drawable, otherwise, it is an
  * animatable drawable.
  */
-public class CustomAnimationScaleListDrawableTest extends AndroidTestCase {
-    @MediumTest
-    public void testNonZeroDurationScale() {
-        float originalScale = ValueAnimator.getDurationScale();
-        ValueAnimator.setDurationScale(2.0f);
-        Drawable dr = getContext().getDrawable(R.drawable.custom_animation_scale_list_drawable);
-        assertTrue(dr instanceof DrawableContainer);
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CustomAnimationScaleListDrawableTest {
+    private static final int DRAWABLE_ID = R.drawable.custom_animation_scale_list_drawable;
+    private Context mContext;
+    private float mOriginalScale;
 
-        assertTrue(dr.getCurrent() instanceof Animatable);
-        ValueAnimator.setDurationScale(originalScale);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mOriginalScale = ValueAnimator.getDurationScale();
+    }
+
+    @After
+    public void teardown() {
+        // Restore the original duration scale.
+        ValueAnimator.setDurationScale(mOriginalScale);
     }
 
     @MediumTest
+    @Test
+    public void testNonZeroDurationScale() {
+        // Set the duration scale to a non-zero value will cause the AnimationScaleListDrawable's
+        // current drawable choose the animatable one.
+        ValueAnimator.setDurationScale(2.0f);
+        Drawable dr = mContext.getDrawable(DRAWABLE_ID);
+        assertTrue(dr instanceof DrawableContainer);
+        assertTrue(dr.getCurrent() instanceof Animatable);
+    }
+
+    @MediumTest
+    @Test
     public void testZeroDurationScale() {
-        float originalScale = ValueAnimator.getDurationScale();
+        // Set the duration scale to zero will cause the AnimationScaleListDrawable's current
+        // drawable choose the static one.
         ValueAnimator.setDurationScale(0f);
-        Drawable dr = getContext().getDrawable(R.drawable.custom_animation_scale_list_drawable);
+        Drawable dr = mContext.getDrawable(DRAWABLE_ID);
         assertTrue(dr instanceof DrawableContainer);
         assertFalse(dr.getCurrent() instanceof Animatable);
-        ValueAnimator.setDurationScale(originalScale);
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java
index 7dff729..9070690 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomDrawableTest.java
@@ -16,10 +16,8 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -28,16 +26,27 @@
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-public class CustomDrawableTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CustomDrawableTest {
+    @Test
     public void testInflation() {
-        Drawable dr = getContext().getDrawable(R.drawable.custom_drawable);
+        Drawable dr = InstrumentationRegistry.getTargetContext().getDrawable(
+                R.drawable.custom_drawable);
         assertTrue(dr instanceof CustomDrawable);
         assertEquals(Color.RED, ((CustomDrawable) dr).getColor());
     }
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..aef8c3a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerStateTest.java
@@ -16,26 +16,39 @@
 
 package android.graphics.drawable.cts;
 
+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.doReturn;
+import static org.mockito.Mockito.spy;
 
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
+import android.graphics.Color;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 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 android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class DrawableContainerStateTest extends TestCase{
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawableContainerStateTest {
     private DrawableContainerState mDrawableContainerState;
 
     private DrawableContainer mDrawableContainer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         // DrawableContainerState has no public constructor. Obtain an instance through
         // LevelListDrawable.getConstants(). This is fine for testing the final methods of
         // DrawableContainerState.
@@ -44,16 +57,16 @@
         assertNotNull(mDrawableContainerState);
     }
 
-    public void testAddChild() {
-        try {
-            mDrawableContainerState.addChild(null);
-            fail("Should throw NullPointerException if the drawable is null.");
-        } catch (NullPointerException e) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testAddChildNull() {
+        mDrawableContainerState.addChild(null);
+    }
 
+    @Test
+    public void testAddChild() {
         assertEquals(0, mDrawableContainerState.getChildCount());
 
-        MockDrawable dr0 = new MockDrawable();
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
         dr0.setVisible(true, false);
         assertTrue(dr0.isVisible());
         assertEquals(0, mDrawableContainerState.addChild(dr0));
@@ -65,7 +78,7 @@
         assertNull(children[1]);
         assertFalse(dr0.isVisible());
 
-        MockDrawable dr1 = new MockDrawable();
+        Drawable dr1 = spy(new ColorDrawable(Color.BLUE));
         dr1.setVisible(true, false);
         assertTrue(dr1.isVisible());
         assertEquals(1, mDrawableContainerState.addChild(dr1));
@@ -88,35 +101,37 @@
         assertSame(dr1, children[2]);
     }
 
-    public void testIsStateFul() {
+    @Test
+    public void testIsStateful() {
         assertEquals(0, mDrawableContainerState.getChildCount());
         assertFalse(mDrawableContainerState.isStateful());
 
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setStateful(false);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(false).when(dr0).isStateful();
         mDrawableContainerState.addChild(dr0);
         assertEquals(1, mDrawableContainerState.getChildCount());
         assertFalse(mDrawableContainerState.isStateful());
 
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setStateful(false);
+        Drawable dr1 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(false).when(dr1).isStateful();
         mDrawableContainerState.addChild(dr1);
         assertEquals(2, mDrawableContainerState.getChildCount());
         assertFalse(mDrawableContainerState.isStateful());
 
-        MockDrawable dr2 = new MockDrawable();
-        dr2.setStateful(true);
+        Drawable dr2 = spy(new ColorDrawable(Color.BLUE));
+        doReturn(true).when(dr2).isStateful();
         mDrawableContainerState.addChild(dr2);
         assertEquals(3, mDrawableContainerState.getChildCount());
         assertTrue(mDrawableContainerState.isStateful());
 
-        MockDrawable dr3 = new MockDrawable();
-        dr3.setStateful(false);
+        Drawable dr3 = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(false).when(dr3).isStateful();
         mDrawableContainerState.addChild(dr3);
         assertEquals(4, mDrawableContainerState.getChildCount());
         assertTrue(mDrawableContainerState.isStateful());
     }
 
+    @Test
     public void testAccessEnterFadeDuration() {
         mDrawableContainerState.setEnterFadeDuration(1000);
         assertEquals(1000, mDrawableContainerState.getEnterFadeDuration());
@@ -125,6 +140,7 @@
         assertEquals(-1000, mDrawableContainerState.getEnterFadeDuration());
     }
 
+    @Test
     public void testAccessExitFadeDuration() {
         mDrawableContainerState.setExitFadeDuration(1000);
         assertEquals(1000, mDrawableContainerState.getExitFadeDuration());
@@ -133,6 +149,7 @@
         assertEquals(-1000, mDrawableContainerState.getExitFadeDuration());
     }
 
+    @Test
     public void testAccessConstantSize() {
         mDrawableContainerState.setConstantSize(true);
         assertTrue(mDrawableContainerState.isConstantSize());
@@ -141,6 +158,7 @@
         assertFalse(mDrawableContainerState.isConstantSize());
     }
 
+    @Test
     public void testAccessConstantPadding() {
         mDrawableContainerState.setVariablePadding(true);
         assertNull(mDrawableContainerState.getConstantPadding());
@@ -173,6 +191,7 @@
         */
     }
 
+    @Test
     public void testConstantHeightsAndWidths() {
         assertEquals(0, mDrawableContainerState.getChildCount());
         assertEquals(-1, mDrawableContainerState.getConstantHeight());
@@ -180,11 +199,11 @@
         assertEquals(0, mDrawableContainerState.getConstantMinimumHeight());
         assertEquals(0, mDrawableContainerState.getConstantMinimumWidth());
 
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setMinimumHeight(1);
-        dr0.setMinimumWidth(2);
-        dr0.setIntrinsicHeight(0);
-        dr0.setIntrinsicWidth(0);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(1).when(dr0).getMinimumHeight();
+        doReturn(2).when(dr0).getMinimumWidth();
+        doReturn(0).when(dr0).getIntrinsicHeight();
+        doReturn(0).when(dr0).getIntrinsicWidth();
         mDrawableContainerState.addChild(dr0);
         assertEquals(1, mDrawableContainerState.getChildCount());
         assertEquals(0, mDrawableContainerState.getConstantHeight());
@@ -192,11 +211,11 @@
         assertEquals(1, mDrawableContainerState.getConstantMinimumHeight());
         assertEquals(2, mDrawableContainerState.getConstantMinimumWidth());
 
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setMinimumHeight(0);
-        dr1.setMinimumWidth(0);
-        dr1.setIntrinsicHeight(3);
-        dr1.setIntrinsicWidth(4);
+        Drawable dr1 = spy(new ColorDrawable(Color.BLUE));
+        doReturn(0).when(dr1).getMinimumHeight();
+        doReturn(0).when(dr1).getMinimumWidth();
+        doReturn(3).when(dr1).getIntrinsicHeight();
+        doReturn(4).when(dr1).getIntrinsicWidth();
         mDrawableContainerState.addChild(dr1);
         assertEquals(2, mDrawableContainerState.getChildCount());
         assertEquals(3, mDrawableContainerState.getConstantHeight());
@@ -204,11 +223,11 @@
         assertEquals(1, mDrawableContainerState.getConstantMinimumHeight());
         assertEquals(2, mDrawableContainerState.getConstantMinimumWidth());
 
-        MockDrawable dr2 = new MockDrawable();
-        dr2.setMinimumHeight(5);
-        dr2.setMinimumWidth(5);
-        dr2.setIntrinsicHeight(5);
-        dr2.setIntrinsicWidth(5);
+        Drawable dr2 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(5).when(dr2).getMinimumHeight();
+        doReturn(5).when(dr2).getMinimumWidth();
+        doReturn(5).when(dr2).getIntrinsicHeight();
+        doReturn(5).when(dr2).getIntrinsicWidth();
         mDrawableContainerState.addChild(dr2);
         assertEquals(3, mDrawableContainerState.getChildCount());
         assertEquals(5, mDrawableContainerState.getConstantHeight());
@@ -217,50 +236,55 @@
         assertEquals(5, mDrawableContainerState.getConstantMinimumWidth());
     }
 
+    @Test
     public void testGetOpacity() {
         assertEquals(0, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.TRANSPARENT, mDrawableContainerState.getOpacity());
 
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setOpacity(PixelFormat.OPAQUE);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(PixelFormat.OPAQUE).when(dr0).getOpacity();
         mDrawableContainerState.addChild(dr0);
         assertEquals(1, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.OPAQUE, mDrawableContainerState.getOpacity());
 
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setOpacity(PixelFormat.TRANSPARENT);
+        Drawable dr1 = spy(new ColorDrawable(Color.BLUE));
+        doReturn(PixelFormat.TRANSPARENT).when(dr1).getOpacity();
         mDrawableContainerState.addChild(dr1);
         assertEquals(2, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.TRANSPARENT, mDrawableContainerState.getOpacity());
 
-        MockDrawable dr2 = new MockDrawable();
-        dr2.setOpacity(PixelFormat.TRANSLUCENT);
+        Drawable dr2 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(PixelFormat.TRANSLUCENT).when(dr2).getOpacity();
         mDrawableContainerState.addChild(dr2);
         assertEquals(3, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.TRANSLUCENT, mDrawableContainerState.getOpacity());
 
-        MockDrawable dr3 = new MockDrawable();
-        dr3.setOpacity(PixelFormat.UNKNOWN);
+        Drawable dr3 = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(PixelFormat.UNKNOWN).when(dr3).getOpacity();
         mDrawableContainerState.addChild(dr3);
         assertEquals(4, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.UNKNOWN, mDrawableContainerState.getOpacity());
 
-        MockDrawable dr4 = new MockDrawable();
-        dr4.setOpacity(PixelFormat.TRANSLUCENT);
+        Drawable dr4 = spy(new ColorDrawable(Color.MAGENTA));
+        doReturn(PixelFormat.TRANSLUCENT).when(dr4).getOpacity();
         mDrawableContainerState.addChild(dr4);
         assertEquals(5, mDrawableContainerState.getChildCount());
         assertEquals(PixelFormat.UNKNOWN, mDrawableContainerState.getOpacity());
     }
 
+    @Test
     public void testCanConstantState() {
         DrawableContainer dr = new LevelListDrawable();
         DrawableContainerState cs = (DrawableContainerState) dr.getConstantState();
         assertTrue(cs.canConstantState());
 
-        cs.addChild(new MockDrawable());
+        Drawable child = spy(new ColorDrawable(Color.RED));
+        doReturn(null).when(child).getConstantState();
+        cs.addChild(child);
         assertFalse(cs.canConstantState());
     }
 
+    @Test
     public void testGrowArray() {
         DrawableContainer dr = new LevelListDrawable();
         DrawableContainerState cs = (DrawableContainerState) dr.getConstantState();
@@ -277,111 +301,4 @@
         cs.growArray(0, 10);
         cs.getChild(9);
     }
-
-    private class MockDrawable extends Drawable {
-        private boolean mIsStatful;
-
-        private Rect mPadding;
-
-        private int mIntrinsicHeight;
-
-        private int mIntrinsicWidth;
-
-        private int mMinimumHeight;
-
-        private int mMinimumWidth;
-
-        private int mOpacity;
-
-        @Override
-        public void draw(Canvas canvas) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return mOpacity;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-
-        @Override
-        public boolean isStateful() {
-            return mIsStatful;
-        }
-
-        public void setStateful(boolean isStateful) {
-            mIsStatful = isStateful;
-        }
-
-        public void setPadding(Rect rect) {
-            if (mPadding == null) {
-                mPadding = new Rect();
-            }
-            mPadding.left = rect.left;
-            mPadding.right = rect.right;
-            mPadding.top = rect.top;
-            mPadding.bottom = rect.bottom;
-        }
-
-        @Override
-        public boolean getPadding(Rect padding) {
-            if (padding == null) {
-                return false;
-            }
-            if (mPadding == null) {
-                return false;
-            }
-            padding.left = mPadding.left;
-            padding.top = mPadding.top;
-            padding.right = mPadding.right;
-            padding.bottom = mPadding.bottom;
-            return true;
-        }
-
-        @Override
-        public int getMinimumHeight() {
-            return mMinimumHeight;
-        }
-
-        @Override
-        public int getMinimumWidth() {
-            return mMinimumWidth;
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mIntrinsicHeight;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return mIntrinsicWidth;
-        }
-
-        public void setMinimumHeight(int h) {
-            mMinimumHeight = h;
-        }
-
-        public void setMinimumWidth(int w) {
-            mMinimumWidth = w;
-        }
-
-        public void setIntrinsicHeight(int h) {
-            mIntrinsicHeight = h;
-        }
-
-        public void setIntrinsicWidth(int w) {
-            mIntrinsicWidth = w;
-        }
-
-        public void setOpacity(int opacity){
-            mOpacity = opacity;
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
index e78b04c..4b8ea67 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
@@ -16,9 +16,26 @@
 
 package android.graphics.drawable.cts;
 
-import junit.framework.TestCase;
-
-import java.util.Arrays;
+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.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+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 android.graphics.Canvas;
 import android.graphics.Color;
@@ -26,21 +43,31 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
 import android.graphics.drawable.LevelListDrawable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class DrawableContainerTest extends TestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawableContainerTest {
     private DrawableContainerState mDrawableContainerState;
 
     private MockDrawableContainer mMockDrawableContainer;
     private DrawableContainer mDrawableContainer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setup() {
         // DrawableContainerState has no public constructor. Obtain an instance through
         // LevelListDrawable.getConstants(). This is fine for testing the final methods of
         // DrawableContainerState.
@@ -49,65 +76,75 @@
         assertNotNull(mDrawableContainerState);
 
         mMockDrawableContainer = new MockDrawableContainer();
+        // While the two fields point to the same object, the second one is there to
+        // workaround the bug in CTS coverage tool that is not recognizing calls on
+        // subclasses.
         mDrawableContainer = mMockDrawableContainer;
+
+        assertNull(mDrawableContainer.getCurrent());
     }
 
-    public void testDraw() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
+    @Test(expected=NullPointerException.class)
+    public void testConstantStateNotSet() {
+        // This should throw NPE since our mock container has not been configured with
+        // constant state yet
+        mDrawableContainer.getConstantState();
+    }
 
+    @Test
+    public void testDraw() {
         mDrawableContainer.draw(null);
         mDrawableContainer.draw(new Canvas());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr = new MockDrawable();
+        Drawable dr = spy(new ColorDrawable(Color.WHITE));
         addAndSelectDrawable(dr);
 
-        dr.reset();
+        reset(dr);
+        doNothing().when(dr).draw(any());
         mDrawableContainer.draw(null);
-        assertTrue(dr.hasDrawCalled());
+        verify(dr, times(1)).draw(any());
 
-        dr.reset();
+        reset(dr);
+        doNothing().when(dr).draw(any());
         mDrawableContainer.draw(new Canvas());
-        assertTrue(dr.hasDrawCalled());
+        verify(dr, times(1)).draw(any());
     }
 
+    @Test
     public void testSetEnterFadeDuration() {
-        helpTestSetEnterFadeDuration(1000);
-        helpTestSetEnterFadeDuration(0);
+        verifySetEnterFadeDuration(1000);
+        verifySetEnterFadeDuration(0);
     }
 
-    private void helpTestSetEnterFadeDuration(int enterFadeDuration) {
+    private void verifySetEnterFadeDuration(int enterFadeDuration) {
         DrawableContainer container = new LevelListDrawable();
         DrawableContainerState cs = ((DrawableContainerState) container.getConstantState());
         container.setEnterFadeDuration(enterFadeDuration);
         assertEquals(enterFadeDuration, cs.getEnterFadeDuration());
     }
 
+    @Test
     public void testSetExitFadeDuration() {
-        helpTestSetExitFadeDuration(1000);
-        helpTestSetExitFadeDuration(0);
+        verifySetExitFadeDuration(1000);
+        verifySetExitFadeDuration(0);
     }
 
-    private void helpTestSetExitFadeDuration(int exitFadeDuration) {
+    private void verifySetExitFadeDuration(int exitFadeDuration) {
         DrawableContainer container = new LevelListDrawable();
         DrawableContainerState cs = ((DrawableContainerState) container.getConstantState());
         container.setExitFadeDuration(exitFadeDuration);
         assertEquals(exitFadeDuration, cs.getExitFadeDuration());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetChangingConfigurationsNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getChangingConfigurations();
+    }
+
+    @Test
     public void testGetChangingConfigurations() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.getChangingConfigurations();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         MockDrawable dr0 = new MockDrawable();
         dr0.setChangingConfigurations(0x001);
@@ -115,7 +152,7 @@
         MockDrawable dr1 = new MockDrawable();
         dr1.setChangingConfigurations(0x010);
         mDrawableContainerState.addChild(dr1);
-        dr.selectDrawable(0);
+        mDrawableContainer.selectDrawable(0);
         assertSame(dr0, mDrawableContainer.getCurrent());
 
         // can not set mDrawableContainerState's ChangingConfigurations
@@ -124,28 +161,33 @@
                 mDrawableContainer.getChangingConfigurations());
     }
 
-    public void testGetPadding() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
+    @Test(expected=NullPointerException.class)
+    public void testGetPaddingNoConstantState() {
         Rect result = new Rect(1, 1, 1, 1);
-        try {
-            mDrawableContainer.getPadding(result);
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getPadding(result);
+    }
+
+    @Test
+    public void testGetPadding() {
+        Rect result = new Rect(1, 1, 1, 1);
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setPadding(new Rect(1, 2, 0, 0));
+        Drawable dr0 = spy(new ColorDrawable(Color.BLUE));
+        doAnswer((InvocationOnMock invocation) -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(1, 2, 0, 0);
+            return true;
+        }).when(dr0).getPadding(any());
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setPadding(new Rect(0, 0, 3, 4));
+        Drawable dr1 = spy(new ColorDrawable(Color.RED));
+        doAnswer((InvocationOnMock invocation) -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(0, 0, 3, 4);
+            return true;
+        }).when(dr1).getPadding(any());
         mDrawableContainerState.addChild(dr1);
-        dr.selectDrawable(0);
+        mDrawableContainer.selectDrawable(0);
         assertSame(dr0, mDrawableContainer.getCurrent());
 
         // use the current drawable's padding
@@ -161,7 +203,7 @@
         assertEquals(mDrawableContainerState.getConstantPadding(), result);
 
         // use default padding
-        dr.selectDrawable(-1);
+        mDrawableContainer.selectDrawable(-1);
         assertNull(mDrawableContainer.getCurrent());
         mDrawableContainerState.setVariablePadding(true);
         assertNull(mDrawableContainerState.getConstantPadding());
@@ -175,55 +217,48 @@
         }
     }
 
+    @Test
     public void testSetAlpha() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
-        dr.setAlpha(0);
+        mDrawableContainer.setAlpha(0);
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.BLACK));
         addAndSelectDrawable(mockDrawable);
 
         // call current drawable's setAlpha if alpha is changed.
-        mockDrawable.reset();
-        dr.setAlpha(1);
-        assertTrue(mockDrawable.hasSetAlphaCalled());
+        reset(mockDrawable);
+        mDrawableContainer.setAlpha(1);
+        verify(mockDrawable, times(1)).setAlpha(1);
 
         // does not call it if alpha is not changed.
-        mockDrawable.reset();
-        dr.setAlpha(1);
-        assertFalse(mockDrawable.hasSetAlphaCalled());
+        reset(mockDrawable);
+        mDrawableContainer.setAlpha(1);
+        verify(mockDrawable, never()).setAlpha(anyInt());
     }
 
+    @Test
     public void testSetDither() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         mDrawableContainer.setDither(false);
         mDrawableContainer.setDither(true);
 
-        MockDrawable dr = new MockDrawable();
+        Drawable dr = spy(new ColorDrawable(Color.BLUE));
         addAndSelectDrawable(dr);
 
         // call current drawable's setDither if dither is changed.
-        dr.reset();
+        reset(dr);
         mDrawableContainer.setDither(false);
-        assertTrue(dr.hasSetDitherCalled());
+        verify(dr, times(1)).setDither(false);
 
         // does not call it if dither is not changed.
-        dr.reset();
+        reset(dr);
         mDrawableContainer.setDither(true);
-        assertTrue(dr.hasSetDitherCalled());
+        verify(dr, times(1)).setDither(true);
     }
 
+    @Test
     public void testSetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
-        assertConstantStateNotSet();
         assertNull(mDrawableContainer.getCurrent());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
@@ -240,9 +275,9 @@
         dr.reset();
     }
 
+    @Test
     public void testGetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
-        assertConstantStateNotSet();
         assertNull(mDrawableContainer.getCurrent());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
@@ -259,54 +294,44 @@
         dr.reset();
     }
 
+    @Test
     public void testSetColorFilter() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        dr.setColorFilter(null);
-        dr.setColorFilter(new ColorFilter());
+        mDrawableContainer.setColorFilter(null);
+        mDrawableContainer.setColorFilter(new ColorFilter());
 
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.MAGENTA));
         addAndSelectDrawable(mockDrawable);
 
         // call current drawable's setColorFilter if filter is changed.
-        mockDrawable.reset();
-        dr.setColorFilter(null);
-        assertTrue(mockDrawable.hasSetColorFilterCalled());
+        reset(mockDrawable);
+        mDrawableContainer.setColorFilter(null);
+        verify(mockDrawable, times(1)).setColorFilter(null);
 
         // does not call it if filter is not changed.
-        mockDrawable.reset();
-        dr.setColorFilter(new ColorFilter());
-        assertTrue(mockDrawable.hasSetColorFilterCalled());
+        reset(mockDrawable);
+        mDrawableContainer.setColorFilter(new ColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(any());
     }
 
+    @Test
     public void testSetTint() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         mDrawableContainer.setTint(Color.BLACK);
         mDrawableContainer.setTintMode(Mode.SRC_OVER);
 
-        MockDrawable dr = new MockDrawable();
+        Drawable dr = spy(new ColorDrawable(Color.GREEN));
         addAndSelectDrawable(dr);
 
-        assertEquals("Initial tint propagates", Mode.SRC_OVER, dr.getTintMode());
+        verify(dr, times(1)).setTintMode(Mode.SRC_OVER);
 
-        dr.reset();
         mDrawableContainer.setTintList(null);
         mDrawableContainer.setTintMode(null);
-        assertTrue("setImageTintList() propagates", dr.hasSetTintCalled());
+        verify(dr, times(1)).setTintMode(null);
     }
 
+    @Test
     public void testOnBoundsChange() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mMockDrawableContainer.onBoundsChange(new Rect());
         mMockDrawableContainer.onBoundsChange(null);
 
@@ -334,21 +359,20 @@
         }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testIsStatefulNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.isStateful();
+    }
+
+    @Test
     public void testIsStateful() {
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.isStateful();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setStateful(true);
+        Drawable dr0 = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(true).when(dr0).isStateful();
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setStateful(false);
+        Drawable dr1 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(false).when(dr1).isStateful();
         mDrawableContainerState.addChild(dr1);
 
         // return result of constant state's isStateful
@@ -360,10 +384,8 @@
         assertEquals(true, mDrawableContainer.isStateful());
     }
 
+    @Test
     public void testOnStateChange() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         assertFalse(mMockDrawableContainer.onStateChange(new int[] { 0 }));
         assertFalse(mMockDrawableContainer.onStateChange(null));
 
@@ -390,10 +412,8 @@
         assertTrue(Arrays.equals(new int[] { 0 }, dr.getState()));
     }
 
+    @Test
     public void testOnLevelChange() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         assertFalse(mMockDrawableContainer.onLevelChange(Integer.MAX_VALUE));
         assertFalse(mMockDrawableContainer.onLevelChange(Integer.MIN_VALUE));
 
@@ -422,21 +442,20 @@
         assertFalse(dr.hasOnLevelChangedCalled());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetIntrinsicWidthNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getIntrinsicWidth();
+    }
+
+    @Test
     public void testGetIntrinsicWidth() {
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.getIntrinsicWidth();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setIntrinsicWidth(1);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(1).when(dr0).getIntrinsicWidth();
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setIntrinsicWidth(2);
+        Drawable dr1 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(2).when(dr1).getIntrinsicWidth();
         mDrawableContainerState.addChild(dr1);
 
         // return result of constant state's getConstantWidth
@@ -456,21 +475,20 @@
         assertEquals(1, mDrawableContainer.getIntrinsicWidth());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetIntrinsicHeightNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getIntrinsicHeight();
+    }
+
+    @Test
     public void testGetIntrinsicHeight() {
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.getIntrinsicHeight();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setIntrinsicHeight(1);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(1).when(dr0).getIntrinsicHeight();
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setIntrinsicHeight(2);
+        Drawable dr1 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(2).when(dr1).getIntrinsicHeight();
         mDrawableContainerState.addChild(dr1);
 
         // return result of constant state's getConstantHeight
@@ -490,21 +508,20 @@
         assertEquals(1, mDrawableContainer.getIntrinsicHeight());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetMinimumWidthNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getMinimumWidth();
+    }
+
+    @Test
     public void testGetMinimumWidth() {
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.getMinimumWidth();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setMinimumWidth(1);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(1).when(dr0).getMinimumWidth();
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setMinimumWidth(2);
+        Drawable dr1 = spy(new ColorDrawable(Color.RED));
+        doReturn(2).when(dr1).getMinimumWidth();
         mDrawableContainerState.addChild(dr1);
 
         // return result of constant state's getConstantMinimumWidth
@@ -524,21 +541,20 @@
         assertEquals(1, mDrawableContainer.getMinimumWidth());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetMinimumHeightNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.getMinimumHeight();
+    }
+
+    @Test
     public void testGetMinimumHeight() {
-        assertConstantStateNotSet();
-
-        try {
-            mDrawableContainer.getMinimumHeight();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setMinimumHeight(1);
+        Drawable dr0 = spy(new ColorDrawable(Color.RED));
+        doReturn(1).when(dr0).getMinimumHeight();
         mDrawableContainerState.addChild(dr0);
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setMinimumHeight(2);
+        Drawable dr1 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(2).when(dr1).getMinimumHeight();
         mDrawableContainerState.addChild(dr1);
 
         // return result of constant state's getConstantMinimumHeight
@@ -558,154 +574,108 @@
         assertEquals(1, mDrawableContainer.getMinimumHeight());
     }
 
+    @Test
     public void testInvalidateDrawable() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mDrawableContainer.setCallback(null);
-        dr.invalidateDrawable(mDrawableContainer);
-        dr.invalidateDrawable(null);
+        mDrawableContainer.invalidateDrawable(mDrawableContainer);
+        mDrawableContainer.invalidateDrawable(null);
 
-        MockCallBack callback = new MockCallBack();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         mDrawableContainer.setCallback(callback);
 
-        callback.reset();
-        dr.invalidateDrawable(mDrawableContainer);
-        assertFalse(callback.hasInvalidateDrawableCalled());
+        mDrawableContainer.invalidateDrawable(mDrawableContainer);
+        verify(callback, never()).invalidateDrawable(any());
 
         // the callback method can be called if the drawable passed in and the
-        // current drawble are both null
-        callback.reset();
-        dr.invalidateDrawable(null);
-        assertTrue(callback.hasInvalidateDrawableCalled());
+        // current drawable are both null
+        mDrawableContainer.invalidateDrawable(null);
+        verify(callback, times(1)).invalidateDrawable(any());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         MockDrawable mockDrawable = new MockDrawable();
         addAndSelectDrawable(mockDrawable);
 
-        callback.reset();
-        dr.invalidateDrawable(mDrawableContainer);
-        assertFalse(callback.hasInvalidateDrawableCalled());
+        reset(callback);
+        mDrawableContainer.invalidateDrawable(mDrawableContainer);
+        verify(callback, never()).invalidateDrawable(any());
 
-        callback.reset();
-        dr.invalidateDrawable(null);
-        assertFalse(callback.hasInvalidateDrawableCalled());
+        mDrawableContainer.invalidateDrawable(null);
+        verify(callback, never()).invalidateDrawable(any());
 
         // Call the callback method if the drawable is selected.
-        callback.reset();
-        dr.invalidateDrawable(mockDrawable);
-        assertTrue(callback.hasInvalidateDrawableCalled());
+        mDrawableContainer.invalidateDrawable(mockDrawable);
+        verify(callback, times(1)).invalidateDrawable(any());
     }
 
+    @Test
     public void testScheduleDrawable() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mDrawableContainer.setCallback(null);
-        dr.scheduleDrawable(mDrawableContainer, null, 0);
-        dr.scheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            }, 0);
+        mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0);
+        mDrawableContainer.scheduleDrawable(null, () -> {}, 0);
 
-        MockCallBack callback = new MockCallBack();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         mDrawableContainer.setCallback(callback);
 
-        callback.reset();
-        dr.scheduleDrawable(mDrawableContainer, null, 0);
-        assertFalse(callback.hasScheduleDrawableCalled());
+        mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0);
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
 
         // the callback method can be called if the drawable passed in and the
         // current drawble are both null
-        callback.reset();
-        dr.scheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            }, 0);
-        assertTrue(callback.hasScheduleDrawableCalled());
+        mDrawableContainer.scheduleDrawable(null, () -> {}, 0);
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         MockDrawable mockDrawable = new MockDrawable();
         addAndSelectDrawable(mockDrawable);
 
-        callback.reset();
-        dr.scheduleDrawable(mDrawableContainer, null, 0);
-        assertFalse(callback.hasScheduleDrawableCalled());
+        reset(callback);
+        mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0);
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
 
-        callback.reset();
-        dr.scheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            }, 0);
-        assertFalse(callback.hasScheduleDrawableCalled());
+        mDrawableContainer.scheduleDrawable(null, () -> {}, 0);
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
 
         // Call the callback method if the drawable is selected.
-        callback.reset();
-        dr.scheduleDrawable(mockDrawable, null, 0);
-        assertTrue(callback.hasScheduleDrawableCalled());
+        mDrawableContainer.scheduleDrawable(mockDrawable, null, 0);
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
     }
 
+    @Test
     public void testUnscheduleDrawable() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         mDrawableContainer.setCallback(null);
-        dr.unscheduleDrawable(mDrawableContainer, null);
-        dr.unscheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            });
+        mDrawableContainer.unscheduleDrawable(mDrawableContainer, null);
+        mDrawableContainer.unscheduleDrawable(null, () -> {});
 
-        MockCallBack callback = new MockCallBack();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
         mDrawableContainer.setCallback(callback);
 
-        callback.reset();
-        dr.unscheduleDrawable(mDrawableContainer, null);
-        assertFalse(callback.hasUnscheduleDrawableCalled());
+        mDrawableContainer.unscheduleDrawable(mDrawableContainer, null);
+        verify(callback, never()).unscheduleDrawable(any(), any());
 
         // the callback method can be called if the drawable passed in and the
         // current drawble are both null
-        callback.reset();
-        dr.unscheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            });
-        assertTrue(callback.hasUnscheduleDrawableCalled());
+        mDrawableContainer.unscheduleDrawable(null, () -> {});
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         MockDrawable mockDrawable = new MockDrawable();
         addAndSelectDrawable(mockDrawable);
 
-        callback.reset();
-        dr.unscheduleDrawable(mDrawableContainer, null);
-        assertFalse(callback.hasUnscheduleDrawableCalled());
+        reset(callback);
+        mDrawableContainer.unscheduleDrawable(mDrawableContainer, null);
+        verify(callback, never()).unscheduleDrawable(any(), any());
 
-        callback.reset();
-        dr.unscheduleDrawable(null, new Runnable() {
-                public void run() {
-                }
-            });
-        assertFalse(callback.hasUnscheduleDrawableCalled());
+        mDrawableContainer.unscheduleDrawable(null, () -> {});
+        verify(callback, never()).unscheduleDrawable(any(), any());
 
         // Call the callback method if the drawable is selected.
-        callback.reset();
-        dr.unscheduleDrawable(mockDrawable, null);
-        assertTrue(callback.hasUnscheduleDrawableCalled());
+        mDrawableContainer.unscheduleDrawable(mockDrawable, null);
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
     }
 
+    @Test
     public void testSetVisible() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
         assertTrue(mDrawableContainer.isVisible());
         assertFalse(mDrawableContainer.setVisible(true, false));
         assertTrue(mDrawableContainer.setVisible(false, false));
@@ -724,48 +694,39 @@
         assertFalse(dr.isVisible());
     }
 
+    @Test
     public void testGetOpacity() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        assertConstantStateNotSet();
-
         // there is no child, so the container is transparent
-        assertEquals(PixelFormat.TRANSPARENT, dr.getOpacity());
+        assertEquals(PixelFormat.TRANSPARENT, mDrawableContainer.getOpacity());
 
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        dr0.setOpacity(PixelFormat.OPAQUE);
+        Drawable dr0 = spy(new ColorDrawable(Color.GREEN));
+        doReturn(PixelFormat.OPAQUE).when(dr0).getOpacity();
         mDrawableContainerState.addChild(dr0);
         // no child selected yet
-        assertEquals(PixelFormat.TRANSPARENT, dr.getOpacity());
+        assertEquals(PixelFormat.TRANSPARENT, mDrawableContainer.getOpacity());
 
-        dr.selectDrawable(0);
-        assertEquals(mDrawableContainerState.getOpacity(), dr.getOpacity());
+        mDrawableContainer.selectDrawable(0);
+        assertEquals(mDrawableContainerState.getOpacity(), mDrawableContainer.getOpacity());
         assertEquals(PixelFormat.OPAQUE, mDrawableContainer.getOpacity());
 
-        MockDrawable dr1 = new MockDrawable();
-        dr1.setOpacity(PixelFormat.TRANSLUCENT);
+        Drawable dr1 = spy(new ColorDrawable(Color.RED));
+        doReturn(PixelFormat.TRANSLUCENT).when(dr1).getOpacity();
         mDrawableContainerState.addChild(dr1);
 
-        dr.selectDrawable(1);
-        assertEquals(mDrawableContainerState.getOpacity(), dr.getOpacity());
-        assertEquals(PixelFormat.TRANSLUCENT, dr.getOpacity());
+        mDrawableContainer.selectDrawable(1);
+        assertEquals(mDrawableContainerState.getOpacity(), mDrawableContainer.getOpacity());
+        assertEquals(PixelFormat.TRANSLUCENT, mDrawableContainer.getOpacity());
     }
 
-    public void testAccessCurrentDrawable() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
+    @Test(expected=NullPointerException.class)
+    public void testSelectDrawableNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.selectDrawable(0);
+    }
 
-        assertConstantStateNotSet();
-
-        assertNull(mDrawableContainer.getCurrent());
-        try {
-            dr.selectDrawable(0);
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
+    @Test
+    public void testSelectDrawable() {
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         MockDrawable dr0 = new MockDrawable();
         dr0.setVisible(false, false);
@@ -776,69 +737,38 @@
         assertFalse(dr1.isVisible());
         mDrawableContainerState.addChild(dr1);
 
-        assertTrue(dr.selectDrawable(0));
+        assertTrue(mDrawableContainer.selectDrawable(0));
         assertSame(dr0, mDrawableContainer.getCurrent());
         assertTrue(dr0.isVisible());
 
-        assertFalse(dr.selectDrawable(0));
+        assertFalse(mDrawableContainer.selectDrawable(0));
 
-        assertTrue(dr.selectDrawable(1));
+        assertTrue(mDrawableContainer.selectDrawable(1));
         assertSame(dr1, mDrawableContainer.getCurrent());
         assertTrue(dr1.isVisible());
         assertFalse(dr0.isVisible());
 
-        assertFalse(dr.selectDrawable(1));
+        assertFalse(mDrawableContainer.selectDrawable(1));
 
-        assertTrue(dr.selectDrawable(-1));
+        assertTrue(mDrawableContainer.selectDrawable(-1));
         assertNull(mDrawableContainer.getCurrent());
         assertFalse(dr0.isVisible());
         assertFalse(dr1.isVisible());
 
-        assertTrue(dr.selectDrawable(2));
+        assertTrue(mDrawableContainer.selectDrawable(2));
         assertNull(mDrawableContainer.getCurrent());
         assertFalse(dr0.isVisible());
         assertFalse(dr1.isVisible());
     }
 
+    @Test
     public void testAccessConstantState() {
-        try {
-            mDrawableContainer.getConstantState();
-            fail("Should throw NullPointerException if the constant state is not set.");
-        } catch (NullPointerException e) {
-        }
-
         mMockDrawableContainer.setConstantState(mDrawableContainerState);
         assertSame(mDrawableContainerState, mDrawableContainer.getConstantState());
 
         mMockDrawableContainer.setConstantState(null);
-        assertConstantStateNotSet();
-    }
-
-    public void testMutate() {
-        assertConstantStateNotSet();
-        try {
-            mDrawableContainer.mutate();
-            fail("Should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        mMockDrawableContainer.setConstantState(mDrawableContainerState);
-        MockDrawable dr0 = new MockDrawable();
-        mDrawableContainerState.addChild(dr0);
-        mDrawableContainer.mutate();
-        assertTrue(dr0.hasMutateCalled());
-    }
-
-    private void addAndSelectDrawable(MockDrawable mockDrawable) {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        DrawableContainer dr = mDrawableContainer;
-
-        int pos = mDrawableContainerState.addChild(mockDrawable);
-        dr.selectDrawable(pos);
-        assertSame(mockDrawable, dr.getCurrent());
-    }
-
-    private void assertConstantStateNotSet() {
+        // Note that we're not using 'expected' on the @Test annotation since we want to
+        // make sure that only this next call is going to throw NPE.
         try {
             mDrawableContainer.getConstantState();
             fail("Should throw NullPointerException.");
@@ -846,6 +776,27 @@
         }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testMutateNoConstantState() {
+        // Should throw NullPointerException if the constant state is not set
+        mDrawableContainer.mutate();
+    }
+
+    @Test
+    public void testMutate() {
+        mMockDrawableContainer.setConstantState(mDrawableContainerState);
+        Drawable dr0 = spy(new ColorDrawable(Color.MAGENTA));
+        mDrawableContainerState.addChild(dr0);
+        mDrawableContainer.mutate();
+        verify(dr0, atLeastOnce()).mutate();
+    }
+
+    private void addAndSelectDrawable(Drawable drawable) {
+        int pos = mDrawableContainerState.addChild(drawable);
+        mDrawableContainer.selectDrawable(pos);
+        assertSame(drawable, mDrawableContainer.getCurrent());
+    }
+
     private class MockDrawableContainer extends DrawableContainer {
         @Override
         protected void onBoundsChange(Rect bounds) {
@@ -868,135 +819,29 @@
         }
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of Drawable to track calls to protected methods. This class also has empty implementations
+    // of the base abstract methods.
     private class MockDrawable extends Drawable {
-        private boolean mHasCalledDraw;
-        private boolean mHasCalledSetAlpha;
-        private boolean mHasCalledSetColorFilter;
-        private boolean mHasCalledSetDither;
-        private boolean mHasCalledSetTint;
         private boolean mHasCalledOnBoundsChanged;
         private boolean mHasCalledOnStateChanged;
         private boolean mHasCalledOnLevelChanged;
-        private boolean mHasCalledMutate;
-
-        private boolean mIsStateful;
-
-        private Rect mPadding;
-
-        private int mIntrinsicHeight;
-        private int mIntrinsicWidth;
-
-        private int mMinimumHeight;
-        private int mMinimumWidth;
-
-        private int mOpacity;
-
-        private Mode mTintMode;
 
         @Override
         public int getOpacity() {
-            return mOpacity;
+            return PixelFormat.OPAQUE;
         }
 
         @Override
-        public boolean isStateful() {
-            return mIsStateful;
-        }
-
-        public void setStateful(boolean isStateful) {
-            mIsStateful = isStateful;
-        }
-
-        public Mode getTintMode() {
-            return mTintMode;
-        }
-
-        public void setPadding(Rect rect) {
-            if (mPadding == null) {
-                mPadding = new Rect();
-            }
-            mPadding.set(rect);
+        public void draw(Canvas canvas) {
         }
 
         @Override
-        public boolean getPadding(Rect padding) {
-            if (padding == null || mPadding == null) {
-                return false;
-            }
-            padding.set(mPadding);
-            return true;
+        public void setAlpha(int alpha) {
         }
 
         @Override
-        public int getMinimumHeight() {
-            return mMinimumHeight;
-        }
-
-        @Override
-        public int getMinimumWidth() {
-            return mMinimumWidth;
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mIntrinsicHeight;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return mIntrinsicWidth;
-        }
-
-        @Override
-        public Drawable mutate() {
-            mHasCalledMutate = true;
-            return this;
-        }
-
-        @Override
-        public void setTintMode(Mode tintMode) {
-            mTintMode = tintMode;
-            mHasCalledSetTint = true;
-        }
-
-        public void setMinimumHeight(int h) {
-            mMinimumHeight = h;
-        }
-
-        public void setMinimumWidth(int w) {
-            mMinimumWidth = w;
-        }
-
-        public void setIntrinsicHeight(int h) {
-            mIntrinsicHeight = h;
-        }
-
-        public void setIntrinsicWidth(int w) {
-            mIntrinsicWidth = w;
-        }
-
-        public void setOpacity(int opacity) {
-            mOpacity = opacity;
-        }
-
-        public boolean hasDrawCalled() {
-            return mHasCalledDraw;
-        }
-
-        public boolean hasSetAlphaCalled() {
-            return mHasCalledSetAlpha;
-        }
-
-        public boolean hasSetColorFilterCalled() {
-            return mHasCalledSetColorFilter;
-        }
-
-        public boolean hasSetDitherCalled() {
-            return mHasCalledSetDither;
-        }
-
-        public boolean hasSetTintCalled() {
-            return mHasCalledSetTint;
+        public void setColorFilter(ColorFilter colorFilter) {
         }
 
         public boolean hasOnBoundsChangedCalled() {
@@ -1011,34 +856,10 @@
             return mHasCalledOnLevelChanged;
         }
 
-        public boolean hasMutateCalled() {
-            return mHasCalledMutate;
-        }
-
         public void reset() {
             mHasCalledOnLevelChanged = false;
             mHasCalledOnStateChanged = false;
             mHasCalledOnBoundsChanged = false;
-            mHasCalledSetDither = false;
-            mHasCalledSetColorFilter = false;
-            mHasCalledSetAlpha = false;
-            mHasCalledDraw = false;
-            mHasCalledMutate = false;
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            mHasCalledDraw = true;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-            mHasCalledSetAlpha = true;
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-            mHasCalledSetColorFilter = true;
         }
 
         @Override
@@ -1059,55 +880,6 @@
             boolean result = super.onStateChange(state);
             mHasCalledOnStateChanged = true;
             return result;
-
-        }
-
-        @Override
-        public void setDither(boolean dither) {
-            super.setDither(dither);
-            mHasCalledSetDither = true;
-        }
-    }
-
-    private class MockCallBack implements Drawable.Callback {
-        private boolean mCalledInvalidateDrawable;
-
-        private boolean mCalledScheduleDrawable;
-
-        private boolean mCalledUnscheduleDrawable;
-
-        public boolean hasInvalidateDrawableCalled() {
-            return mCalledInvalidateDrawable;
-        }
-
-        public boolean hasScheduleDrawableCalled() {
-            return mCalledScheduleDrawable;
-        }
-
-        public boolean hasUnscheduleDrawableCalled() {
-            return mCalledUnscheduleDrawable;
-        }
-
-        public void reset() {
-            mCalledUnscheduleDrawable = false;
-            mCalledScheduleDrawable = false;
-            mCalledInvalidateDrawable = false;
-        }
-
-        public void invalidateDrawable(Drawable who) {
-            mCalledInvalidateDrawable = true;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mCalledScheduleDrawable = true;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mCalledUnscheduleDrawable = true;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
         }
     }
 }
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..13cc2e0 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,36 @@
 
 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.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.ContentResolver;
+import android.content.Context;
+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.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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,34 +54,31 @@
 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.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.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
-public class DrawableTest extends AndroidTestCase {
-    Resources mResources;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawableTest {
+    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 testClearColorFilter() {
         Drawable mockDrawable = new MockDrawable();
         mockDrawable.clearColorFilter();
@@ -73,6 +92,7 @@
         assertNull(mockDrawable.getColorFilter());
     }
 
+    @Test
     public void testCopyBounds() {
         Drawable mockDrawable = new MockDrawable();
         Rect rect1 = mockDrawable.copyBounds();
@@ -120,6 +140,7 @@
         }
     }
 
+    @Test
     public void testCreateFromPath() throws IOException {
         assertNull(Drawable.createFromPath(null));
 
@@ -139,29 +160,17 @@
     }
 
     private void writeSampleImage(File imagefile) throws IOException {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = mResources.openRawResource(R.raw.testimage);
-            target = new FileOutputStream(imagefile);
-
+        try (InputStream source = mResources.openRawResource(R.raw.testimage);
+             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 {
-            if (target != null) {
-                target.close();
-            }
-
-            if (source != null) {
-                source.close();
-            }
         }
     }
 
-    public void testCreateFromStream() throws FileNotFoundException, IOException {
+    @Test
+    public void testCreateFromStream() throws IOException {
         FileInputStream inputEmptyStream = null;
         FileInputStream inputStream = null;
         File imageFile = null;
@@ -186,7 +195,6 @@
             inputStream = new FileInputStream(imageFile);
             assertNotNull(Drawable.createFromStream(inputStream, "Sample"));
         } finally {
-
             if (null != outputEmptyStream) {
                 outputEmptyStream.close();
             }
@@ -205,13 +213,14 @@
         }
     }
 
-    public void testCreateFromResourceStream1() throws FileNotFoundException, IOException {
+    @Test
+    public void testCreateFromResourceStream1() throws IOException {
         FileInputStream inputEmptyStream = null;
         FileInputStream inputStream = null;
         File imageFile = null;
         OutputStream outputEmptyStream = null;
 
-        assertNull(Drawable.createFromResourceStream(null, null, inputStream, "test.bmp"));
+        assertNull(Drawable.createFromResourceStream(null, null, null, "test.bmp"));
 
         File emptyFile = new File(mContext.getFilesDir(), "tempemptyimage.jpg");
 
@@ -233,7 +242,6 @@
             assertNotNull(Drawable.createFromResourceStream(mResources, value, inputStream,
                     "Sample"));
         } finally {
-
             if (null != outputEmptyStream) {
                 outputEmptyStream.close();
             }
@@ -252,7 +260,8 @@
         }
     }
 
-    public void testCreateFromResourceStream2() throws FileNotFoundException, IOException {
+    @Test
+    public void testCreateFromResourceStream2() throws IOException {
         FileInputStream inputEmptyStream = null;
         FileInputStream inputStream = null;
         File imageFile = null;
@@ -261,7 +270,7 @@
         BitmapFactory.Options opt = new BitmapFactory.Options();
         opt.inScaled = false;
 
-        assertNull(Drawable.createFromResourceStream(null, null, inputStream, "test.bmp", opt));
+        assertNull(Drawable.createFromResourceStream(null, null, null, "test.bmp", opt));
 
         File emptyFile = new File(mContext.getFilesDir(), "tempemptyimage.jpg");
 
@@ -283,7 +292,6 @@
             assertNotNull(Drawable.createFromResourceStream(mResources, value, inputStream,
                     "Sample", opt));
         } finally {
-
             if (null != outputEmptyStream) {
                 outputEmptyStream.close();
             }
@@ -302,6 +310,7 @@
         }
     }
 
+    @Test
     public void testCreateFromXml() throws XmlPullParserException, IOException {
         XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable);
         Drawable drawable = Drawable.createFromXml(mResources, parser);
@@ -312,6 +321,7 @@
         assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testCreateFromXmlThemed() throws XmlPullParserException, IOException {
         XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable_theme);
         Theme theme = mResources.newTheme();
@@ -324,6 +334,7 @@
         assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testCreateFromXmlInner() throws XmlPullParserException, IOException {
         XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable);
         while (parser.next() != XmlPullParser.START_TAG) {
@@ -338,6 +349,7 @@
         assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testCreateFromXmlInnerThemed() throws XmlPullParserException, IOException {
         XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable_theme);
         while (parser.next() != XmlPullParser.START_TAG) {
@@ -354,6 +366,7 @@
         assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testAccessBounds() {
         Drawable mockDrawable = new MockDrawable();
         mockDrawable.setBounds(0, 0, 100, 100);
@@ -377,6 +390,7 @@
         }
     }
 
+    @Test
     public void testAccessChangingConfigurations() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(0, mockDrawable.getChangingConfigurations());
@@ -391,26 +405,31 @@
         assertEquals(Integer.MIN_VALUE, mockDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetConstantState() {
         Drawable mockDrawable = new MockDrawable();
         assertNull(mockDrawable.getConstantState());
     }
 
+    @Test
     public void testGetCurrent() {
         Drawable mockDrawable = new MockDrawable();
         assertSame(mockDrawable, mockDrawable.getCurrent());
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(-1, mockDrawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testGetIntrinsicWidth() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(-1, mockDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testAccessLevel() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(0, mockDrawable.getLevel());
@@ -428,16 +447,19 @@
         assertEquals(10000, mockDrawable.getLevel());
     }
 
+    @Test
     public void testGetMinimumHeight() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(0, mockDrawable.getMinimumHeight());
     }
 
+    @Test
     public void testGetMinimumWidth() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(0, mockDrawable.getMinimumWidth());
     }
 
+    @Test
     public void testGetPadding() {
         Drawable mockDrawable = new MockDrawable();
         Rect r = new Rect(10, 10, 20, 20);
@@ -454,6 +476,7 @@
         }
     }
 
+    @Test
     public void testAccessState() {
         Drawable mockDrawable = new MockDrawable();
         assertEquals(StateSet.WILD_CARD, mockDrawable.getState());
@@ -465,11 +488,13 @@
         mockDrawable.setState(null);
     }
 
+    @Test
     public void testGetTransparentRegion() {
         Drawable mockDrawable = new MockDrawable();
         assertNull(mockDrawable.getTransparentRegion());
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         Drawable mockDrawable = new MockDrawable();
 
@@ -484,23 +509,26 @@
         assertFalse(mockDrawable.isVisible());
     }
 
+    @Test
     public void testInvalidateSelf() {
         Drawable mockDrawable = new MockDrawable();
         // if setCallback() is not called, invalidateSelf() would do nothing,
         // so just call it to check whether it throws exceptions.
         mockDrawable.invalidateSelf();
 
-        MockCallback mockCallback = new MockCallback();
+        Drawable.Callback mockCallback = mock(Drawable.Callback.class);
         mockDrawable.setCallback(mockCallback);
         mockDrawable.invalidateSelf();
-        assertEquals(mockDrawable, mockCallback.getInvalidateDrawable());
+        verify(mockCallback, times(1)).invalidateDrawable(mockDrawable);
     }
 
+    @Test
     public void testIsStateful() {
         Drawable mockDrawable = new MockDrawable();
         assertFalse(mockDrawable.isStateful());
     }
 
+    @Test
     public void testVisible() {
         Drawable mockDrawable = new MockDrawable();
         assertTrue(mockDrawable.isVisible());
@@ -515,6 +543,7 @@
         assertTrue(mockDrawable.isVisible());
     }
 
+    @Test
     public void testOnBoundsChange() {
         MockDrawable mockDrawable = new MockDrawable();
 
@@ -522,16 +551,19 @@
         mockDrawable.onBoundsChange(new Rect(0, 0, 10, 10));
     }
 
+    @Test
     public void testOnLevelChange() {
         MockDrawable mockDrawable = new MockDrawable();
         assertFalse(mockDrawable.onLevelChange(0));
     }
 
+    @Test
     public void testOnStateChange() {
         MockDrawable mockDrawable = new MockDrawable();
         assertFalse(mockDrawable.onStateChange(null));
     }
 
+    @Test
     public void testResolveOpacity() {
         assertEquals(PixelFormat.TRANSLUCENT,
                 Drawable.resolveOpacity(PixelFormat.TRANSLUCENT, PixelFormat.TRANSLUCENT));
@@ -545,16 +577,27 @@
                 Drawable.resolveOpacity(PixelFormat.RGB_888, PixelFormat.RGB_565));
     }
 
+    @Test
     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));
     }
 
+    @Test
     public void testAccessCallback() {
         Drawable mockDrawable = new MockDrawable();
         Callback mockCallback = mock(Callback.class);
@@ -566,11 +609,13 @@
         assertEquals(null, mockDrawable.getCallback());
     }
 
+    @Test
     public void testSetColorFilter() {
         Drawable mockDrawable = new MockDrawable();
         mockDrawable.setColorFilter(5, PorterDuff.Mode.CLEAR);
     }
 
+    @Test
     public void testSetDither() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -578,6 +623,7 @@
         mockDrawable.setDither(false);
     }
 
+    @Test
     public void testSetHotspotBounds() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -585,6 +631,7 @@
         mockDrawable.setHotspotBounds(10, 15, 100, 150);
     }
 
+    @Test
     public void testGetHotspotBounds() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -592,6 +639,7 @@
         mockDrawable.getHotspotBounds(new Rect());
     }
 
+    @Test
     public void testAccessLayoutDirection() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -602,6 +650,7 @@
         assertEquals(View.LAYOUT_DIRECTION_RTL, mockDrawable.getLayoutDirection());
     }
 
+    @Test
     public void testOnLayoutDirectionChanged() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -609,6 +658,7 @@
         mockDrawable.onLayoutDirectionChanged(View.LAYOUT_DIRECTION_LTR);
     }
 
+    @Test
     public void testSetFilterBitmap() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -616,6 +666,7 @@
         mockDrawable.setFilterBitmap(false);
     }
 
+    @Test
     public void testIsFilterBitmap() {
         Drawable mockDrawable = new MockDrawable();
 
@@ -623,39 +674,48 @@
         mockDrawable.isFilterBitmap();
     }
 
+    @Test
     public void testUnscheduleSelf() {
         Drawable mockDrawable = new MockDrawable();
-        MockCallback mockCallback = new MockCallback();
+        Drawable.Callback mockCallback = mock(Drawable.Callback.class);
         mockDrawable.setCallback(mockCallback);
         mockDrawable.unscheduleSelf(null);
-        assertEquals(mockDrawable, mockCallback.getScheduleDrawable());
-        assertNull(mockCallback.getRunnable());
+        verify(mockCallback, times(1)).unscheduleDrawable(mockDrawable, null);
     }
 
+    @Test
     public void testMutate() {
         Drawable mockDrawable = new MockDrawable();
         assertSame(mockDrawable, mockDrawable.mutate());
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of Drawable to track calls to protected methods. This class also has empty implementations
+    // of the base abstract methods.
     private static class MockDrawable extends Drawable {
         private ColorFilter mColorFilter;
 
+        @Override
         public void draw(Canvas canvas) {
         }
 
+        @Override
         public void setAlpha(int alpha) {
         }
 
+        @Override
         public void setColorFilter(ColorFilter cf) {
             mColorFilter = cf;
         }
 
+        @Override
         public ColorFilter getColorFilter() {
             return mColorFilter;
         }
 
+        @Override
         public int getOpacity() {
-            return 0;
+            return PixelFormat.OPAQUE;
         }
 
         protected void onBoundsChange(Rect bounds) {
@@ -670,45 +730,4 @@
             return super.onStateChange(state);
         }
     }
-
-    private static class MockCallback implements Drawable.Callback {
-        private Drawable mInvalidateDrawable;
-        private Drawable mScheduleDrawable;
-        private Runnable mRunnable;
-        private long mWhen;
-
-        public MockCallback() {
-        }
-
-        public Drawable getInvalidateDrawable() {
-            return mInvalidateDrawable;
-        }
-
-        public Drawable getScheduleDrawable() {
-            return mScheduleDrawable;
-        }
-
-        public Runnable getRunnable() {
-            return mRunnable;
-        }
-
-        public long getWhen() {
-            return mWhen;
-        }
-
-        public void invalidateDrawable(Drawable who) {
-            mInvalidateDrawable = who;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mScheduleDrawable = who;
-            mRunnable = what;
-            mWhen = when;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mScheduleDrawable = who;
-            mRunnable = what;
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
index 340f945..03b2f22 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableWrapperTest.java
@@ -16,23 +16,45 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.drawable.DrawableWrapper;
-import android.graphics.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.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doNothing;
+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 android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableWrapper;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.StateSet;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
-import android.test.AndroidTestCase;
-import android.util.StateSet;
-
-public class DrawableWrapperTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawableWrapperTest {
     static class MyWrapper extends DrawableWrapper {
         public MyWrapper(Drawable dr) {
             super(dr);
@@ -40,6 +62,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
         Drawable d = new BitmapDrawable();
         DrawableWrapper wrapper = new MyWrapper(d);
@@ -49,6 +72,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetDrawable() {
         Drawable d = new BitmapDrawable();
         DrawableWrapper wrapper = new MyWrapper(d);
@@ -56,6 +80,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testSetDrawable() {
         Drawable d = new BitmapDrawable();
         DrawableWrapper wrapper = new MyWrapper(null);
@@ -66,120 +91,81 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testInvalidateDrawable() {
         DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable());
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         wrapper.setCallback(cb);
         wrapper.invalidateDrawable(null);
-        assertTrue(cb.hasCalledInvalidate());
+        verify(cb, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(cb);
         wrapper.invalidateDrawable(new BitmapDrawable());
-        assertTrue(cb.hasCalledInvalidate());
+        verify(cb, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(cb);
         wrapper.setCallback(null);
         wrapper.invalidateDrawable(null);
-        assertFalse(cb.hasCalledInvalidate());
+        verify(cb, never()).invalidateDrawable(any());
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testScheduleDrawable() {
         DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable());
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         wrapper.setCallback(cb);
         wrapper.scheduleDrawable(null, null, 0);
-        assertTrue(cb.hasCalledSchedule());
+        verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
-        wrapper.scheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        }, 1000L);
-        assertTrue(cb.hasCalledSchedule());
+        reset(cb);
+        wrapper.scheduleDrawable(new BitmapDrawable(), () -> {}, 1000L);
+        verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
+        reset(cb);
         wrapper.setCallback(null);
         wrapper.scheduleDrawable(null, null, 0);
-        assertFalse(cb.hasCalledSchedule());
+        verify(cb, never()).scheduleDrawable(any(), any(), anyLong());
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testUnscheduleDrawable() {
         DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable());
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         wrapper.setCallback(cb);
         wrapper.unscheduleDrawable(null, null);
-        assertTrue(cb.hasCalledUnschedule());
+        verify(cb, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
-        wrapper.unscheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        });
-        assertTrue(cb.hasCalledUnschedule());
+        reset(cb);
+        wrapper.unscheduleDrawable(new BitmapDrawable(), () -> {});
+        verify(cb, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
+        reset(cb);
         wrapper.setCallback(null);
         wrapper.unscheduleDrawable(null, null);
-        assertFalse(cb.hasCalledUnschedule());
+        verify(cb, never()).unscheduleDrawable(any(), any());
     }
 
-    private static class MockCallback implements Drawable.Callback {
-        private boolean mCalledInvalidate;
-        private boolean mCalledSchedule;
-        private boolean mCalledUnschedule;
-
-        public void invalidateDrawable(Drawable who) {
-            mCalledInvalidate = true;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mCalledSchedule = true;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mCalledUnschedule = true;
-        }
-
-        public boolean hasCalledInvalidate() {
-            return mCalledInvalidate;
-        }
-
-        public boolean hasCalledSchedule() {
-            return mCalledSchedule;
-        }
-
-        public boolean hasCalledUnschedule() {
-            return mCalledUnschedule;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-
-        public void reset() {
-            mCalledInvalidate = false;
-            mCalledSchedule = false;
-            mCalledUnschedule = false;
-        }
-    }
-
+    @Test
     public void testDraw() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.BLUE));
+        doNothing().when(mockDrawable).draw(any());
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         wrapper.draw(new Canvas());
-        assertTrue(mockDrawable.hasCalledDraw());
+        verify(mockDrawable, times(1)).draw(any());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
+        doNothing().when(mockDrawable).draw(any());
         wrapper.draw(null);
-        assertTrue(mockDrawable.hasCalledDraw());
+        verify(mockDrawable, times(1)).draw(any());
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         final int SUPER_CONFIG = 1;
         final int CONTAINED_DRAWABLE_CONFIG = 2;
@@ -197,91 +183,98 @@
                 wrapper.getChangingConfigurations());
     }
 
+    @Test
     public void testGetPadding() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's getPadding method.
         wrapper.getPadding(new Rect());
-        assertTrue(mockDrawable.hasCalledGetPadding());
-
-        // input null as param
-        try {
-            wrapper.getPadding(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        verify(mockDrawable, times(1)).getPadding(any());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetPaddingNull() {
+        DrawableWrapper wrapper = new MyWrapper(new ColorDrawable(Color.RED));
+
+        wrapper.getPadding(null);
+    }
+
+    @Test
     public void testSetVisible() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.YELLOW));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
         assertTrue(wrapper.isVisible());
 
         assertTrue(wrapper.setVisible(false, false));
         assertFalse(wrapper.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         assertFalse(wrapper.setVisible(false, false));
         assertFalse(wrapper.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         assertTrue(wrapper.setVisible(true, false));
         assertTrue(wrapper.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean());
     }
 
+    @Test
     public void testSetAlpha() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.MAGENTA));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's setAlpha method.
         wrapper.setAlpha(100);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         wrapper.setAlpha(Integer.MAX_VALUE);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         wrapper.setAlpha(-1);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
     }
 
+    @Test
     public void testSetColorFilter() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GRAY));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's setColorFilter method.
         wrapper.setColorFilter(new ColorFilter());
-        assertTrue(mockDrawable.hasCalledSetColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(any());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         wrapper.setColorFilter(null);
-        assertTrue(mockDrawable.hasCalledSetColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(any());
     }
 
+    @Test
     public void testGetOpacity() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // This method will call contained drawable's getOpacity method.
         wrapper.setLevel(1);
         wrapper.getOpacity();
-        assertTrue(mockDrawable.hasCalledGetOpacity());
+        verify(mockDrawable, times(1)).getOpacity();
     }
 
+    @Test
     public void testIsStateful() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.BLACK));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's isStateful method.
         wrapper.isStateful();
-        assertTrue(mockDrawable.hasCalledIsStateful());
+        verify(mockDrawable, times(1)).isStateful();
     }
 
+    @Test
     public void testOnStateChange() {
         Drawable d = new MockDrawable();
         MockDrawableWrapper wrapper = new MockDrawableWrapper(d);
@@ -291,7 +284,7 @@
         assertFalse("child did not change", wrapper.onStateChange(state));
         assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD);
 
-        d = mContext.getDrawable(R.drawable.statelistdrawable);
+        d = InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.statelistdrawable);
         wrapper = new MockDrawableWrapper(d);
         assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
         wrapper.onStateChange(state);
@@ -302,6 +295,7 @@
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testOnLevelChange() {
         MockDrawable mockDrawable = new MockDrawable();
         MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable);
@@ -315,11 +309,11 @@
         assertEquals(1000, mockDrawable.getLevel());
 
         mockDrawable.reset();
-        mockDrawableWrapper.reset();
         assertFalse(mockDrawableWrapper.onLevelChange(Integer.MIN_VALUE));
         assertTrue(mockDrawable.hasCalledOnLevelChange());
     }
 
+    @Test
     public void testOnBoundsChange() {
         MockDrawable mockDrawable = new MockDrawable();
         MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable);
@@ -340,110 +334,64 @@
         assertEquals(2, bounds.top);
         assertEquals(26, bounds.right);
         assertEquals(32, bounds.bottom);
-
-        // input null as param
-        try {
-            mockDrawableWrapper.onBoundsChange(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
-
     }
 
-    public void testGetIntrinsicWidth() {
+    @Test(expected=NullPointerException.class)
+    public void testOnBoundsChangeNull() {
         MockDrawable mockDrawable = new MockDrawable();
+        MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable);
+
+        mockDrawableWrapper.onBoundsChange(null);
+    }
+
+    @Test
+    public void testGetIntrinsicWidth() {
+        Drawable mockDrawable = spy(new ColorDrawable(Color.WHITE));
         MyWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's getIntrinsicWidth method.
         wrapper.getIntrinsicWidth();
-        assertTrue(mockDrawable.hasCalledGetIntrinsicWidth());
+        verify(mockDrawable, times(1)).getIntrinsicWidth();
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         DrawableWrapper wrapper = new MyWrapper(mockDrawable);
 
         // this method will call contained drawable's getIntrinsicHeight method.
         wrapper.getIntrinsicHeight();
-        assertTrue(mockDrawable.hasCalledGetIntrinsicHeight());
+        verify(mockDrawable, times(1)).getIntrinsicHeight();
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetConstantState() {
         DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable());
-        ConstantState constantState = wrapper.getConstantState();
+        wrapper.getConstantState();
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of Drawable to track calls to protected methods. This class also has empty implementations
+    // of the base abstract methods.
     private static class MockDrawable extends Drawable {
-        private boolean mCalledDraw = false;
-        private boolean mCalledGetPadding = false;
-        private boolean mCalledSetVisible = false;
-        private boolean mCalledSetAlpha = false;
-        private boolean mCalledGetOpacity = false;
-        private boolean mCalledSetColorFilter = false;
-        private boolean mCalledIsStateful = false;
-        private boolean mCalledGetIntrinsicWidth = false;
-        private boolean mCalledGetIntrinsicHeight = false;
-        private boolean mCalledSetState = false;
         private boolean mCalledOnLevelChange = false;
 
         @Override
         public void draw(Canvas canvas) {
-            mCalledDraw = true;
         }
 
         @Override
         public int getOpacity() {
-            mCalledGetOpacity = true;
-            return 0;
+            return PixelFormat.OPAQUE;
         }
 
         @Override
         public void setAlpha(int alpha) {
-            mCalledSetAlpha = true;
         }
 
         @Override
         public void setColorFilter(ColorFilter cf) {
-            mCalledSetColorFilter = true;
-        }
-
-        @Override
-        public boolean getPadding(Rect padding) {
-            mCalledGetPadding = true;
-            return super.getPadding(padding);
-        }
-
-        @Override
-        public boolean setVisible(boolean visible, boolean restart) {
-            mCalledSetVisible = true;
-            return super.setVisible(visible, restart);
-        }
-
-        @Override
-        public boolean isStateful() {
-            mCalledIsStateful = true;
-            return super.isStateful();
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            mCalledGetIntrinsicWidth = true;
-            return super.getIntrinsicWidth();
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            mCalledGetIntrinsicHeight = true;
-            return super.getIntrinsicHeight();
-
-        }
-
-        @Override
-        public boolean setState(final int[] stateSet) {
-            mCalledSetState = true;
-            return super.setState(stateSet);
         }
 
         @Override
@@ -452,68 +400,16 @@
             return super.onLevelChange(level);
         }
 
-        public boolean hasCalledDraw() {
-            return mCalledDraw;
-        }
-
-        public boolean hasCalledGetPadding() {
-            return mCalledGetPadding;
-        }
-
-        public boolean hasCalledSetVisible() {
-            return mCalledSetVisible;
-        }
-
-        public boolean hasCalledSetAlpha() {
-            return mCalledSetAlpha;
-        }
-
-        public boolean hasCalledGetOpacity() {
-            return mCalledGetOpacity;
-        }
-
-        public boolean hasCalledSetColorFilter() {
-            return mCalledSetColorFilter;
-        }
-
-        public boolean hasCalledIsStateful() {
-            return mCalledIsStateful;
-        }
-
-        public boolean hasCalledGetIntrinsicWidth() {
-            return mCalledGetIntrinsicWidth;
-        }
-
-        public boolean hasCalledGetIntrinsicHeight() {
-            return mCalledGetIntrinsicHeight;
-        }
-
-        public boolean hasCalledSetState() {
-            return mCalledSetState;
-        }
-
         public boolean hasCalledOnLevelChange() {
             return mCalledOnLevelChange;
         }
 
         public void reset() {
-            mCalledDraw = false;
-            mCalledGetPadding = false;
-            mCalledSetVisible = false;
-            mCalledSetAlpha = false;
-            mCalledGetOpacity = false;
-            mCalledSetColorFilter = false;
-            mCalledIsStateful = false;
-            mCalledGetIntrinsicWidth = false;
-            mCalledGetIntrinsicHeight = false;
-            mCalledSetState = false;
             mCalledOnLevelChange = false;
         }
     }
 
     private static class MockDrawableWrapper extends DrawableWrapper {
-        private boolean mCalledOnBoundsChange = false;
-
         MockDrawableWrapper() {
             super(null);
         }
@@ -534,16 +430,7 @@
 
         @Override
         protected void onBoundsChange(Rect bounds) {
-            mCalledOnBoundsChange = true;
             super.onBoundsChange(bounds);
         }
-
-        public boolean hasCalledOnBoundsChange() {
-            return mCalledOnBoundsChange;
-        }
-
-        public void reset() {
-            mCalledOnBoundsChange = false;
-        }
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/Drawable_ConstantStateTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/Drawable_ConstantStateTest.java
index 45e83dd..abcb71f 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/Drawable_ConstantStateTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/Drawable_ConstantStateTest.java
@@ -16,39 +16,57 @@
 
 package android.graphics.drawable.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+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.content.Context;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Drawable_ConstantStateTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Drawable_ConstantStateTest {
+    @Test
     public void testNewDrawable() {
-        MockConstantState mock = new MockConstantState();
+        Context context = InstrumentationRegistry.getTargetContext();
+        Resources resources = context.getResources();
+
+        MockConstantState mock = spy(new MockConstantState());
         ConstantState cs = mock;
 
         assertEquals(null, cs.newDrawable());
-        assertTrue(mock.hasCalledNewDrawable());
-        mock.reset();
+        verify(mock, times(1)).newDrawable();
+        reset(mock);
 
-        assertEquals(null, cs.newDrawable(mContext.getResources()));
-        assertTrue(mock.hasCalledNewDrawable());
-        mock.reset();
+        assertEquals(null, cs.newDrawable(resources));
+        verify(mock, times(1)).newDrawable();
+        reset(mock);
 
-        assertEquals(null, cs.newDrawable(mContext.getResources(), mContext.getTheme()));
-        assertTrue(mock.hasCalledNewDrawable());
+        assertEquals(null, cs.newDrawable(resources, context.getTheme()));
+        verify(mock, times(1)).newDrawable();
+        reset(mock);
     }
 
+    @Test
     public void testCanApplyTheme() {
         ConstantState cs = new MockConstantState();
         assertFalse(cs.canApplyTheme());
     }
 
     public static class MockConstantState extends ConstantState {
-        private boolean mCalledNewDrawable;
-
         @Override
         public Drawable newDrawable() {
-            mCalledNewDrawable = true;
             return null;
         }
 
@@ -56,13 +74,5 @@
         public int getChangingConfigurations() {
             return 0;
         }
-
-        public boolean hasCalledNewDrawable() {
-            return mCalledNewDrawable;
-        }
-
-        public void reset() {
-            mCalledNewDrawable = false;
-        }
     }
 }
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..eb660f3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -16,8 +16,12 @@
 
 package android.graphics.drawable.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertArrayEquals;
+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.junit.Assert.fail;
 
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -32,19 +36,33 @@
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.GradientDrawable.Orientation;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 
+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;
 import java.util.Arrays;
 
-import static org.junit.Assert.assertArrayEquals;
+@RunWith(AndroidJUnit4.class)
+public class GradientDrawableTest {
+    private Resources mResources;
 
-public class GradientDrawableTest extends AndroidTestCase {
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
+    }
+
     @SmallTest
+    @Test
     public void testConstructor() {
         int[] color = new int[] {1, 2, 3};
 
@@ -54,6 +72,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetOpacity() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertEquals("Default opacity is TRANSLUCENT",
@@ -87,6 +106,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetOrientation() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Orientation orientation;
@@ -98,6 +118,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetCornerRadii() {
         float[] radii = new float[] {1.0f, 2.0f, 3.0f};
 
@@ -116,6 +137,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetCornerRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -124,6 +146,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,13 +175,14 @@
     }
 
     @SmallTest
+    @Test
     public void testSetStroke_WidthGap() {
-        helpTestSetStroke_WidthGap(2, Color.RED, 3.4f, 5.5f);
-        helpTestSetStroke_WidthGap(-2, Color.TRANSPARENT, -3.4f, -5.5f);
-        helpTestSetStroke_WidthGap(0, 0, 0, (float) 0.0f);
+        verifySetStroke_WidthGap(2, Color.RED, 3.4f, 5.5f);
+        verifySetStroke_WidthGap(-2, Color.TRANSPARENT, -3.4f, -5.5f);
+        verifySetStroke_WidthGap(0, 0, 0, (float) 0.0f);
     }
 
-    private void helpTestSetStroke_WidthGap(int width, int color,
+    private void verifySetStroke_WidthGap(int width, int color,
             float dashWidth, float dashGap) {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setStroke(width, color, dashWidth, dashGap);
@@ -151,13 +190,14 @@
     }
 
     @SmallTest
+    @Test
     public void testSetStrokeList() {
-        helpTestSetStrokeList(2, ColorStateList.valueOf(Color.RED));
-        helpTestSetStrokeList(-2, ColorStateList.valueOf(Color.TRANSPARENT));
-        helpTestSetStrokeList(0, null);
+        verifySetStrokeList(2, ColorStateList.valueOf(Color.RED));
+        verifySetStrokeList(-2, ColorStateList.valueOf(Color.TRANSPARENT));
+        verifySetStrokeList(0, null);
     }
 
-    private void helpTestSetStrokeList(int width,
+    private void verifySetStrokeList(int width,
             ColorStateList colorList) {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setStroke(width, colorList);
@@ -165,13 +205,14 @@
     }
 
     @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);
-        helpTestSetStrokeList_WidthGap(0, null, 0.0f, 0.0f);
+        verifySetStrokeList_WidthGap(2, ColorStateList.valueOf(Color.RED), 3.4f, 5.5f);
+        verifySetStrokeList_WidthGap(-2, ColorStateList.valueOf(Color.TRANSPARENT), -3.4f, -5.5f);
+        verifySetStrokeList_WidthGap(0, null, 0.0f, 0.0f);
     }
 
-    private void helpTestSetStrokeList_WidthGap(int width, ColorStateList colorList,
+    private void verifySetStrokeList_WidthGap(int width, ColorStateList colorList,
             float dashWidth, float dashGap) {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setStroke(width, colorList, dashWidth, dashGap);
@@ -179,14 +220,15 @@
     }
 
     @SmallTest
+    @Test
     public void testSetSize() {
-        helpTestSetSize(6, 4);
-        helpTestSetSize(-30, -40);
-        helpTestSetSize(0, 0);
-        helpTestSetSize(Integer.MAX_VALUE, Integer.MIN_VALUE);
+        verifySetSize(6, 4);
+        verifySetSize(-30, -40);
+        verifySetSize(0, 0);
+        verifySetSize(Integer.MAX_VALUE, Integer.MIN_VALUE);
     }
 
-    private void helpTestSetSize(int width, int height) {
+    private void verifySetSize(int width, int height) {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setSize(width, height);
         assertEquals(width, gradientDrawable.getIntrinsicWidth());
@@ -194,6 +236,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetShape() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int shape;
@@ -210,6 +253,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetGradientType() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int gradientType;
@@ -226,6 +270,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetGradientCenter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         float centerX;
@@ -245,11 +290,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 +304,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetUseLevel() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         boolean useLevel;
@@ -276,6 +323,7 @@
     }
 
     @SmallTest
+    @Test
     public void testDraw() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Canvas c = new Canvas();
@@ -286,6 +334,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColor() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int color;
@@ -302,6 +351,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColors() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         int[] colors;
@@ -318,6 +368,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColorList() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         ColorStateList color;
@@ -332,6 +383,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetChangingConfigurations() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertEquals(0, gradientDrawable.getChangingConfigurations());
@@ -344,6 +396,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetAlpha() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -352,6 +405,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetDither() {
         GradientDrawable gradientDrawable = new GradientDrawable();
 
@@ -360,6 +414,7 @@
     }
 
     @SmallTest
+    @Test
     public void testSetColorFilter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         ColorFilter cf = new ColorFilter();
@@ -370,6 +425,7 @@
     }
 
     @SmallTest
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         GradientDrawable gradientDrawable = new GradientDrawable();
         Rect rect = new Rect();
@@ -379,8 +435,7 @@
         assertEquals(0, rect.right);
         assertEquals(0, rect.bottom);
 
-        Resources resources = mContext.getResources();
-        XmlPullParser parser = resources.getXml(R.drawable.gradientdrawable);
+        XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable);
         AttributeSet attrs = Xml.asAttributeSet(parser);
 
         // find the START_TAG
@@ -392,7 +447,7 @@
         assertEquals(XmlPullParser.START_TAG, type);
 
         // padding is set in gradientdrawable.xml
-        gradientDrawable.inflate(resources, parser, attrs);
+        gradientDrawable.inflate(mResources, parser, attrs);
         assertTrue(gradientDrawable.getPadding(rect));
         assertEquals(4, rect.left);
         assertEquals(2, rect.top);
@@ -415,20 +470,20 @@
     }
 
     @SmallTest
+    @Test
     public void testInflateGradientRadius() throws XmlPullParserException, IOException {
         Rect parentBounds = new Rect(0, 0, 100, 100);
-        Resources resources = mContext.getResources();
 
         GradientDrawable gradientDrawable;
         float radius;
 
-        gradientDrawable = (GradientDrawable) resources.getDrawable(
+        gradientDrawable = (GradientDrawable) mResources.getDrawable(
                 R.drawable.gradientdrawable_radius_base);
         gradientDrawable.setBounds(parentBounds);
         radius = gradientDrawable.getGradientRadius();
         assertEquals(25.0f, radius, 0.0f);
 
-        gradientDrawable = (GradientDrawable) resources.getDrawable(
+        gradientDrawable = (GradientDrawable) mResources.getDrawable(
                 R.drawable.gradientdrawable_radius_parent);
         gradientDrawable.setBounds(parentBounds);
         radius = gradientDrawable.getGradientRadius();
@@ -436,6 +491,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetIntrinsicWidth() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setSize(6, 4);
@@ -446,6 +502,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetIntrinsicHeight() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         gradientDrawable.setSize(5, 3);
@@ -456,17 +513,21 @@
     }
 
     @SmallTest
+    @Test
     public void testGetConstantState() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertNotNull(gradientDrawable.getConstantState());
     }
 
     @SmallTest
+    @Test
     public void testMutate() {
-        Resources resources = mContext.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);
+        GradientDrawable d1 =
+                (GradientDrawable) mResources.getDrawable(R.drawable.gradientdrawable);
+        GradientDrawable d2 =
+                (GradientDrawable) mResources.getDrawable(R.drawable.gradientdrawable);
+        GradientDrawable d3 =
+                (GradientDrawable) mResources.getDrawable(R.drawable.gradientdrawable);
 
         d1.setSize(10, 10);
         assertEquals(10, d1.getIntrinsicHeight());
@@ -495,17 +556,17 @@
     }
 
     @MediumTest
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
-        final int densityDpi = res.getConfiguration().densityDpi;
+        final int densityDpi = mResources.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, densityDpi);
+            verifyPreloadDensityInner(mResources, densityDpi);
         } finally {
-            DrawableTestUtils.setResourcesDensity(res, densityDpi);
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int densityDpi)
+    private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
index 299eaf0..e58b402 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
@@ -16,169 +16,134 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.cts.R;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
-import android.app.Instrumentation;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
-import android.graphics.cts.ImageViewCtsActivity;
-import android.graphics.drawable.Icon;
-import android.graphics.drawable.Drawable;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
+import android.graphics.cts.ImageViewCtsActivity;
+import android.graphics.cts.R;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Parcel;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.MediumTest;
+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 java.io.File;
 import java.io.FileOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 
-public class IconTest extends ActivityInstrumentationTestCase2<ImageViewCtsActivity> {
-    static final long TIMEOUT = 1000;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class IconTest {
+    private static final long TIMEOUT_MS = 1000;
 
-    Activity mActivity;
-    Instrumentation mInstrumentation;
-    Icon mIcon;
+    private Activity mActivity;
+    private Icon mIcon;
 
-    MockOnDrawableLoadedListener mListener;
-    MockRunner mRunner;
+    @Rule
+    public ActivityTestRule<ImageViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ImageViewCtsActivity.class);
 
-    public IconTest() {
-        super("android.graphics.cts", ImageViewCtsActivity.class);
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-    }
-
+    @Test
     public void testBitmapIcon() {
-        checkIconValidity(
+        verifyIconValidity(
                 Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888)));
     }
 
+    @Test
     public void testDataIcon() {
         byte[] data = new byte[4];
         data[0] = data[1] = data[2] = data[3] = (byte)255;
-        checkIconValidity(Icon.createWithData(data, 0, 4));
+        verifyIconValidity(Icon.createWithData(data, 0, 4));
     }
 
+    @Test
     public void testFileIcon() throws IOException {
         File file = new File(mActivity.getFilesDir(), "testimage.jpg");
         try {
             writeSampleImage(file);
             assertTrue(file.exists());
 
-            checkIconValidity(Icon.createWithFilePath(file.getPath()));
+            verifyIconValidity(Icon.createWithFilePath(file.getPath()));
 
-            checkIconValidity(Icon.createWithContentUri(Uri.fromFile(file)));
+            verifyIconValidity(Icon.createWithContentUri(Uri.fromFile(file)));
 
-            checkIconValidity(Icon.createWithContentUri(file.toURI().toString()));
+            verifyIconValidity(Icon.createWithContentUri(file.toURI().toString()));
         } finally {
             file.delete();
         }
     }
 
+    @Test
     public void testResourceIcon() {
-        checkIconValidity(Icon.createWithResource(mActivity, R.drawable.bmp_test));
+        verifyIconValidity(Icon.createWithResource(mActivity, R.drawable.bmp_test));
 
-        checkIconValidity(Icon.createWithResource(mActivity.getPackageName(), R.drawable.bmp_test));
+        verifyIconValidity(Icon.createWithResource(
+                mActivity.getPackageName(), R.drawable.bmp_test));
     }
 
-    public void testLoadDrawableAsync() {
+    @Test
+    public void testLoadDrawableAsync() throws Throwable {
         mIcon = Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888));
 
-        mListener = new MockOnDrawableLoadedListener();
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mIcon.loadDrawableAsync(mActivity, mListener, new Handler());
-            }
-        });
-        sleep(TIMEOUT);
-
-        assertEquals(1, mListener.getLoadedCount());
+        Icon.OnDrawableLoadedListener mockListener = mock(Icon.OnDrawableLoadedListener.class);
+        mActivityRule.runOnUiThread(
+                () -> mIcon.loadDrawableAsync(mActivity, mockListener, new Handler()));
+        // Verify that there was exactly one call to the passed listener's callback within the
+        // predetermined timeout
+        Thread.sleep(TIMEOUT_MS);
+        verify(mockListener, times(1)).onDrawableLoaded(any());
     }
 
-    public void testLoadDrawableAsyncWithMessage() {
+    @Test
+    public void testLoadDrawableAsyncWithMessage() throws Throwable {
         mIcon = Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888));
 
-        mRunner = new MockRunner();
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mIcon.loadDrawableAsync(mActivity, Message.obtain(new Handler(), mRunner));
-            }
-        });
-        sleep(TIMEOUT);
-
-        assertEquals(1, mRunner.getRunCount());
-    }
-
-    class MockOnDrawableLoadedListener implements Icon.OnDrawableLoadedListener {
-        int mLoadedCount;
-
-        @Override
-        public void onDrawableLoaded(Drawable d) {
-            assertNotNull(d);
-            ++mLoadedCount;
-        }
-
-        int getLoadedCount() { return mLoadedCount; }
-    }
-
-    class MockRunner implements Runnable {
-        int mRun;
-
-        @Override
-        public void run() {
-            ++mRun;
-        }
-
-        int getRunCount() { return mRun; }
-    };
-
-    private void sleep(long time) {
-        try {
-            Thread.sleep(time);
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
+        Runnable mockRunnable = mock(Runnable.class);
+        mActivityRule.runOnUiThread(
+                () -> mIcon.loadDrawableAsync(mActivity, Message.obtain(new Handler(),
+                        mockRunnable)));
+        // Verify that there was exactly one call to the passed Runnable's run within the
+        // predetermined timeout
+        Thread.sleep(TIMEOUT_MS);
+        verify(mockRunnable, times(1)).run();
     }
 
     private void writeSampleImage(File imagefile) throws IOException {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = mActivity.getResources().openRawResource(R.drawable.testimage);
-            target = new FileOutputStream(imagefile);
-
+        try (InputStream source = mActivity.getResources().openRawResource(R.drawable.testimage);
+             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 {
-            if (target != null) {
-                target.close();
-            }
-
-            if (source != null) {
-                source.close();
-            }
         }
     }
 
     // Check if the created icon is valid and doesn't cause crashes for the public methods.
-    private void checkIconValidity(Icon icon) {
+    private void verifyIconValidity(Icon icon) {
         assertNotNull(icon);
 
         // tint properties.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index 8f6eb63..3fcdf82 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -16,9 +16,13 @@
 
 package android.graphics.drawable.cts;
 
-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 static org.junit.Assert.fail;
 
+import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
@@ -30,27 +34,48 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.InsetDrawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.util.Xml;
 import android.view.InflateException;
 
+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;
 import java.util.Arrays;
 
-public class InsetDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InsetDrawableTest {
+    private Context mContext;
+    private Drawable mPassDrawable;
+    private InsetDrawable mInsetDrawable;
 
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mPassDrawable = mContext.getDrawable(R.drawable.pass);
+        mInsetDrawable = new InsetDrawable(mPassDrawable, 0);
+    }
+
+    @Test
     public void testConstructor() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        new InsetDrawable(d, 1);
-        new InsetDrawable(d, 1, 1, 1, 1);
+        new InsetDrawable(mPassDrawable, 1);
+        new InsetDrawable(mPassDrawable, 1, 1, 1, 1);
 
         new InsetDrawable(null, -1);
         new InsetDrawable(null, -1, -1, -1, -1);
     }
 
-    public void testInflate() {
+    @Test
+    public void testInflate() throws Throwable {
         InsetDrawable insetDrawable = new InsetDrawable(null, 0);
 
         Resources r = mContext.getResources();
@@ -62,92 +87,62 @@
             fail("There should be an InflateException thrown out.");
         } catch (InflateException e) {
             // expected, test success
-        } catch (IOException e) {
-            fail("There should not be an IOException thrown out.");
-        } catch (XmlPullParserException e) {
-            fail("There should not be a XmlPullParserException thrown out.");
-        }
-
-        // input null as params
-        try {
-            insetDrawable.inflate(null, null, null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        } catch (IOException e) {
-            fail("There should not be an IOException thrown out.");
-        } catch (XmlPullParserException e) {
-            fail("There should not be a XmlPullParserException thrown out.");
         }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testInflateNull() throws Throwable {
+        InsetDrawable insetDrawable = new InsetDrawable(null, 0);
+
+        insetDrawable.inflate(null, null, null);
+    }
+
+    @Test
     public void testInvalidateDrawable() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
-        insetDrawable.invalidateDrawable(d);
+        mInsetDrawable.invalidateDrawable(mPassDrawable);
     }
 
+    @Test
     public void testScheduleDrawable() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
-        Runnable runnable = new Runnable() {
-            public void run() {
-            }
-        };
-        insetDrawable.scheduleDrawable(d, runnable, 10);
+        mInsetDrawable.scheduleDrawable(mPassDrawable, () -> {}, 10);
 
         // input null as params
-        insetDrawable.scheduleDrawable(null, null, -1);
+        mInsetDrawable.scheduleDrawable(null, null, -1);
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testUnscheduleDrawable() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
-        Runnable runnable = new Runnable() {
-            public void run() {
-            }
-        };
-        insetDrawable.unscheduleDrawable(d, runnable);
+        mInsetDrawable.unscheduleDrawable(mPassDrawable, () -> {});
 
         // input null as params
-        insetDrawable.unscheduleDrawable(null, null);
+        mInsetDrawable.unscheduleDrawable(null, null);
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testDraw() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
         Canvas c = new Canvas();
-        insetDrawable.draw(c);
-
-        // input null as param
-        try {
-            insetDrawable.draw(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
+        mInsetDrawable.draw(c);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawNull() {
+        mInsetDrawable.draw(null);
+    }
+
+    @Test
     public void testGetChangingConfigurations() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
+        mInsetDrawable.setChangingConfigurations(11);
+        assertEquals(11, mInsetDrawable.getChangingConfigurations());
 
-        insetDrawable.setChangingConfigurations(11);
-        assertEquals(11, insetDrawable.getChangingConfigurations());
-
-        insetDrawable.setChangingConfigurations(-21);
-        assertEquals(-21, insetDrawable.getChangingConfigurations());
+        mInsetDrawable.setChangingConfigurations(-21);
+        assertEquals(-21, mInsetDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetPadding() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 1, 2, 3, 4);
+        InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, 1, 2, 3, 4);
 
         Rect r = new Rect();
         assertEquals(0, r.left);
@@ -163,7 +158,7 @@
         assertEquals(4, r.bottom);
 
         // padding is set to 0, then return value should be false
-        insetDrawable = new InsetDrawable(d, 0);
+        insetDrawable = new InsetDrawable(mPassDrawable, 0);
 
         r = new Rect();
         assertEquals(0, r.left);
@@ -177,90 +172,80 @@
         assertEquals(0, r.top);
         assertEquals(0, r.right);
         assertEquals(0, r.bottom);
-
-        // input null as param
-        try {
-            insetDrawable.getPadding(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetPaddingNull() {
+        InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, 1, 2, 3, 4);
+        insetDrawable.getPadding(null);
+    }
+
+    @Test
     public void testSetVisible() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
-        assertFalse(insetDrawable.setVisible(true, true)); /* unchanged */
-        assertTrue(insetDrawable.setVisible(false, true)); /* changed */
-        assertFalse(insetDrawable.setVisible(false, true)); /* unchanged */
+        assertFalse(mInsetDrawable.setVisible(true, true)); /* unchanged */
+        assertTrue(mInsetDrawable.setVisible(false, true)); /* changed */
+        assertFalse(mInsetDrawable.setVisible(false, true)); /* unchanged */
     }
 
+    @Test
     public void testSetAlpha() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
+        mInsetDrawable.setAlpha(1);
+        mInsetDrawable.setAlpha(-1);
 
-        insetDrawable.setAlpha(1);
-        insetDrawable.setAlpha(-1);
-
-        insetDrawable.setAlpha(0);
-        insetDrawable.setAlpha(Integer.MAX_VALUE);
-        insetDrawable.setAlpha(Integer.MIN_VALUE);
+        mInsetDrawable.setAlpha(0);
+        mInsetDrawable.setAlpha(Integer.MAX_VALUE);
+        mInsetDrawable.setAlpha(Integer.MIN_VALUE);
     }
 
+    @Test
     public void testSetColorFilter() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
         ColorFilter cf = new ColorFilter();
-        insetDrawable.setColorFilter(cf);
+        mInsetDrawable.setColorFilter(cf);
 
         // input null as param
-        insetDrawable.setColorFilter(null);
+        mInsetDrawable.setColorFilter(null);
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testGetOpacity() {
-        Drawable d = mContext.getDrawable(R.drawable.testimage);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-        insetDrawable.setAlpha(255);
-        assertEquals(PixelFormat.OPAQUE, insetDrawable.getOpacity());
+        mInsetDrawable.setAlpha(255);
+        assertEquals(PixelFormat.OPAQUE, mInsetDrawable.getOpacity());
 
-        insetDrawable.setAlpha(100);
-        assertEquals(PixelFormat.TRANSLUCENT, insetDrawable.getOpacity());
+        mInsetDrawable.setAlpha(100);
+        assertEquals(PixelFormat.TRANSLUCENT, mInsetDrawable.getOpacity());
     }
 
+    @Test
     public void testIsStateful() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-        assertFalse(insetDrawable.isStateful());
+        assertFalse(mInsetDrawable.isStateful());
     }
 
+    @Test
     public void testOnStateChange() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        MockInsetDrawable insetDrawable = new MockInsetDrawable(d, 10);
-        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
+        MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 10);
+        assertEquals("initial child state is empty", mPassDrawable.getState(), StateSet.WILD_CARD);
 
         int[] state = new int[] {1, 2, 3};
         assertFalse("child did not change", insetDrawable.onStateChange(state));
-        assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD);
+        assertEquals("child state did not change", mPassDrawable.getState(), StateSet.WILD_CARD);
 
-        d = mContext.getDrawable(R.drawable.statelistdrawable);
-        insetDrawable = new MockInsetDrawable(d, 10);
-        assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD);
+        mPassDrawable = mContext.getDrawable(R.drawable.statelistdrawable);
+        insetDrawable = new MockInsetDrawable(mPassDrawable, 10);
+        assertEquals("initial child state is empty", mPassDrawable.getState(), StateSet.WILD_CARD);
         insetDrawable.onStateChange(state);
-        assertTrue("child state changed", Arrays.equals(state, d.getState()));
+        assertTrue("child state changed", Arrays.equals(state, mPassDrawable.getState()));
 
         // input null as param
         insetDrawable.onStateChange(null);
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testOnBoundsChange() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        MockInsetDrawable insetDrawable = new MockInsetDrawable(d, 5);
+        MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
 
-        Rect bounds = d.getBounds();
+        Rect bounds = mPassDrawable.getBounds();
         assertEquals(0, bounds.left);
         assertEquals(0, bounds.top);
         assertEquals(0, bounds.right);
@@ -273,72 +258,66 @@
         assertEquals(5, bounds.top);
         assertEquals(-5, bounds.right);
         assertEquals(-5, bounds.bottom);
-
-        // input null as param
-        try {
-            insetDrawable.onBoundsChange(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testOnBoundsChangeNull() {
+        MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
+
+        insetDrawable.onBoundsChange(null);
+    }
+
+    @Test
     public void testGetIntrinsicWidth() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
+        int expected = mPassDrawable.getIntrinsicWidth();
+        assertEquals(expected, mInsetDrawable.getIntrinsicWidth());
 
-        int expected = d.getIntrinsicWidth();
-        assertEquals(expected, insetDrawable.getIntrinsicWidth());
+        mPassDrawable = mContext.getDrawable(R.drawable.scenery);
+        mInsetDrawable = new InsetDrawable(mPassDrawable, 0);
 
-        d = mContext.getDrawable(R.drawable.scenery);
-        insetDrawable = new InsetDrawable(d, 0);
+        expected = mPassDrawable.getIntrinsicWidth();
+        assertEquals(expected, mInsetDrawable.getIntrinsicWidth());
 
-        expected = d.getIntrinsicWidth();
-        assertEquals(expected, insetDrawable.getIntrinsicWidth());
+        mPassDrawable = mContext.getDrawable(R.drawable.scenery);
+        mInsetDrawable = new InsetDrawable(mPassDrawable, 20);
 
-        d = mContext.getDrawable(R.drawable.scenery);
-        insetDrawable = new InsetDrawable(d, 20);
+        expected = mPassDrawable.getIntrinsicWidth() + 40;
+        assertEquals(expected, mInsetDrawable.getIntrinsicWidth());
 
-        expected = d.getIntrinsicWidth() + 40;
-        assertEquals(expected, insetDrawable.getIntrinsicWidth());
-
-        d = mContext.getDrawable(R.drawable.inset_color);
+        mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
         expected = -1;
-        assertEquals(expected, d.getIntrinsicWidth());
+        assertEquals(expected, mPassDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
+        int expected = mPassDrawable.getIntrinsicHeight();
+        assertEquals(expected, mInsetDrawable.getIntrinsicHeight());
 
-        int expected = d.getIntrinsicHeight();
-        assertEquals(expected, insetDrawable.getIntrinsicHeight());
+        mPassDrawable = mContext.getDrawable(R.drawable.scenery);
+        mInsetDrawable = new InsetDrawable(mPassDrawable, 0);
 
-        d = mContext.getDrawable(R.drawable.scenery);
-        insetDrawable = new InsetDrawable(d, 0);
+        expected = mPassDrawable.getIntrinsicHeight();
+        assertEquals(expected, mInsetDrawable.getIntrinsicHeight());
 
-        expected = d.getIntrinsicHeight();
-        assertEquals(expected, insetDrawable.getIntrinsicHeight());
+        mPassDrawable = mContext.getDrawable(R.drawable.scenery);
+        mInsetDrawable = new InsetDrawable(mPassDrawable, 20);
 
-        d = mContext.getDrawable(R.drawable.scenery);
-        insetDrawable = new InsetDrawable(d, 20);
+        expected = mPassDrawable.getIntrinsicHeight() + 40;
+        assertEquals(expected, mInsetDrawable.getIntrinsicHeight());
 
-        expected = d.getIntrinsicHeight() + 40;
-        assertEquals(expected, insetDrawable.getIntrinsicHeight());
-
-        d = mContext.getDrawable(R.drawable.inset_color);
+        mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
         expected = -1;
-        assertEquals(expected, d.getIntrinsicHeight());
+        assertEquals(expected, mPassDrawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testGetConstantState() {
-        Drawable d = mContext.getDrawable(R.drawable.pass);
-        InsetDrawable insetDrawable = new InsetDrawable(d, 0);
-
-        ConstantState constantState = insetDrawable.getConstantState();
+        ConstantState constantState = mInsetDrawable.getConstantState();
         assertNotNull(constantState);
     }
 
+    @Test
     public void testMutate() {
         // Obtain the first instance, then mutate and modify a property held by
         // constant state. If mutate() works correctly, the property should not
@@ -358,17 +337,18 @@
     }
 
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
+        final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, densityDpi);
+            verifyPreloadDensityInner(res, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int densityDpi)
+    private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
         final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index d180261..b5c84e6 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -16,11 +16,32 @@
 
 package android.graphics.drawable.cts;
 
-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.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+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 android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -36,38 +57,57 @@
 import android.graphics.drawable.RotateDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.StateListDrawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.util.Xml;
 import android.view.Gravity;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-public class LayerDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LayerDrawableTest {
+    private Context mContext;
+    private ColorDrawable mColorDrawable;
+    private BitmapDrawable mBitmapDrawable;
 
-    @SuppressWarnings("deprecation")
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        Resources resources = mContext.getResources();
+        mColorDrawable = new ColorDrawable(Color.BLUE);
+        mBitmapDrawable = new BitmapDrawable(resources,
+                BitmapFactory.decodeResource(resources, R.drawable.icon_blue));
+    }
+
+    @Test
     public void testConstructor() {
-        Drawable bitmapDrawable = new BitmapDrawable();
-        Drawable colorDrawable  = new ColorDrawable(Color.BLUE);
-        Drawable[] array = new Drawable[] { bitmapDrawable, colorDrawable };
+        Drawable[] array = new Drawable[]{mBitmapDrawable, mColorDrawable};
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(array.length, layerDrawable.getNumberOfLayers());
-        assertSame(bitmapDrawable, layerDrawable.getDrawable(0));
-        assertSame(colorDrawable, layerDrawable.getDrawable(1));
+        assertSame(mBitmapDrawable, layerDrawable.getDrawable(0));
+        assertSame(mColorDrawable, layerDrawable.getDrawable(1));
 
         array = new Drawable[0];
         layerDrawable = new LayerDrawable(array);
         assertEquals(0, layerDrawable.getNumberOfLayers());
-
-        try {
-            new LayerDrawable(null);
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorNull() {
+        new LayerDrawable(null);
+    }
+
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
@@ -122,33 +162,31 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testFindDrawableByLayerId() {
-        Drawable bitmapDrawable = new BitmapDrawable();
-        Drawable colorDrawable  = new ColorDrawable(Color.BLUE);
-        Drawable[] array = new Drawable[] { bitmapDrawable, colorDrawable };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setId(0, 10);
         layerDrawable.setId(1, 20);
-        assertSame(bitmapDrawable, layerDrawable.findDrawableByLayerId(10));
-        assertSame(colorDrawable, layerDrawable.findDrawableByLayerId(20));
+        assertSame(mBitmapDrawable, layerDrawable.findDrawableByLayerId(10));
+        assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(20));
         assertNull(layerDrawable.findDrawableByLayerId(30));
 
         layerDrawable.setId(0, Integer.MIN_VALUE);
         layerDrawable.setId(1, Integer.MAX_VALUE);
-        assertSame(bitmapDrawable, layerDrawable.findDrawableByLayerId(Integer.MIN_VALUE));
-        assertSame(colorDrawable, layerDrawable.findDrawableByLayerId(Integer.MAX_VALUE));
+        assertSame(mBitmapDrawable, layerDrawable.findDrawableByLayerId(Integer.MIN_VALUE));
+        assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(Integer.MAX_VALUE));
 
         layerDrawable.setId(0, 10);
         layerDrawable.setId(1, 10);
-        assertSame(colorDrawable, layerDrawable.findDrawableByLayerId(10));
+        assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(10));
         assertNull(layerDrawable.findDrawableByLayerId(30));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testAccessId() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setId(0, 10);
@@ -160,35 +198,39 @@
         layerDrawable.setId(1, Integer.MAX_VALUE);
         assertEquals(Integer.MIN_VALUE, layerDrawable.getId(0));
         assertEquals(Integer.MAX_VALUE, layerDrawable.getId(1));
-
-        try {
-            layerDrawable.setId(-1, 20);
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            layerDrawable.setId(layerDrawable.getNumberOfLayers(), 20);
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            layerDrawable.getId(-1);
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            layerDrawable.getId(layerDrawable.getNumberOfLayers());
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetIdIndexTooLow() {
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
+        LayerDrawable layerDrawable = new LayerDrawable(array);
+        layerDrawable.setId(-1, 20);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetIdIndexTooHigh() {
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
+        LayerDrawable layerDrawable = new LayerDrawable(array);
+        layerDrawable.setId(layerDrawable.getNumberOfLayers(), 20);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetIdIndexTooLow() {
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
+        LayerDrawable layerDrawable = new LayerDrawable(array);
+        layerDrawable.getId(-1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetIdIndexTooHigh() {
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
+        LayerDrawable layerDrawable = new LayerDrawable(array);
+        layerDrawable.getId(layerDrawable.getNumberOfLayers());
+    }
+
+    @Test
     public void testGetNumberOfLayers() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(2, layerDrawable.getNumberOfLayers());
 
@@ -204,14 +246,12 @@
         assertEquals(0, layerDrawable.getNumberOfLayers());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testAccessDrawable() {
-        Drawable bitmapDrawable = new BitmapDrawable();
-        Drawable colorDrawable  = new ColorDrawable(Color.BLUE);
-        Drawable[] array = new Drawable[] { bitmapDrawable, colorDrawable };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
-        assertSame(bitmapDrawable, layerDrawable.getDrawable(0));
-        assertSame(colorDrawable, layerDrawable.getDrawable(1));
+        assertSame(mBitmapDrawable, layerDrawable.getDrawable(0));
+        assertSame(mColorDrawable, layerDrawable.getDrawable(1));
 
         layerDrawable.setId(0, 10);
         layerDrawable.setId(1, 20);
@@ -237,7 +277,7 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetDrawableByLayerId() {
         Drawable layer1A  = new ColorDrawable(Color.RED);
         Drawable layer2A  = new ColorDrawable(Color.BLUE);
@@ -258,12 +298,14 @@
                 5000, layerDrawable.findDrawableByLayerId(20).getLevel());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInset() {
-        MockDrawable firstLayer = new MockDrawable();
-        firstLayer.setIntrinsicSize(10, 10);
-        MockDrawable secondLayer = new MockDrawable();
-        secondLayer.setIntrinsicSize(-1, -1);
+        Drawable firstLayer = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(10).when(firstLayer).getIntrinsicWidth();
+        doReturn(10).when(firstLayer).getIntrinsicHeight();
+        Drawable secondLayer = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(-1).when(secondLayer).getIntrinsicWidth();
+        doReturn(-1).when(secondLayer).getIntrinsicHeight();
 
         Drawable[] array = new Drawable[] { firstLayer, secondLayer };
         LayerDrawable layerDrawable = new LayerDrawable(array);
@@ -294,147 +336,97 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testInvalidateDrawable() {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         layerDrawable.setCallback(cb);
         layerDrawable.invalidateDrawable(null);
-        assertTrue(cb.hasCalledInvalidate());
+        verify(cb, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(cb);
         layerDrawable.invalidateDrawable(new BitmapDrawable());
-        assertTrue(cb.hasCalledInvalidate());
+        verify(cb, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(cb);
         layerDrawable.setCallback(null);
         layerDrawable.invalidateDrawable(null);
-        assertFalse(cb.hasCalledInvalidate());
+        verify(cb, never()).invalidateDrawable(any());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testScheduleDrawable() {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         layerDrawable.setCallback(cb);
         layerDrawable.scheduleDrawable(null, null, 0);
-        assertTrue(cb.hasCalledSchedule());
+        verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
-        layerDrawable.scheduleDrawable(new BitmapDrawable(), new Runnable() {
-            @Override
-            public void run() {
-            }
-        }, 1000L);
-        assertTrue(cb.hasCalledSchedule());
+        reset(cb);
+        layerDrawable.scheduleDrawable(mBitmapDrawable, () -> {}, 1000L);
+        verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
+        reset(cb);
         layerDrawable.setCallback(null);
         layerDrawable.scheduleDrawable(null, null, 0);
-        assertFalse(cb.hasCalledSchedule());
+        verify(cb, never()).scheduleDrawable(any(), any(), anyLong());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testUnscheduleDrawable() {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        MockCallback cb = new MockCallback();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         layerDrawable.setCallback(cb);
         layerDrawable.unscheduleDrawable(null, null);
-        assertTrue(cb.hasCalledUnschedule());
+        verify(cb, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
-        layerDrawable.unscheduleDrawable(new BitmapDrawable(), new Runnable() {
-            @Override
-            public void run() {
-            }
-        });
-        assertTrue(cb.hasCalledUnschedule());
+        reset(cb);
+        layerDrawable.unscheduleDrawable(mBitmapDrawable, () -> {});
+        verify(cb, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
+        reset(cb);
         layerDrawable.setCallback(null);
         layerDrawable.unscheduleDrawable(null, null);
-        assertFalse(cb.hasCalledUnschedule());
+        verify(cb, never()).unscheduleDrawable(any(), any());
     }
 
-    private static class MockCallback implements Drawable.Callback {
-        private boolean mCalledInvalidate;
-        private boolean mCalledSchedule;
-        private boolean mCalledUnschedule;
-
-        @Override
-        public void invalidateDrawable(Drawable who) {
-            mCalledInvalidate = true;
-        }
-
-        @Override
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mCalledSchedule = true;
-        }
-
-        @Override
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mCalledUnschedule = true;
-        }
-
-        public boolean hasCalledInvalidate() {
-            return mCalledInvalidate;
-        }
-
-        public boolean hasCalledSchedule() {
-            return mCalledSchedule;
-        }
-
-        public boolean hasCalledUnschedule() {
-            return mCalledUnschedule;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-
-        public void reset() {
-            mCalledInvalidate = false;
-            mCalledSchedule = false;
-            mCalledUnschedule = false;
-        }
-    }
-
+    @Test
     public void testDraw() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.RED));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // this method will call each child's draw().
         layerDrawable.draw(new Canvas());
-        assertTrue(mockDrawable1.hasCalledDraw());
-        assertTrue(mockDrawable2.hasCalledDraw());
+        verify(mockDrawable1, times(1)).draw(any());
+        verify(mockDrawable2, times(1)).draw(any());
 
-        mockDrawable1.reset();
-        mockDrawable2.reset();
+        reset(mockDrawable1);
+        reset(mockDrawable2);
+        doNothing().when(mockDrawable1).draw(any());
+        doNothing().when(mockDrawable2).draw(any());
         layerDrawable.draw(null);
-        assertTrue(mockDrawable1.hasCalledDraw());
-        assertTrue(mockDrawable2.hasCalledDraw());
+        verify(mockDrawable1, times(1)).draw(any());
+        verify(mockDrawable2, times(1)).draw(any());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetChangingConfigurations() {
         final int superConfig = 1;
-        final int bitmapDrawableConfig = 2;
+        final int gradientDrawableConfig = 2;
         final int colorDrawableConfig = 4;
-        final int childConfig = bitmapDrawableConfig | colorDrawableConfig;
+        final int childConfig = gradientDrawableConfig | colorDrawableConfig;
 
-        BitmapDrawable bitmapDrawable = new BitmapDrawable();
-        bitmapDrawable.setChangingConfigurations(bitmapDrawableConfig);
-        ColorDrawable colorDrawable = new ColorDrawable(Color.BLUE);
-        colorDrawable.setChangingConfigurations(colorDrawableConfig);
-        Drawable[] array = new Drawable[] { bitmapDrawable, colorDrawable };
+        mBitmapDrawable.setChangingConfigurations(gradientDrawableConfig);
+        mColorDrawable.setChangingConfigurations(colorDrawableConfig);
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         assertEquals(childConfig, layerDrawable.getChangingConfigurations());
@@ -443,6 +435,7 @@
         assertEquals(superConfig | childConfig, layerDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testAccessPadding() {
         Drawable[] array = new Drawable[] { new ShapeDrawable(), new ShapeDrawable() };
         LayerDrawable layerDrawable = new LayerDrawable(array);
@@ -471,6 +464,7 @@
         assertEquals(padding0.bottom + padding1.bottom, rc.bottom);
     }
 
+    @Test
     public void testAccessPaddingMode() {
         Rect padding = new Rect();
         Drawable dr0 = new IntrinsicSizeDrawable(20, 30, new Rect(1, 2, 3, 4));
@@ -492,9 +486,9 @@
         assertEquals(new Rect(9, 8, 7, 6), padding);
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetVisible() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         assertTrue(layerDrawable.setVisible(false, true));
@@ -510,27 +504,29 @@
         assertTrue(layerDrawable.getDrawable(1).isVisible());
     }
 
+    @Test
     public void testSetDither() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setDither(true);
-        assertTrue(mockDrawable1.hasCalledSetDither());
-        assertTrue(mockDrawable2.hasCalledSetDither());
+        verify(mockDrawable1, times(1)).setDither(anyBoolean());
+        verify(mockDrawable2, times(1)).setDither(anyBoolean());
 
-        mockDrawable1.reset();
-        mockDrawable2.reset();
+        reset(mockDrawable1);
+        reset(mockDrawable2);
         layerDrawable.setDither(false);
-        assertTrue(mockDrawable1.hasCalledSetDither());
-        assertTrue(mockDrawable2.hasCalledSetDither());
+        verify(mockDrawable1, times(1)).setDither(anyBoolean());
+        verify(mockDrawable2, times(1)).setDither(anyBoolean());
     }
 
+    @Test
     public void testSetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = new ColorDrawable(Color.BLUE);
+        Drawable mockDrawable2 = new ColorDrawable(Color.GREEN);
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
@@ -540,10 +536,11 @@
         assertTrue(bounds.equals(outRect));
     }
 
+    @Test
     public void testGetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = new ColorDrawable(Color.BLUE);
+        Drawable mockDrawable2 = new ColorDrawable(Color.GREEN);
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
@@ -553,88 +550,93 @@
         assertTrue(bounds.equals(outRect));
     }
 
+    @Test
     public void testSetAlpha() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setAlpha(0);
-        assertTrue(mockDrawable1.hasCalledSetAlpha());
-        assertTrue(mockDrawable2.hasCalledSetAlpha());
+        verify(mockDrawable1, times(1)).setAlpha(anyInt());
+        verify(mockDrawable2, times(1)).setAlpha(anyInt());
 
-        mockDrawable1.reset();
-        mockDrawable2.reset();
+        reset(mockDrawable1);
+        reset(mockDrawable2);
         layerDrawable.setAlpha(Integer.MAX_VALUE);
-        assertTrue(mockDrawable1.hasCalledSetAlpha());
-        assertTrue(mockDrawable2.hasCalledSetAlpha());
+        verify(mockDrawable1, times(1)).setAlpha(anyInt());
+        verify(mockDrawable2, times(1)).setAlpha(anyInt());
     }
 
+    @Test
     public void testSetColorFilter() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setColorFilter(new ColorFilter());
-        assertTrue(mockDrawable1.hasCalledColorFilter());
-        assertTrue(mockDrawable2.hasCalledColorFilter());
+        verify(mockDrawable1, times(1)).setColorFilter(any());
+        verify(mockDrawable2, times(1)).setColorFilter(any());
 
-        mockDrawable1.reset();
-        mockDrawable2.reset();
+        reset(mockDrawable1);
+        reset(mockDrawable2);
         layerDrawable.setColorFilter(null);
-        assertTrue(mockDrawable1.hasCalledColorFilter());
-        assertTrue(mockDrawable2.hasCalledColorFilter());
+        verify(mockDrawable1, times(1)).setColorFilter(any());
+        verify(mockDrawable2, times(1)).setColorFilter(any());
     }
 
+    @Test
     public void testAccessOpacity() {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(PixelFormat.TRANSPARENT, layerDrawable.getOpacity());
 
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.GREEN));
         array = new Drawable[] { mockDrawable1, mockDrawable2 };
         layerDrawable = new LayerDrawable(array);
         assertEquals(PixelFormat.OPAQUE, layerDrawable.getOpacity());
 
         layerDrawable = new LayerDrawable(array);
-        mockDrawable2.setOpacity(PixelFormat.TRANSPARENT);
+        doReturn(PixelFormat.OPAQUE).when(mockDrawable1).getOpacity();
+        doReturn(PixelFormat.TRANSPARENT).when(mockDrawable2).getOpacity();
         assertEquals(PixelFormat.TRANSPARENT, layerDrawable.getOpacity());
 
         layerDrawable = new LayerDrawable(array);
-        mockDrawable2.setOpacity(PixelFormat.TRANSPARENT);
-        mockDrawable1.setOpacity(PixelFormat.TRANSLUCENT);
+        doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
+        doReturn(PixelFormat.TRANSPARENT).when(mockDrawable2).getOpacity();
         assertEquals(PixelFormat.TRANSLUCENT, layerDrawable.getOpacity());
 
         layerDrawable = new LayerDrawable(array);
-        mockDrawable1.setOpacity(PixelFormat.TRANSLUCENT);
-        mockDrawable2.setOpacity(PixelFormat.UNKNOWN);
+        doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
+        doReturn(PixelFormat.UNKNOWN).when(mockDrawable2).getOpacity();
         assertEquals(PixelFormat.UNKNOWN, layerDrawable.getOpacity());
 
         layerDrawable = new LayerDrawable(array);
         layerDrawable.setOpacity(PixelFormat.OPAQUE);
-        mockDrawable1.setOpacity(PixelFormat.TRANSLUCENT);
-        mockDrawable2.setOpacity(PixelFormat.UNKNOWN);
+        doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
+        doReturn(PixelFormat.UNKNOWN).when(mockDrawable2).getOpacity();
         assertEquals(PixelFormat.OPAQUE, layerDrawable.getOpacity());
 
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testIsStateful() {
         Drawable[] array = new Drawable[0];
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertFalse(layerDrawable.isStateful());
 
-        array = new Drawable[] { new BitmapDrawable(), new MockDrawable(false) };
+        array = new Drawable[] { new GradientDrawable(), new MockDrawable(false) };
         layerDrawable = new LayerDrawable(array);
         assertFalse(layerDrawable.isStateful());
 
-        array = new Drawable[] { new BitmapDrawable(), new StateListDrawable() };
+        array = new Drawable[] { new GradientDrawable(), new StateListDrawable() };
         layerDrawable = new LayerDrawable(array);
         assertTrue(layerDrawable.isStateful());
     }
 
+    @Test
     public void testSetState() {
         MockDrawable mockDrawable1 = new MockDrawable(true);
         MockDrawable mockDrawable2 = new MockDrawable(true);
@@ -672,21 +674,23 @@
         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
     }
 
+    @Test
     public void testJumpToCurrentState() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        assertFalse(mockDrawable1.hasCalledJumpToCurrentState());
-        assertFalse(mockDrawable2.hasCalledJumpToCurrentState());
+        verify(mockDrawable1, never()).jumpToCurrentState();
+        verify(mockDrawable2, never()).jumpToCurrentState();
 
         layerDrawable.jumpToCurrentState();
 
-        assertTrue(mockDrawable1.hasCalledJumpToCurrentState());
-        assertTrue(mockDrawable2.hasCalledJumpToCurrentState());
+        verify(mockDrawable1, times(1)).jumpToCurrentState();
+        verify(mockDrawable2, times(1)).jumpToCurrentState();
     }
 
+    @Test
     public void testSetLevel() {
         MockDrawable mockDrawable1 = new MockDrawable();
         MockDrawable mockDrawable2 = new MockDrawable();
@@ -724,9 +728,10 @@
         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
     }
 
+    @Test
     public void testSetBounds() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
+        Drawable mockDrawable1 = spy(new ColorDrawable(Color.GREEN));
+        Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLUE));
         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
@@ -736,8 +741,16 @@
         Rect padding2 = new Rect(21, 32, 43, 54);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
-        mockDrawable1.setPadding(padding1);
-        mockDrawable2.setPadding(padding2);
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding1);
+            return true;
+        }).when(mockDrawable1).getPadding(any());
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding2);
+            return true;
+        }).when(mockDrawable2).getPadding(any());
         layerDrawable.getPadding(new Rect());
 
         // the children's bounds before call onBoundsChange
@@ -766,23 +779,37 @@
                 mockDrawable2.getBounds().bottom);
     }
 
+    @Test
     public void testGetIntrinsicWidth() {
-        MockDrawable largeMockDrawable = new MockDrawable();
-        largeMockDrawable.setIntrinsicSize(10, 10);
-        MockDrawable smallMockDrawable = new MockDrawable();
-        smallMockDrawable.setIntrinsicSize(1, 1);
+        Drawable largeMockDrawable = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(10).when(largeMockDrawable).getIntrinsicWidth();
+        doReturn(10).when(largeMockDrawable).getIntrinsicHeight();
+        Drawable smallMockDrawable = spy(new ColorDrawable(Color.MAGENTA));
+        doReturn(1).when(smallMockDrawable).getIntrinsicWidth();
+        doReturn(1).when(smallMockDrawable).getIntrinsicHeight();
+
         Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(largeMockDrawable.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
         Rect inset2 = new Rect(2, 4, 6, 7);
-        Rect padding1 = new Rect(11, 22, 33, 44);
-        Rect padding2 = new Rect(21, 32, 43, 54);
+        final Rect padding1 = new Rect(11, 22, 33, 44);
+        final Rect padding2 = new Rect(21, 32, 43, 54);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
-        largeMockDrawable.setPadding(padding1);
-        smallMockDrawable.setPadding(padding2);
+
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding1);
+            return true;
+        }).when(largeMockDrawable).getPadding(any());
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding2);
+            return true;
+        }).when(smallMockDrawable).getPadding(any());
+
         layerDrawable.getPadding(new Rect());
         assertEquals(smallMockDrawable.getIntrinsicWidth() + inset2.left
                 + inset2.right + padding1.left + padding1.right,
@@ -795,23 +822,37 @@
                 layerDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
-        MockDrawable largeMockDrawable = new MockDrawable();
-        largeMockDrawable.setIntrinsicSize(10, 10);
-        MockDrawable smallMockDrawable = new MockDrawable();
-        smallMockDrawable.setIntrinsicSize(1, 1);
+        Drawable largeMockDrawable = spy(new ColorDrawable(Color.CYAN));
+        doReturn(10).when(largeMockDrawable).getIntrinsicWidth();
+        doReturn(10).when(largeMockDrawable).getIntrinsicHeight();
+        Drawable smallMockDrawable = spy(new ColorDrawable(Color.DKGRAY));
+        doReturn(1).when(smallMockDrawable).getIntrinsicWidth();
+        doReturn(1).when(smallMockDrawable).getIntrinsicHeight();
+
         Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         assertEquals(largeMockDrawable.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
 
         Rect inset1 = new Rect(1, 2, 3, 4);
         Rect inset2 = new Rect(2, 4, 6, 7);
-        Rect padding1 = new Rect(11, 22, 33, 44);
-        Rect padding2 = new Rect(21, 32, 43, 54);
+        final Rect padding1 = new Rect(11, 22, 33, 44);
+        final Rect padding2 = new Rect(21, 32, 43, 54);
         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
-        largeMockDrawable.setPadding(padding1);
-        smallMockDrawable.setPadding(padding2);
+
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding1);
+            return true;
+        }).when(largeMockDrawable).getPadding(any());
+        doAnswer(invocation -> {
+            Rect target = (Rect) invocation.getArguments() [0];
+            target.set(padding2);
+            return true;
+        }).when(smallMockDrawable).getPadding(any());
+
         layerDrawable.getPadding(new Rect());
         assertEquals(smallMockDrawable.getIntrinsicHeight() + inset2.top
                 + inset2.bottom + padding1.top + padding1.bottom,
@@ -824,9 +865,9 @@
                 layerDrawable.getIntrinsicHeight());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetConstantState() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         ConstantState constantState = layerDrawable.getConstantState();
         assertNotNull(constantState);
@@ -838,11 +879,11 @@
         assertEquals(1, constantState.getChangingConfigurations());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testAddLayer() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { new GradientDrawable(), new ColorDrawable(Color.BLUE) };
         LayerDrawable layerDrawable = new LayerDrawable(array);
-        BitmapDrawable newDrawable = new BitmapDrawable();
+        GradientDrawable newDrawable = new GradientDrawable();
         int index = layerDrawable.addLayer(newDrawable);
 
         final int numLayers = layerDrawable.getNumberOfLayers();
@@ -850,12 +891,11 @@
         assertEquals(newDrawable, layerDrawable.getDrawable(index));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetDrawable() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
-        final int numLayers = layerDrawable.getNumberOfLayers();
         assertEquals(array[0], layerDrawable.getDrawable(0));
         assertEquals(array[1], layerDrawable.getDrawable(1));
         try {
@@ -865,9 +905,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testFindIndexByLayerId() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setId(0, 10);
@@ -878,9 +918,9 @@
         assertEquals(-1, layerDrawable.findIndexByLayerId(30));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetDrawable() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         BitmapDrawable newBitmapDrawable = new BitmapDrawable();
         ColorDrawable newColorDrawable = new ColorDrawable(Color.GREEN);
@@ -898,45 +938,45 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLeftPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
         assertEquals(10, layerDrawable.getLeftPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetTopPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
         assertEquals(11, layerDrawable.getTopPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetRightPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
         assertEquals(20, layerDrawable.getRightPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetBottomPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
         assertEquals(21, layerDrawable.getBottomPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetStartPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
@@ -945,9 +985,9 @@
         assertEquals(10, layerDrawable.getStartPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetEndPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
@@ -956,9 +996,9 @@
         assertEquals(20, layerDrawable.getEndPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetPadding() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPadding(10, 11, 20, 21);
 
@@ -970,9 +1010,9 @@
         assertEquals(-1, layerDrawable.getEndPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetPaddingRelative() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable()};
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
         layerDrawable.setPaddingRelative(10, 11, 20, 21);
 
@@ -984,9 +1024,9 @@
         assertEquals(-1, layerDrawable.getRightPadding());
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerGravity() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerGravity(0, Gravity.CENTER);
@@ -1001,9 +1041,9 @@
         assertEquals(Gravity.NO_GRAVITY, layerDrawable.getLayerGravity(1));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerGravity() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerGravity(0, Gravity.CENTER);
@@ -1018,9 +1058,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerWidth() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerWidth(0, 100);
@@ -1035,9 +1075,9 @@
         assertEquals(200, layerDrawable.getLayerWidth(1));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerWidth() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerWidth(0, 100);
@@ -1052,9 +1092,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerHeight() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerHeight(0, 100);
@@ -1069,9 +1109,9 @@
         assertEquals(200, layerDrawable.getLayerHeight(1));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerHeight() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerHeight(0, 100);
@@ -1086,9 +1126,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerSize() {
-        Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+        Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         layerDrawable.setLayerSize(0, 100, 200);
@@ -1105,12 +1145,14 @@
         assertEquals(400, layerDrawable.getLayerHeight(1));
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetRelative() {
-        MockDrawable firstLayer = new MockDrawable();
-        firstLayer.setIntrinsicSize(10, 10);
-        MockDrawable secondLayer = new MockDrawable();
-        secondLayer.setIntrinsicSize(-1, -1);
+        Drawable firstLayer = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(10).when(firstLayer).getIntrinsicWidth();
+        doReturn(10).when(firstLayer).getIntrinsicHeight();
+        Drawable secondLayer = spy(new ColorDrawable(Color.YELLOW));
+        doReturn(-1).when(secondLayer).getIntrinsicWidth();
+        doReturn(-1).when(secondLayer).getIntrinsicHeight();
 
         Drawable[] array = new Drawable[] { firstLayer, secondLayer };
         LayerDrawable layerDrawable = new LayerDrawable(array);
@@ -1146,9 +1188,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetLeft() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1172,9 +1214,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetLeft() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1195,9 +1237,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetTop() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1221,9 +1263,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetTop() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1244,9 +1286,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetRight() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1270,9 +1312,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetRight() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1293,9 +1335,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetBottom() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1319,9 +1361,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetBottom() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1342,9 +1384,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetStart() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1368,9 +1410,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetStart() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1391,9 +1433,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testSetLayerInsetEnd() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1418,9 +1460,9 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testGetLayerInsetEnd() {
-        Drawable[] array = new Drawable[] { new BitmapDrawable() };
+        Drawable[] array = new Drawable[] { mBitmapDrawable };
         LayerDrawable layerDrawable = new LayerDrawable(array);
 
         // set inset for layer 0
@@ -1441,11 +1483,12 @@
         }
     }
 
+    @Test
     public void testChildIntrinsicSize() {
         LayerDrawable dr;
 
         // Ensure that a child with no intrinsic size correctly reports bounds.
-        dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic);
+        dr = (LayerDrawable) mContext.getDrawable(R.drawable.layer_drawable_intrinsic);
         assertEquals(-1, dr.getIntrinsicWidth());
         assertEquals(-1, dr.getIntrinsicHeight());
 
@@ -1456,7 +1499,7 @@
         assertEquals(-1, dr.getIntrinsicHeight());
 
         // Ensure mixed children report bounds correctly as well.
-        dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic_mixed);
+        dr = (LayerDrawable) mContext.getDrawable(R.drawable.layer_drawable_intrinsic_mixed);
         int width = dr.getLayerInsetLeft(0) + dr.getLayerInsetRight(0)
                 + dr.getDrawable(0).getIntrinsicWidth();
         int height = dr.getLayerInsetTop(0) + dr.getLayerInsetBottom(0)
@@ -1465,28 +1508,18 @@
         assertEquals(height, dr.getIntrinsicHeight());
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of Drawable to track calls to protected methods. This class also has empty implementations
+    // of the base abstract methods. In addition, this class also updates its padding on every
+    // change in level or state.
     private static class MockDrawable extends Drawable {
-        private boolean mCalledSetDither = false;
-        private boolean mCalledSetAlpha = false;
-        private boolean mCalledColorFilter = false;
-
         private boolean mCalledSetState = false;
         private boolean mCalledOnLevelChange = false;
         private boolean mCalledOnBoundsChange = false;
-        private boolean mCalledJumpToCurrentState = false;
-
-        private boolean mCalledDraw = false;
 
         private boolean mIsStateful = false;
 
-        private int mOpacity = PixelFormat.OPAQUE;
-
-        private int mIntrinsicWidth = -1;
-        private int mIntrinsicHeight = -1;
-
-        private boolean mDither = false;
-
-        Rect mPadding = null;
+        private Rect mPadding = null;
 
         public MockDrawable() {
             this(false);
@@ -1498,87 +1531,25 @@
 
         @Override
         public void draw(Canvas canvas) {
-            mCalledDraw = true;
-        }
-
-        public boolean hasCalledDraw() {
-            return mCalledDraw;
         }
 
         @Override
         public int getOpacity() {
-            return mOpacity;
-        }
-
-        public void setOpacity(int opacity) {
-            mOpacity = opacity;
+            return PixelFormat.OPAQUE;
         }
 
         @Override
         public void setAlpha(int alpha) {
-            mCalledSetAlpha = true;
         }
 
         @Override
         public void setColorFilter(ColorFilter cf) {
-            mCalledColorFilter = true;
-        }
-
-        @Override
-        public void setDither(boolean dither) {
-            mDither = dither;
-            mCalledSetDither = true;
-        }
-
-        public void setIntrinsicSize(int width, int height) {
-            mIntrinsicWidth = width;
-            mIntrinsicHeight = height;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return mIntrinsicWidth;
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mIntrinsicHeight;
-        }
-
-        public boolean hasCalledSetDither() {
-            return mCalledSetDither;
-        }
-
-        public boolean hasCalledSetAlpha() {
-            return mCalledSetAlpha;
-        }
-
-        public boolean hasCalledColorFilter() {
-            return mCalledColorFilter;
         }
 
         public void reset() {
-            mCalledSetDither = false;
-            mCalledSetAlpha = false;
-            mCalledColorFilter = false;
-
             mCalledSetState = false;
             mCalledOnLevelChange = false;
             mCalledOnBoundsChange = false;
-            mCalledJumpToCurrentState = false;
-
-            mCalledDraw = false;
-        }
-
-        @Override
-        public void jumpToCurrentState() {
-            super.jumpToCurrentState();
-
-            mCalledJumpToCurrentState = true;
-        }
-
-        public boolean hasCalledJumpToCurrentState() {
-            return mCalledJumpToCurrentState;
         }
 
         @Override
@@ -1634,7 +1605,7 @@
             return mCalledOnLevelChange;
         }
 
-        public void setPadding(Rect padding) {
+        private void setPadding(Rect padding) {
             if (padding == null) {
                 mPadding = null;
             } else {
@@ -1656,6 +1627,7 @@
         }
     }
 
+    @Test
     public void testMutate() {
         LayerDrawable d1 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
         LayerDrawable d2 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
@@ -1688,17 +1660,18 @@
     }
 
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
+        final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, densityDpi);
+            verifyPreloadDensityInner(res, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int densityDpi)
+    private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
         final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
index 4ef49c0..9bc423b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LevelListDrawableTest.java
@@ -16,39 +16,50 @@
 
 package android.graphics.drawable.cts;
 
-import java.io.IOException;
-
-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 android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
+import android.graphics.Color;
+import android.graphics.cts.R;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
-import android.test.InstrumentationTestCase;
+import android.graphics.drawable.LevelListDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Xml;
 
-import android.graphics.cts.R;
+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;
 
-public class LevelListDrawableTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LevelListDrawableTest {
     private MockLevelListDrawable mLevelListDrawable;
 
     private Resources mResources;
 
     private DrawableContainerState mDrawableContainerState;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
         mLevelListDrawable = new MockLevelListDrawable();
         mDrawableContainerState = (DrawableContainerState) mLevelListDrawable.getConstantState();
-        mResources = getInstrumentation().getTargetContext().getResources();
     }
 
+    @Test
     public void testLevelListDrawable() {
         new LevelListDrawable();
         // Check the values set in the constructor
@@ -56,6 +67,7 @@
         assertTrue(new MockLevelListDrawable().hasCalledOnLevelChanged());
     }
 
+    @Test
     public void testAddLevel() {
         assertEquals(0, mDrawableContainerState.getChildCount());
 
@@ -67,20 +79,23 @@
 
         // call onLevelChanged to assure that the correct drawable is selected.
         mLevelListDrawable.reset();
-        mLevelListDrawable.addLevel(Integer.MAX_VALUE, Integer.MIN_VALUE, new MockDrawable());
+        mLevelListDrawable.addLevel(Integer.MAX_VALUE, Integer.MIN_VALUE,
+                new ColorDrawable(Color.GREEN));
         assertEquals(1, mDrawableContainerState.getChildCount());
         assertTrue(mLevelListDrawable.hasCalledOnLevelChanged());
 
         mLevelListDrawable.reset();
-        mLevelListDrawable.addLevel(Integer.MIN_VALUE, Integer.MAX_VALUE, new MockDrawable());
+        mLevelListDrawable.addLevel(Integer.MIN_VALUE, Integer.MAX_VALUE,
+                new ColorDrawable(Color.RED));
         assertEquals(2, mDrawableContainerState.getChildCount());
         assertTrue(mLevelListDrawable.hasCalledOnLevelChanged());
     }
 
+    @Test
     public void testOnLevelChange() {
-        mLevelListDrawable.addLevel(0, 0, new MockDrawable());
-        mLevelListDrawable.addLevel(0, 0, new MockDrawable());
-        mLevelListDrawable.addLevel(0, 10, new MockDrawable());
+        mLevelListDrawable.addLevel(0, 0, new ColorDrawable(Color.BLUE));
+        mLevelListDrawable.addLevel(0, 0, new ColorDrawable(Color.MAGENTA));
+        mLevelListDrawable.addLevel(0, 10, new ColorDrawable(Color.YELLOW));
 
         // the method is not called if same level is set
         mLevelListDrawable.reset();
@@ -109,6 +124,13 @@
         assertNull(mLevelListDrawable.getCurrent());
     }
 
+    @Test
+    public void testInflateResources() throws XmlPullParserException, IOException {
+        getResourceParser(R.xml.level_list_correct);
+        getResourceParser(R.xml.level_list_missing_item_drawable);
+    }
+
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
 
@@ -133,47 +155,48 @@
         assertSame(mLevelListDrawable.getCurrent(), mDrawableContainerState.getChildren()[2]);
         mLevelListDrawable.setLevel(1);
         assertNull(mLevelListDrawable.getCurrent());
-
-        parser = getResourceParser(R.xml.level_list_missing_item_drawable);
-        try {
-            mLevelListDrawable.inflate(mResources, parser, Xml.asAttributeSet(parser));
-            fail("Should throw XmlPullParserException if drawable of item is missing");
-        } catch (XmlPullParserException e) {
-        }
     }
 
-    public void testInflateWithNullParameters() throws XmlPullParserException, IOException{
+    @Test(expected=XmlPullParserException.class)
+    public void testInflateMissingContent() throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResourceParser(R.xml.level_list_missing_item_drawable);
+        // Should throw XmlPullParserException if drawable of item is missing
+        mLevelListDrawable.inflate(mResources, parser, Xml.asAttributeSet(parser));
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullResources() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
-        try {
-            mLevelListDrawable.inflate(null, parser, Xml.asAttributeSet(parser));
-            fail("Should throw XmlPullParserException if resource is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mLevelListDrawable.inflate(mResources, null, Xml.asAttributeSet(parser));
-            fail("Should throw XmlPullParserException if parser is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mLevelListDrawable.inflate(mResources, parser, null);
-            fail("Should throw XmlPullParserException if AttributeSet is null");
-        } catch (NullPointerException e) {
-        }
+        // Should throw NullPointerException if resource is null
+        mLevelListDrawable.inflate(null, parser, Xml.asAttributeSet(parser));
     }
 
+
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullParser() throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
+        // Should throw NullPointerException if parser is null
+        mLevelListDrawable.inflate(mResources, null, Xml.asAttributeSet(parser));
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullAttrSet() throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
+        // Should throw NullPointerException if AttributeSet is null
+        mLevelListDrawable.inflate(mResources, parser, null);
+    }
+
+    @Test
     public void testMutate() throws InterruptedException {
-        Resources resources = getInstrumentation().getTargetContext().getResources();
         LevelListDrawable d1 =
-            (LevelListDrawable) resources.getDrawable(R.drawable.levellistdrawable);
+            (LevelListDrawable) mResources.getDrawable(R.drawable.levellistdrawable);
         LevelListDrawable d2 =
-            (LevelListDrawable) resources.getDrawable(R.drawable.levellistdrawable);
+            (LevelListDrawable) mResources.getDrawable(R.drawable.levellistdrawable);
         LevelListDrawable d3 =
-            (LevelListDrawable) resources.getDrawable(R.drawable.levellistdrawable);
+            (LevelListDrawable) mResources.getDrawable(R.drawable.levellistdrawable);
 
         // the state does not appear to be shared before calling mutate()
-        d1.addLevel(100, 200, resources.getDrawable(R.drawable.testimage));
+        d1.addLevel(100, 200, mResources.getDrawable(R.drawable.testimage));
         assertEquals(3, ((DrawableContainerState) d1.getConstantState()).getChildCount());
         assertEquals(2, ((DrawableContainerState) d2.getConstantState()).getChildCount());
         assertEquals(2, ((DrawableContainerState) d3.getConstantState()).getChildCount());
@@ -184,8 +207,7 @@
 
     private XmlResourceParser getResourceParser(int resId) throws XmlPullParserException,
             IOException {
-        XmlResourceParser parser = getInstrumentation().getTargetContext().getResources().getXml(
-                resId);
+        XmlResourceParser parser = mResources.getXml(resId);
         int type;
         while ((type = parser.next()) != XmlPullParser.START_TAG
                 && type != XmlPullParser.END_DOCUMENT) {
@@ -212,23 +234,4 @@
             return result;
         }
     }
-
-    private class MockDrawable extends Drawable {
-        @Override
-        public void draw(Canvas canvas) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
index 4b4a3bb..2760940 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
@@ -16,40 +16,55 @@
 
 package android.graphics.drawable.cts;
 
-import android.content.res.Resources.Theme;
-import android.graphics.Outline;
-import android.graphics.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 android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.NinePatch;
+import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.graphics.Bitmap.Config;
-import android.graphics.PorterDuff.Mode;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.test.InstrumentationTestCase;
+import android.graphics.drawable.NinePatchDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Xml;
 
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-public class NinePatchDrawableTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NinePatchDrawableTest {
     // A small value is actually making sure that the values are matching
     // exactly with the golden image.
     // We can increase the threshold if the Skia is drawing with some variance
@@ -66,14 +81,14 @@
 
     private Resources mResources;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mResources = getInstrumentation().getTargetContext().getResources();
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
         mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_0);
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testConstructors() {
         byte[] chunk = new byte[MIN_CHUNK_SIZE];
         chunk[MIN_CHUNK_SIZE - 1] = 1;
@@ -97,6 +112,7 @@
         }
     }
 
+    @Test
     public void testDraw() {
         Bitmap bmp = Bitmap.createBitmap(9, 9, Config.ARGB_8888);
         Canvas c = new Canvas(bmp);
@@ -105,32 +121,31 @@
 
         mNinePatchDrawable.setBounds(0, 0, 9, 9);
         mNinePatchDrawable.draw(c);
-        assertColorFillRect(bmp, 0, 0, 4, 4, Color.RED);
-        assertColorFillRect(bmp, 5, 0, 4, 4, Color.BLUE);
-        assertColorFillRect(bmp, 0, 5, 4, 4, ocean);
-        assertColorFillRect(bmp, 5, 5, 4, 4, Color.YELLOW);
-        assertColorFillRect(bmp, 4, 0, 1, 9, Color.WHITE);
-        assertColorFillRect(bmp, 0, 4, 9, 1, Color.WHITE);
+        verifyColorFillRect(bmp, 0, 0, 4, 4, Color.RED);
+        verifyColorFillRect(bmp, 5, 0, 4, 4, Color.BLUE);
+        verifyColorFillRect(bmp, 0, 5, 4, 4, ocean);
+        verifyColorFillRect(bmp, 5, 5, 4, 4, Color.YELLOW);
+        verifyColorFillRect(bmp, 4, 0, 1, 9, Color.WHITE);
+        verifyColorFillRect(bmp, 0, 4, 9, 1, Color.WHITE);
 
         bmp.eraseColor(0xff000000);
 
         mNinePatchDrawable.setBounds(0, 0, 3, 3);
         mNinePatchDrawable.draw(c);
-        assertColorFillRect(bmp, 0, 0, 1, 1, Color.RED);
-        assertColorFillRect(bmp, 2, 0, 1, 1, Color.BLUE);
-        assertColorFillRect(bmp, 0, 2, 1, 1, ocean);
-        assertColorFillRect(bmp, 2, 2, 1, 1, Color.YELLOW);
-        assertColorFillRect(bmp, 1, 0, 1, 3, Color.WHITE);
-        assertColorFillRect(bmp, 0, 1, 3, 1, Color.WHITE);
-
-        try {
-            mNinePatchDrawable.draw(null);
-            fail("The method should check whether the canvas is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        verifyColorFillRect(bmp, 0, 0, 1, 1, Color.RED);
+        verifyColorFillRect(bmp, 2, 0, 1, 1, Color.BLUE);
+        verifyColorFillRect(bmp, 0, 2, 1, 1, ocean);
+        verifyColorFillRect(bmp, 2, 2, 1, 1, Color.YELLOW);
+        verifyColorFillRect(bmp, 1, 0, 1, 3, Color.WHITE);
+        verifyColorFillRect(bmp, 0, 1, 3, 1, Color.WHITE);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawNullCanvas() {
+        mNinePatchDrawable.draw(null);
+    }
+
+    @Test
     public void testGetChangingConfigurations() {
         ConstantState constantState = mNinePatchDrawable.getConstantState();
 
@@ -153,6 +168,7 @@
         assertEquals(0xffff,  mNinePatchDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetPadding() {
         Rect r = new Rect();
         NinePatchDrawable npd = (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatch_0);
@@ -171,6 +187,7 @@
         assertTrue(r.bottom > 0);
     }
 
+    @Test
     public void testSetAlpha() {
         assertEquals(0xff, mNinePatchDrawable.getPaint().getAlpha());
 
@@ -184,10 +201,11 @@
         assertEquals(0xfe, mNinePatchDrawable.getPaint().getAlpha());
     }
 
+    @Test
     public void testSetColorFilter() {
         assertNull(mNinePatchDrawable.getPaint().getColorFilter());
 
-        MockColorFilter cf = new MockColorFilter();
+        ColorFilter cf = new ColorFilter();
         mNinePatchDrawable.setColorFilter(cf);
         assertSame(cf, mNinePatchDrawable.getPaint().getColorFilter());
 
@@ -195,6 +213,7 @@
         assertNull(mNinePatchDrawable.getPaint().getColorFilter());
     }
 
+    @Test
     public void testSetTint() {
         mNinePatchDrawable.setTint(Color.BLACK);
         mNinePatchDrawable.setTintMode(Mode.SRC_OVER);
@@ -205,6 +224,7 @@
         mNinePatchDrawable.setTintMode(null);
     }
 
+    @Test
     public void testSetDither() {
         mNinePatchDrawable.setDither(false);
         assertFalse(mNinePatchDrawable.getPaint().isDither());
@@ -213,6 +233,7 @@
         assertTrue(mNinePatchDrawable.getPaint().isDither());
     }
 
+    @Test
     public void testSetFilterBitmap() {
         mNinePatchDrawable.setFilterBitmap(false);
         assertFalse(mNinePatchDrawable.getPaint().isFilterBitmap());
@@ -221,6 +242,7 @@
         assertTrue(mNinePatchDrawable.getPaint().isFilterBitmap());
     }
 
+    @Test
     public void testIsFilterBitmap() {
         mNinePatchDrawable.setFilterBitmap(false);
         assertFalse(mNinePatchDrawable.isFilterBitmap());
@@ -234,6 +256,7 @@
                 mNinePatchDrawable.getPaint().isFilterBitmap());
     }
 
+    @Test
     public void testGetPaint() {
         Paint paint = mNinePatchDrawable.getPaint();
         assertNotNull(paint);
@@ -241,6 +264,7 @@
         assertSame(paint, mNinePatchDrawable.getPaint());
     }
 
+    @Test
     public void testGetIntrinsicWidth() {
         Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0);
         assertEquals(bmp.getWidth(), mNinePatchDrawable.getIntrinsicWidth());
@@ -252,6 +276,7 @@
         assertEquals(9, mNinePatchDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testGetMinimumWidth() {
         Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0);
         assertEquals(bmp.getWidth(), mNinePatchDrawable.getMinimumWidth());
@@ -263,6 +288,7 @@
         assertEquals(9, mNinePatchDrawable.getMinimumWidth());
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
         Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0);
         assertEquals(bmp.getHeight(), mNinePatchDrawable.getIntrinsicHeight());
@@ -274,6 +300,7 @@
         assertEquals(9, mNinePatchDrawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testGetMinimumHeight() {
         Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0);
         assertEquals(bmp.getHeight(), mNinePatchDrawable.getMinimumHeight());
@@ -287,13 +314,16 @@
 
     // Known failure: Bug 2834281 - Bitmap#hasAlpha seems to return true for
     // images without alpha
-    public void suppress_testGetOpacity() {
+    @Ignore
+    @Test
+    public void testGetOpacity() {
         assertEquals(PixelFormat.OPAQUE, mNinePatchDrawable.getOpacity());
 
         mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1);
         assertEquals(PixelFormat.TRANSLUCENT, mNinePatchDrawable.getOpacity());
     }
 
+    @Test
     public void testGetTransparentRegion() {
         // opaque image
         Region r = mNinePatchDrawable.getTransparentRegion();
@@ -314,6 +344,7 @@
         assertEquals(new Rect(1, 1, 7, 7), r.getBounds());
     }
 
+    @Test
     public void testGetConstantState() {
         assertNotNull(mNinePatchDrawable.getConstantState());
 
@@ -326,6 +357,7 @@
         assertEquals(0xff, constantState.getChangingConfigurations());
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         int sourceWidth = 80;
         int sourceHeight = 120;
@@ -357,6 +389,7 @@
         assertTrue(sourceWidth != ninePatchDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testMutate() {
         NinePatchDrawable d1 =
             (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable);
@@ -395,11 +428,11 @@
         void setTargetDensity(NinePatchDrawable dr, int density);
     }
 
-    private void testSetTargetDensityOuter(TargetDensitySetter densitySetter) {
+    private void verifySetTargetDensityOuter(TargetDensitySetter densitySetter) {
         final Resources res = mResources;
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testSetTargetDensityInner(res, DENSITY_IMAGES[0], DENSITY_VALUES, densitySetter);
+            verifySetTargetDensityInner(res, DENSITY_IMAGES[0], DENSITY_VALUES, densitySetter);
         } catch (IOException | XmlPullParserException e) {
             throw new RuntimeException(e);
         } finally {
@@ -407,7 +440,7 @@
         }
     }
 
-    private void testSetTargetDensityInner(Resources res, int sourceResId, int[] densities,
+    private void verifySetTargetDensityInner(Resources res, int sourceResId, int[] densities,
             TargetDensitySetter densitySetter) throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
 
@@ -455,53 +488,46 @@
         }
     }
 
+    @Test
     public void testSetTargetDensity() {
-        testSetTargetDensityOuter(new TargetDensitySetter() {
-            @Override
-            public void setTargetDensity(NinePatchDrawable dr, int density) {
-                dr.setTargetDensity(density);
-            }
-        });
+        verifySetTargetDensityOuter((dr, density) -> dr.setTargetDensity(density));
     }
 
+    @Test
     public void testSetTargetDensity_Canvas() {
         // This should be identical to calling setTargetDensity(int) with the
         // value returned by Canvas.getDensity().
-        testSetTargetDensityOuter(new TargetDensitySetter() {
-            @Override
-            public void setTargetDensity(NinePatchDrawable dr, int density) {
-                Canvas c = new Canvas();
-                c.setDensity(density);
-                dr.setTargetDensity(c);
-            }
+        verifySetTargetDensityOuter((dr, density) -> {
+            Canvas c = new Canvas();
+            c.setDensity(density);
+            dr.setTargetDensity(c);
         });
     }
 
+    @Test
     public void testSetTargetDensity_DisplayMetrics() {
         // This should be identical to calling setTargetDensity(int) with the
         // value of DisplayMetrics.densityDpi.
-        testSetTargetDensityOuter(new TargetDensitySetter() {
-            @Override
-            public void setTargetDensity(NinePatchDrawable dr, int density) {
-                DisplayMetrics dm = new DisplayMetrics();
-                dm.densityDpi = density;
-                dr.setTargetDensity(dm);
-            }
+        verifySetTargetDensityOuter((dr, density) -> {
+            DisplayMetrics dm = new DisplayMetrics();
+            dm.densityDpi = density;
+            dr.setTargetDensity(dm);
         });
     }
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
         final Resources res = mResources;
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, DENSITY_IMAGES[0], DENSITY_VALUES,
+            verifyPreloadDensityInner(res, DENSITY_IMAGES[0], DENSITY_VALUES,
                     DENSITY_GOLDEN_IMAGES[0]);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int sourceResId, int[] densities,
+    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities,
             int[] goldenResIds) throws XmlPullParserException, IOException {
         // Capture initial state at preload density.
         final int preloadDensityDpi = densities[0];
@@ -560,17 +586,18 @@
         return preloadedDrawable;
     }
 
+    @Test
     public void testOutlinePreloadDensity() throws XmlPullParserException, IOException {
         final Resources res = mResources;
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testOutlinePreloadDensityInner(res);
+            verifyOutlinePreloadDensityInner(res);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private static void testOutlinePreloadDensityInner(Resources res)
+    private static void verifyOutlinePreloadDensityInner(Resources res)
             throws XmlPullParserException, IOException {
         // Capture initial state at preload density.
         final int preloadDensityDpi = DENSITY_VALUES[0];
@@ -612,7 +639,7 @@
         }
     }
 
-    private void assertColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
+    private void verifyColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
         for (int i = x; i < x + w; i++) {
             for (int j = y; j < y + h; j++) {
                 assertEquals(color, bmp.getPixel(i, j));
@@ -688,7 +715,4 @@
             }
         }
     }
-
-    private class MockColorFilter extends ColorFilter {
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
index fdb8f2f..30a07f7 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/PaintDrawableTest.java
@@ -16,30 +16,50 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Rect;
+import android.graphics.cts.R;
 import android.graphics.drawable.PaintDrawable;
 import android.graphics.drawable.shapes.RoundRectShape;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 
+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;
 
-public class PaintDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PaintDrawableTest {
+    private Resources mResources;
+
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
+    }
+
+    @Test
     public void testConstructor() {
         new PaintDrawable();
         new PaintDrawable(0x0);
         new PaintDrawable(0xffffffff);
     }
 
+    @Test
     public void testSetCornerRadius() {
         PaintDrawable paintDrawable;
 
@@ -64,6 +84,7 @@
         assertNull(paintDrawable.getShape());
     }
 
+    @Test
     public void testSetCornerRadii() {
         PaintDrawable paintDrawable;
 
@@ -100,10 +121,11 @@
         assertTrue(paintDrawable.getShape() instanceof RoundRectShape);
     }
 
+    @Test
     public void testInflateTag() throws XmlPullParserException, IOException {
         // Test name is not 'corners', and default executing path will load super's method.
         XmlResourceParser parser = getParser();
-        AttributeSet attr = getAtrributeSet(parser);
+        AttributeSet attr = getAttributeSet(parser);
         assertNotNull(attr);
         gotoTag(parser, "padding");
         Rect padding = new Rect(0, 0, 10, 10);
@@ -114,20 +136,19 @@
         //If the Tagname is not 'corners',inflateTag will invoke its super's version. and the super
         // version is a operation on mPadding, in this case, it will set mPadding to null, and
         // return false by getPadding.
-        assertTrue(paintDrawable.inflateTag("padding", getContext().getResources(), parser, attr));
+        assertTrue(paintDrawable.inflateTag("padding", mResources, parser, attr));
         assertFalse(paintDrawable.getPadding(padding));
 
         // Test tag-name with ''
         parser = getParser();
-        attr = getAtrributeSet(parser);
+        attr = getAttributeSet(parser);
         assertNotNull(attr);
-        assertFalse(new MyPaintDrawable().inflateTag("", getContext().getResources(), parser,
-                attr));
+        assertFalse(new MyPaintDrawable().inflateTag("", mResources, parser, attr));
 
         // Exceptional input Tests
         try {
             // null tag name
-            new MyPaintDrawable().inflateTag(null, getContext().getResources(), parser, attr);
+            new MyPaintDrawable().inflateTag(null, mResources, parser, attr);
             fail("Normally the function would throw a NullPointerException here.");
         } catch (NullPointerException e) {
             // expected
@@ -144,15 +165,15 @@
 
         // null XmlPullParser
         parser = getParser();
-        attr = getAtrributeSet(parser);
+        attr = getAttributeSet(parser);
         assertNotNull(attr);
         gotoTag(parser, "padding");
         paintDrawable = new MyPaintDrawable();
-        assertTrue(paintDrawable.inflateTag("padding", getContext().getResources(), null, attr));
+        assertTrue(paintDrawable.inflateTag("padding", mResources, null, attr));
 
         try {
             // null AttributeSet
-            new MyPaintDrawable().inflateTag("padding", getContext().getResources(), parser, null);
+            new MyPaintDrawable().inflateTag("padding", mResources, parser, null);
             fail("Normally the function would throw a NullPointerException here.");
         } catch (NullPointerException e) {
             // expected
@@ -161,18 +182,18 @@
         assertNull(paintDrawable.getShape());
 
         parser = getParser();
-        attr = getAtrributeSet(parser);
+        attr = getAttributeSet(parser);
         assertNotNull(attr);
         gotoTag(parser, "corners");
-        assertTrue(paintDrawable.inflateTag("corners", getContext().getResources(), parser, attr));
+        assertTrue(paintDrawable.inflateTag("corners", mResources, parser, attr));
         assertNotNull(paintDrawable.getShape());
     }
 
     private XmlResourceParser getParser() {
-        return getContext().getResources().getXml(R.drawable.paintdrawable_attr);
+        return mResources.getXml(R.drawable.paintdrawable_attr);
     }
 
-    private AttributeSet getAtrributeSet(XmlResourceParser parser) throws XmlPullParserException,
+    private AttributeSet getAttributeSet(XmlResourceParser parser) throws XmlPullParserException,
             IOException {
         int type;
         // FIXME: this come from
@@ -212,7 +233,7 @@
         }
     }
 
-    private PaintDrawable getPaintDrawable(boolean hasShape) {
+    private static PaintDrawable getPaintDrawable(boolean hasShape) {
         PaintDrawable paintDrawable = new PaintDrawable();
         if (hasShape) {
             paintDrawable.setCornerRadius(1.5f);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/PictureDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/PictureDrawableTest.java
index 514f5d5..5aed95c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/PictureDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/PictureDrawableTest.java
@@ -16,6 +16,9 @@
 
 package android.graphics.drawable.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -23,14 +26,22 @@
 import android.graphics.Picture;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.PictureDrawable;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PictureDrawableTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PictureDrawableTest {
+    @Test
     public void testConstructor() {
         assertNull((new PictureDrawable(null)).getPicture());
         assertNotNull((new PictureDrawable(new Picture())).getPicture());
     }
 
+    @Test
     public void testDraw() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
 
@@ -57,6 +68,7 @@
         assertEquals(0xff0a0c0b, destBitmap.getPixel(10, 10));
     }
 
+    @Test
     public void testGetIntrinsicSize() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         // Test with null Picture object
@@ -71,16 +83,19 @@
         assertEquals(101, pictureDrawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testGetOpacity() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         assertEquals(PixelFormat.TRANSLUCENT, pictureDrawable.getOpacity());
     }
 
+    @Test
     public void testSetAlpha() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         pictureDrawable.setAlpha(0);
     }
 
+    @Test
     public void testSetColorFilter() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
 
@@ -88,16 +103,19 @@
         pictureDrawable.setColorFilter(colorFilter);
     }
 
+    @Test
     public void testSetDither() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         pictureDrawable.setDither(true);
     }
 
+    @Test
     public void testSetFilterBitmap() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         pictureDrawable.setFilterBitmap(true);
     }
 
+    @Test
     public void testAccessPicture() {
         PictureDrawable pictureDrawable = new PictureDrawable(null);
         assertNull(pictureDrawable.getPicture());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
index 2e46a09..4f6bf6d 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
@@ -16,10 +16,12 @@
 
 package android.graphics.drawable.cts;
 
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -29,16 +31,34 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.RippleDrawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Xml;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-public class RippleDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RippleDrawableTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() {
         new RippleDrawable(ColorStateList.valueOf(Color.RED), null, null);
     }
 
+    @Test
     public void testAccessRadius() {
         RippleDrawable drawable =
             new RippleDrawable(ColorStateList.valueOf(Color.RED), null, null);
@@ -47,23 +67,25 @@
         assertEquals(10, drawable.getRadius());
     }
 
+    @Test
     public void testRadiusAttr() {
         RippleDrawable drawable =
-                (RippleDrawable) getContext().getDrawable(R.drawable.rippledrawable_radius);
+                (RippleDrawable) mContext.getDrawable(R.drawable.rippledrawable_radius);
         assertEquals(10, drawable.getRadius());
     }
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
+        final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, densityDpi);
+            verifyPreloadDensityInner(res, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void testPreloadDensityInner(Resources res, int densityDpi)
+    private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
         final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
@@ -101,6 +123,7 @@
         assertEquals(initialRadius, doubleDrawable.getRadius());
     }
 
+    @Test
     public void testSetColor() {
         Drawable.Callback cb = mock(Drawable.Callback.class);
         RippleDrawable dr = new RippleDrawable(ColorStateList.valueOf(Color.RED), null, null);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
index e51edc1..98f60fa 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/RotateDrawableTest.java
@@ -16,51 +16,75 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+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 android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.RotateDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+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;
 
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
-import android.graphics.drawable.RotateDrawable;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
-
-public class RotateDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RotateDrawableTest {
+    private Resources mResources;
     private RotateDrawable mRotateDrawable;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        Resources resources = mContext.getResources();
-        mRotateDrawable = (RotateDrawable) resources.getDrawable(R.drawable.rotatedrawable);
+    @Before
+    public void setup() {
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
+        mRotateDrawable = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable);
     }
 
+    @Test
     public void testConstructor() {
         new RotateDrawable();
     }
 
+    @Test
     public void testDraw() {
         Canvas canvas = new Canvas();
         mRotateDrawable.draw(canvas);
     }
 
+    @Test
     public void testInflate() {
         RotateDrawable d;
 
-        d = (RotateDrawable) mContext.getResources().getDrawable(R.drawable.rotatedrawable_rel);
+        d = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable_rel);
         assertEquals(0.1f, d.getPivotX(), 0.01f);
         assertEquals(0.2f, d.getPivotY(), 0.01f);
         assertEquals(360.0f, d.getFromDegrees(), 0.01f);
@@ -68,7 +92,7 @@
         assertEquals(true, d.isPivotXRelative());
         assertEquals(true, d.isPivotYRelative());
 
-        d = (RotateDrawable) mContext.getResources().getDrawable(R.drawable.rotatedrawable_abs);
+        d = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable_abs);
         assertEquals(0.3f, d.getPivotX(), 0.01f);
         assertEquals(0.3f, d.getPivotY(), 0.01f);
         assertEquals(180.0f, d.getFromDegrees(), 0.01f);
@@ -77,6 +101,7 @@
         assertEquals(false, d.isPivotYRelative());
     }
 
+    @Test
     public void testSetPivot() {
         RotateDrawable d = new RotateDrawable();
         assertEquals(0.5f, d.getPivotX(), 0.01f);
@@ -97,6 +122,7 @@
         assertEquals(false, d.isPivotYRelative());
     }
 
+    @Test
     public void testSetDegrees() {
         RotateDrawable d = new RotateDrawable();
         assertEquals(0.0f, d.getFromDegrees(), 0.01f);
@@ -111,6 +137,7 @@
         assertEquals(-10.0f, d.getFromDegrees(), 0.01f);
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         assertEquals(0, mRotateDrawable.getChangingConfigurations());
 
@@ -121,6 +148,7 @@
         assertEquals(Configuration.KEYBOARD_12KEY, mRotateDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testSetAlpha() {
         mRotateDrawable.setAlpha(100);
         assertEquals(100, ((BitmapDrawable) mRotateDrawable.getDrawable()).getPaint().getAlpha());
@@ -129,6 +157,7 @@
         assertEquals(255, ((BitmapDrawable) mRotateDrawable.getDrawable()).getPaint().getAlpha());
     }
 
+    @Test
     public void testSetColorFilter() {
         ColorFilter filter = new ColorFilter();
         mRotateDrawable.setColorFilter(filter);
@@ -139,68 +168,67 @@
         assertNull(((BitmapDrawable) mRotateDrawable.getDrawable()).getPaint().getColorFilter());
     }
 
+    @Test
     public void testGetOpacity() {
         assertEquals(PixelFormat.OPAQUE, mRotateDrawable.getOpacity());
     }
 
+    @Test
     public void testInvalidateDrawable() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.pass);
-        MockCallback callback = new MockCallback();
+        Drawable drawable = mResources.getDrawable(R.drawable.pass);
+        Drawable.Callback callback = mock(Drawable.Callback.class);
 
         mRotateDrawable.setCallback(callback);
         mRotateDrawable.invalidateDrawable(null);
-        assertTrue(callback.hasCalledInvalidate());
+        verify(callback, times(1)).invalidateDrawable(any());
 
-        callback.reset();
+        reset(callback);
         mRotateDrawable.invalidateDrawable(drawable);
-        assertTrue(callback.hasCalledInvalidate());
+        verify(callback, times(1)).invalidateDrawable(any());
 
-        callback.reset();
+        reset(callback);
         mRotateDrawable.setCallback(null);
         mRotateDrawable.invalidateDrawable(drawable);
-        assertFalse(callback.hasCalledInvalidate());
+        verify(callback, never()).invalidateDrawable(any());
     }
 
+    @Test
     public void testScheduleDrawable() {
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
 
         mRotateDrawable.setCallback(callback);
         mRotateDrawable.scheduleDrawable(null, null, 0);
-        assertTrue(callback.hasCalledSchedule());
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        callback.reset();
-        mRotateDrawable.scheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        }, 1000L);
-        assertTrue(callback.hasCalledSchedule());
+        reset(callback);
+        mRotateDrawable.scheduleDrawable(new ColorDrawable(Color.RED), () -> {}, 1000L);
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        callback.reset();
+        reset(callback);
         mRotateDrawable.setCallback(null);
         mRotateDrawable.scheduleDrawable(null, null, 0);
-        assertFalse(callback.hasCalledSchedule());
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
     }
 
+    @Test
     public void testUnscheduleDrawable() {
-        MockCallback callback = new MockCallback();
+        Drawable.Callback callback = mock(Drawable.Callback.class);
 
         mRotateDrawable.setCallback(callback);
         mRotateDrawable.unscheduleDrawable(null, null);
-        assertTrue(callback.hasCalledUnschedule());
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
 
-        callback.reset();
-        mRotateDrawable.unscheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        });
-        assertTrue(callback.hasCalledUnschedule());
+        reset(callback);
+        mRotateDrawable.unscheduleDrawable(new ColorDrawable(Color.RED), () -> {});
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
 
-        callback.reset();
+        reset(callback);
         mRotateDrawable.setCallback(null);
         mRotateDrawable.unscheduleDrawable(null, null);
-        assertFalse(callback.hasCalledUnschedule());
+        verify(callback, never()).unscheduleDrawable(any(), any());
     }
 
+    @Test
     public void testGetPadding() {
         Rect rect = new Rect();
         assertFalse(mRotateDrawable.getPadding(rect));
@@ -210,6 +238,7 @@
         assertEquals(0, rect.bottom);
     }
 
+    @Test
     public void testSetVisible() {
         assertTrue(mRotateDrawable.isVisible());
 
@@ -223,50 +252,45 @@
         assertTrue(mRotateDrawable.isVisible());
     }
 
+    @Test
     public void testIsStateful() {
         assertFalse(mRotateDrawable.isStateful());
     }
 
-    public void testMethods() {
-        // implementation details, do not test.
-    }
-
+    @Test
     public void testGetIntrinsicWidthAndHeight() throws XmlPullParserException, IOException {
         // testimage is set in res/drawable/rotatedrawable.xml
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.testimage);
+        Drawable drawable = mResources.getDrawable(R.drawable.testimage);
         assertEquals(drawable.getIntrinsicWidth(), mRotateDrawable.getIntrinsicWidth());
         assertEquals(drawable.getIntrinsicHeight(), mRotateDrawable.getIntrinsicHeight());
 
         RotateDrawable rotateDrawable = new RotateDrawable();
-        Resources r = mContext.getResources();
-        XmlPullParser parser = r.getXml(R.drawable.rotatedrawable);
+        XmlPullParser parser = mResources.getXml(R.drawable.rotatedrawable);
         while (parser.next() != XmlPullParser.START_TAG) {
             // ignore event, just seek to first tag
         }
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        rotateDrawable.inflate(r, parser, attrs);
+        rotateDrawable.inflate(mResources, parser, attrs);
         assertEquals(drawable.getIntrinsicWidth(), rotateDrawable.getIntrinsicWidth());
         assertEquals(drawable.getIntrinsicHeight(), rotateDrawable.getIntrinsicHeight());
-
-        try {
-            mRotateDrawable.inflate(null, null, null);
-            fail("did not throw NullPointerException when parameters are null.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testInflateNull() throws XmlPullParserException, IOException {
+        mRotateDrawable.inflate(null, null, null);
+    }
+
+    @Test
     public void testGetConstantState() {
         ConstantState state = mRotateDrawable.getConstantState();
         assertNotNull(state);
     }
 
+    @Test
     public void testMutate() {
-        Resources resources = mContext.getResources();
-
-        RotateDrawable d1 = (RotateDrawable) resources.getDrawable(R.drawable.rotatedrawable);
-        RotateDrawable d2 = (RotateDrawable) resources.getDrawable(R.drawable.rotatedrawable);
-        RotateDrawable d3 = (RotateDrawable) resources.getDrawable(R.drawable.rotatedrawable);
+        RotateDrawable d1 = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable);
+        RotateDrawable d2 = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable);
+        RotateDrawable d3 = (RotateDrawable) mResources.getDrawable(R.drawable.rotatedrawable);
 
         d1.setAlpha(100);
         assertEquals(100, ((BitmapDrawable) d1.getDrawable()).getPaint().getAlpha());
@@ -284,44 +308,4 @@
         assertEquals(50, ((BitmapDrawable) d2.getDrawable()).getPaint().getAlpha());
         assertEquals(50, ((BitmapDrawable) d3.getDrawable()).getPaint().getAlpha());
     }
-
-    private static class MockCallback implements Drawable.Callback {
-        private boolean mCalledInvalidate;
-        private boolean mCalledSchedule;
-        private boolean mCalledUnschedule;
-
-        public void invalidateDrawable(Drawable who) {
-            mCalledInvalidate = true;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mCalledSchedule = true;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mCalledUnschedule = true;
-        }
-
-        public boolean hasCalledInvalidate() {
-            return mCalledInvalidate;
-        }
-
-        public boolean hasCalledSchedule() {
-            return mCalledSchedule;
-        }
-
-        public boolean hasCalledUnschedule() {
-            return mCalledUnschedule;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-
-        public void reset() {
-            mCalledInvalidate = false;
-            mCalledSchedule = false;
-            mCalledUnschedule = false;
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
index e1f37b3..977850b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
@@ -16,33 +16,65 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doNothing;
+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 android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.ScaleDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.StateSet;
+import android.view.Gravity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.Arrays;
 
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ClipDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Drawable.ConstantState;
-import android.graphics.drawable.ScaleDrawable;
-import android.os.Debug;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.StateSet;
-import android.view.Gravity;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ScaleDrawableTest {
+    private Context mContext;
 
-public class ScaleDrawableTest extends AndroidTestCase {
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
         Drawable d = new BitmapDrawable();
         ScaleDrawable scaleDrawable = new ScaleDrawable(d, Gravity.CENTER, 100, 200);
@@ -52,134 +84,94 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testInvalidateDrawable() {
         ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(),
                 Gravity.CENTER, 100, 200);
 
-        MockCallback cb = new MockCallback();
-        scaleDrawable.setCallback(cb);
+        Drawable.Callback callback = mock(Drawable.Callback.class);
+        scaleDrawable.setCallback(callback);
         scaleDrawable.invalidateDrawable(null);
-        assertTrue(cb.hasCalledInvalidate());
+        verify(callback, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(callback);
         scaleDrawable.invalidateDrawable(new BitmapDrawable());
-        assertTrue(cb.hasCalledInvalidate());
+        verify(callback, times(1)).invalidateDrawable(any());
 
-        cb.reset();
+        reset(callback);
         scaleDrawable.setCallback(null);
         scaleDrawable.invalidateDrawable(null);
-        assertFalse(cb.hasCalledInvalidate());
+        verify(callback, never()).invalidateDrawable(any());
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testScheduleDrawable() {
         ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(),
                 Gravity.CENTER, 100, 200);
 
-        MockCallback cb = new MockCallback();
-        scaleDrawable.setCallback(cb);
+        Drawable.Callback callback = mock(Drawable.Callback.class);
+        scaleDrawable.setCallback(callback);
         scaleDrawable.scheduleDrawable(null, null, 0);
-        assertTrue(cb.hasCalledSchedule());
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
-        scaleDrawable.scheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        }, 1000L);
-        assertTrue(cb.hasCalledSchedule());
+        reset(callback);
+        scaleDrawable.scheduleDrawable(new BitmapDrawable(), () -> {}, 1000L);
+        verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong());
 
-        cb.reset();
+        reset(callback);
         scaleDrawable.setCallback(null);
         scaleDrawable.scheduleDrawable(null, null, 0);
-        assertFalse(cb.hasCalledSchedule());
+        verify(callback, never()).scheduleDrawable(any(), any(), anyLong());
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testUnscheduleDrawable() {
         ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(),
                 Gravity.CENTER, 100, 200);
 
-        MockCallback cb = new MockCallback();
-        scaleDrawable.setCallback(cb);
+        Drawable.Callback callback = mock(Drawable.Callback.class);
+        scaleDrawable.setCallback(callback);
         scaleDrawable.unscheduleDrawable(null, null);
-        assertTrue(cb.hasCalledUnschedule());
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
-        scaleDrawable.unscheduleDrawable(new BitmapDrawable(), new Runnable() {
-            public void run() {
-            }
-        });
-        assertTrue(cb.hasCalledUnschedule());
+        reset(callback);
+        scaleDrawable.unscheduleDrawable(new BitmapDrawable(), () -> {});
+        verify(callback, times(1)).unscheduleDrawable(any(), any());
 
-        cb.reset();
+        reset(callback);
         scaleDrawable.setCallback(null);
         scaleDrawable.unscheduleDrawable(null, null);
-        assertFalse(cb.hasCalledUnschedule());
+        verify(callback, never()).unscheduleDrawable(any(), any());
     }
 
-    private static class MockCallback implements Drawable.Callback {
-        private boolean mCalledInvalidate;
-        private boolean mCalledSchedule;
-        private boolean mCalledUnschedule;
-
-        public void invalidateDrawable(Drawable who) {
-            mCalledInvalidate = true;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-            mCalledSchedule = true;
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-            mCalledUnschedule = true;
-        }
-
-        public boolean hasCalledInvalidate() {
-            return mCalledInvalidate;
-        }
-
-        public boolean hasCalledSchedule() {
-            return mCalledSchedule;
-        }
-
-        public boolean hasCalledUnschedule() {
-            return mCalledUnschedule;
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-
-        public void reset() {
-            mCalledInvalidate = false;
-            mCalledSchedule = false;
-            mCalledUnschedule = false;
-        }
-    }
-
+    @Test
     public void testDraw() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         scaleDrawable.draw(new Canvas());
-        assertFalse(mockDrawable.hasCalledDraw());
+        verify(mockDrawable, never()).draw(any());
 
         // this method will call the contained drawable's draw method
         // if the contained drawable's level doesn't equal 0.
         mockDrawable.setLevel(1);
         scaleDrawable.draw(new Canvas());
-        assertTrue(mockDrawable.hasCalledDraw());
+        verify(mockDrawable, times(1)).draw(any());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
+        doNothing().when(mockDrawable).draw(any());
         scaleDrawable.draw(null);
-        assertTrue(mockDrawable.hasCalledDraw());
+        verify(mockDrawable, times(1)).draw(any());
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         final int SUPER_CONFIG = 1;
         final int CONTAINED_DRAWABLE_CONFIG = 2;
 
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = new ColorDrawable(Color.YELLOW);
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         assertEquals(0, scaleDrawable.getChangingConfigurations());
@@ -192,91 +184,99 @@
                 scaleDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetPadding() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's getPadding method.
         scaleDrawable.getPadding(new Rect());
-        assertTrue(mockDrawable.hasCalledGetPadding());
-
-        // input null as param
-        try {
-            scaleDrawable.getPadding(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        verify(mockDrawable, times(1)).getPadding(any());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetPaddingNull() {
+        Drawable mockDrawable = new ColorDrawable(Color.YELLOW);
+        ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
+
+        scaleDrawable.getPadding(null);
+    }
+
+    @Test
     public void testSetVisible() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
         assertTrue(scaleDrawable.isVisible());
 
         assertTrue(scaleDrawable.setVisible(false, false));
         assertFalse(scaleDrawable.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, atLeastOnce()).setVisible(anyBoolean(), anyBoolean());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         assertFalse(scaleDrawable.setVisible(false, false));
         assertFalse(scaleDrawable.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         assertTrue(scaleDrawable.setVisible(true, false));
         assertTrue(scaleDrawable.isVisible());
-        assertTrue(mockDrawable.hasCalledSetVisible());
+        verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean());
     }
 
+    @Test
     public void testSetAlpha() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's setAlpha method.
         scaleDrawable.setAlpha(100);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         scaleDrawable.setAlpha(Integer.MAX_VALUE);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         scaleDrawable.setAlpha(-1);
-        assertTrue(mockDrawable.hasCalledSetAlpha());
+        verify(mockDrawable, times(1)).setAlpha(anyInt());
     }
 
+    @Test
     public void testSetColorFilter() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's setColorFilter method.
         scaleDrawable.setColorFilter(new ColorFilter());
-        assertTrue(mockDrawable.hasCalledSetColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(any());
 
-        mockDrawable.reset();
+        reset(mockDrawable);
         scaleDrawable.setColorFilter(null);
-        assertTrue(mockDrawable.hasCalledSetColorFilter());
+        verify(mockDrawable, times(1)).setColorFilter(any());
     }
 
+    @Test
     public void testGetOpacity() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // This method will call contained drawable's getOpacity method.
         scaleDrawable.setLevel(1);
         scaleDrawable.getOpacity();
-        assertTrue(mockDrawable.hasCalledGetOpacity());
+        verify(mockDrawable, times(1)).getOpacity();
     }
 
+    @Test
     public void testIsStateful() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's isStateful method.
         scaleDrawable.isStateful();
-        assertTrue(mockDrawable.hasCalledIsStateful());
+        verify(mockDrawable, times(1)).isStateful();
     }
 
+    @Test
     public void testOnStateChange() {
         Drawable d = new MockDrawable();
         MockScaleDrawable scaleDrawable = new MockScaleDrawable(d, Gravity.CENTER, 100, 200);
@@ -297,6 +297,7 @@
         // expected, no Exception thrown out, test success
     }
 
+    @Test
     public void testInitialLevel() throws XmlPullParserException, IOException {
         ScaleDrawable dr = new ScaleDrawable(null, Gravity.CENTER, 1, 1);
         Resources res = mContext.getResources();
@@ -320,6 +321,7 @@
         assertEquals(5000, clone.getLevel());
     }
 
+    @Test
     public void testOnLevelChange() {
         MockDrawable mockDrawable = new MockDrawable();
         MockScaleDrawable mockScaleDrawable = new MockScaleDrawable(
@@ -336,8 +338,9 @@
         assertTrue(mockScaleDrawable.hasCalledOnBoundsChange());
     }
 
+    @Test
     public void testOnBoundsChange() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = new ColorDrawable(Color.YELLOW);
         float scaleWidth = 0.3f;
         float scaleHeight = 0.3f;
         MockScaleDrawable mockScaleDrawable = new MockScaleDrawable(
@@ -393,25 +396,28 @@
         assertEquals(bounds.bottom, mockDrawable.getBounds().bottom);
     }
 
+    @Test
     public void testGetIntrinsicWidth() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's getIntrinsicWidth method.
         scaleDrawable.getIntrinsicWidth();
-        assertTrue(mockDrawable.hasCalledGetIntrinsicWidth());
+        verify(mockDrawable, times(1)).getIntrinsicWidth();
     }
 
+    @Test
     public void testGetIntrinsicHeight() {
-        MockDrawable mockDrawable = new MockDrawable();
+        Drawable mockDrawable = spy(new ColorDrawable(Color.RED));
         ScaleDrawable scaleDrawable = new ScaleDrawable(mockDrawable, Gravity.CENTER, 100, 200);
 
         // this method will call contained drawable's getIntrinsicHeight method.
         scaleDrawable.getIntrinsicHeight();
-        assertTrue(mockDrawable.hasCalledGetIntrinsicHeight());
+        verify(mockDrawable, times(1)).getIntrinsicHeight();
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testGetConstantState() {
         ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(),
                 Gravity.CENTER, 100, 200);
@@ -427,6 +433,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         ScaleDrawable scaleDrawable = new ScaleDrawable(new BitmapDrawable(),
                 Gravity.RIGHT, 100, 200);
@@ -466,6 +473,7 @@
         }
     }
 
+    @Test
     public void testMutate() {
         ScaleDrawable d1 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable);
         ScaleDrawable d2 = (ScaleDrawable) mContext.getDrawable(R.drawable.scaledrawable);
@@ -488,75 +496,27 @@
         assertEquals(50, ((BitmapDrawable) d3.getDrawable()).getPaint().getAlpha());
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of Drawable to track calls to protected methods. This class also has empty implementations
+    // of the base abstract methods.
     private static class MockDrawable extends Drawable {
-        private boolean mCalledDraw = false;
-        private boolean mCalledGetPadding = false;
-        private boolean mCalledSetVisible = false;
-        private boolean mCalledSetAlpha = false;
-        private boolean mCalledGetOpacity = false;
-        private boolean mCalledSetColorFilter = false;
-        private boolean mCalledIsStateful = false;
-        private boolean mCalledGetIntrinsicWidth = false;
-        private boolean mCalledGetIntrinsicHeight = false;
-        private boolean mCalledSetState = false;
         private boolean mCalledOnLevelChange = false;
 
         @Override
         public void draw(Canvas canvas) {
-            mCalledDraw = true;
         }
 
         @Override
         public int getOpacity() {
-            mCalledGetOpacity = true;
             return 0;
         }
 
         @Override
         public void setAlpha(int alpha) {
-            mCalledSetAlpha = true;
         }
 
         @Override
         public void setColorFilter(ColorFilter cf) {
-            mCalledSetColorFilter = true;
-        }
-
-        @Override
-        public boolean getPadding(Rect padding) {
-            mCalledGetPadding = true;
-            return super.getPadding(padding);
-        }
-
-        @Override
-        public boolean setVisible(boolean visible, boolean restart) {
-            mCalledSetVisible = true;
-            return super.setVisible(visible, restart);
-        }
-
-        @Override
-        public boolean isStateful() {
-            mCalledIsStateful = true;
-            return super.isStateful();
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            mCalledGetIntrinsicWidth = true;
-            return super.getIntrinsicWidth();
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            mCalledGetIntrinsicHeight = true;
-            return super.getIntrinsicHeight();
-
-        }
-
-        @Override
-        public boolean setState(final int[] stateSet) {
-            mCalledSetState = true;
-            return super.setState(stateSet);
         }
 
         @Override
@@ -565,61 +525,11 @@
             return super.onLevelChange(level);
         }
 
-        public boolean hasCalledDraw() {
-            return mCalledDraw;
-        }
-
-        public boolean hasCalledGetPadding() {
-            return mCalledGetPadding;
-        }
-
-        public boolean hasCalledSetVisible() {
-            return mCalledSetVisible;
-        }
-
-        public boolean hasCalledSetAlpha() {
-            return mCalledSetAlpha;
-        }
-
-        public boolean hasCalledGetOpacity() {
-            return mCalledGetOpacity;
-        }
-
-        public boolean hasCalledSetColorFilter() {
-            return mCalledSetColorFilter;
-        }
-
-        public boolean hasCalledIsStateful() {
-            return mCalledIsStateful;
-        }
-
-        public boolean hasCalledGetIntrinsicWidth() {
-            return mCalledGetIntrinsicWidth;
-        }
-
-        public boolean hasCalledGetIntrinsicHeight() {
-            return mCalledGetIntrinsicHeight;
-        }
-
-        public boolean hasCalledSetState() {
-            return mCalledSetState;
-        }
-
         public boolean hasCalledOnLevelChange() {
             return mCalledOnLevelChange;
         }
 
         public void reset() {
-            mCalledDraw = false;
-            mCalledGetPadding = false;
-            mCalledSetVisible = false;
-            mCalledSetAlpha = false;
-            mCalledGetOpacity = false;
-            mCalledSetColorFilter = false;
-            mCalledIsStateful = false;
-            mCalledGetIntrinsicWidth = false;
-            mCalledGetIntrinsicHeight = false;
-            mCalledSetState = false;
             mCalledOnLevelChange = false;
         }
     }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 1449bad..35185dd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -16,6 +16,18 @@
 
 package android.graphics.drawable.cts;
 
+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.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -25,23 +37,29 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.Shader;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.ShapeDrawable.ShaderFactory;
 import android.graphics.drawable.shapes.RectShape;
 import android.graphics.drawable.shapes.Shape;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 
-import android.graphics.cts.R;
-
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
-public class ShapeDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShapeDrawableTest {
+    @Test
     public void testConstructors() {
         new ShapeDrawable();
 
@@ -50,16 +68,14 @@
         new ShapeDrawable(new RectShape());
     }
 
+    @Test(expected=NullPointerException.class)
     public void testDraw() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
 
-        try {
-            shapeDrawable.draw(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        shapeDrawable.draw(null);
     }
 
+    @Test
     public void testGetChangingConfigurations() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertEquals(0, shapeDrawable.getChangingConfigurations());
@@ -79,6 +95,7 @@
         assertEquals(3, shapeDrawable.getChangingConfigurations());
     }
 
+    @Test
     public void testGetConstantState() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
 
@@ -88,6 +105,7 @@
         assertEquals(1, constantState.getChangingConfigurations());
     }
 
+    @Test
     public void testAccessIntrinsicHeight() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertEquals(0, shapeDrawable.getIntrinsicHeight());
@@ -102,6 +120,7 @@
         assertEquals(Integer.MAX_VALUE, shapeDrawable.getIntrinsicHeight());
     }
 
+    @Test
     public void testAccessIntrinsicWidth() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertEquals(0, shapeDrawable.getIntrinsicWidth());
@@ -116,6 +135,7 @@
         assertEquals(Integer.MAX_VALUE, shapeDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testGetOpacity() {
         ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape());
         assertEquals(PixelFormat.TRANSLUCENT, shapeDrawable.getOpacity());
@@ -131,6 +151,7 @@
         assertEquals(PixelFormat.TRANSLUCENT, shapeDrawable.getOpacity());
     }
 
+    @Test
     public void testAccessPadding() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         Rect padding = new Rect();
@@ -167,14 +188,15 @@
         assertEquals(0, padding.top);
         assertEquals(0, padding.right);
         assertEquals(0, padding.bottom);
-
-        try {
-            shapeDrawable.getPadding(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test
+    public void testGetPaddingNull() {
+        ShapeDrawable shapeDrawable = new ShapeDrawable();
+        shapeDrawable.getPadding(null);
+    }
+
+    @Test
     public void testGetPaint() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertNotNull(shapeDrawable.getPaint());
@@ -182,6 +204,7 @@
                 | Paint.EMBEDDED_BITMAP_TEXT_FLAG, shapeDrawable.getPaint().getFlags());
     }
 
+    @Test
     public void testAccessShaderFactory() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertNull(shapeDrawable.getShaderFactory());
@@ -200,6 +223,7 @@
         }
     }
 
+    @Test
     public void testAccessShape() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         assertNull(shapeDrawable.getShape());
@@ -212,8 +236,9 @@
         assertNull(shapeDrawable.getShape());
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
-        final Resources res = mContext.getResources();
+        final Resources res = InstrumentationRegistry.getTargetContext().getResources();
 
         XmlPullParser parser = res.getXml(R.drawable.shapedrawable_test);
         while (parser.next() != XmlPullParser.START_TAG) {
@@ -235,11 +260,9 @@
         assertTrue(shapeDrawable.extendedAttrsSet);
     }
 
-    public void testOnBoundsChange() {
-        // implementation details, do not test.
-    }
-
-    private class MockShapeDrawable extends ShapeDrawable {
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of StateListDrawable to track calls to protected inflateTag method.
+    public class MockShapeDrawable extends ShapeDrawable {
         public boolean inflateTagCalled;
         public boolean extendedAttrsSet;
 
@@ -266,36 +289,30 @@
         }
     }
 
+    @Test
     public void testOnDraw() {
+        Shape mockShape = spy(new MockShape());
+        MockShapeDrawable shapeDrawable = new MockShapeDrawable(mockShape);
+        verify(mockShape, never()).draw(any(), any());
+        shapeDrawable.onDraw(mockShape, new Canvas(), new Paint());
+        verify(mockShape, times(1)).draw(any(), any());
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testOnDrawNull() {
         MockShape mockShape = new MockShape();
         MockShapeDrawable shapeDrawable = new MockShapeDrawable(mockShape);
-        assertFalse(mockShape.hasDrawCalled());
-        shapeDrawable.onDraw(mockShape, new Canvas(), new Paint());
-        assertTrue(mockShape.hasDrawCalled());
 
-        try {
-            shapeDrawable.onDraw(null, null, new Paint());
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        shapeDrawable.onDraw(null, null, new Paint());
     }
 
     private static class MockShape extends Shape {
-        private boolean mDrawCalled = false;
-
-        public boolean hasDrawCalled() {
-            return mDrawCalled;
-        }
-
-        public void reset() {
-            mDrawCalled = false;
-        }
-
+        @Override
         public void draw(Canvas canvas, Paint paint) {
-            mDrawCalled = true;
         }
     }
 
+    @Test
     public void testSetAlpha() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
         shapeDrawable.setAlpha(0);
@@ -304,6 +321,7 @@
         shapeDrawable.setAlpha(256);
     }
 
+    @Test
     public void testSetColorFilter() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
 
@@ -315,6 +333,7 @@
         assertNull(shapeDrawable.getPaint().getColorFilter());
     }
 
+    @Test
     public void testSetTint() {
         final ShapeDrawable d = new ShapeDrawable(new RectShape());
         d.setTint(Color.BLACK);
@@ -322,6 +341,7 @@
         assertEquals("Shape is tinted", Color.BLACK, DrawableTestUtils.getPixel(d, 0, 0));
     }
 
+    @Test
     public void testSetDither() {
         ShapeDrawable shapeDrawable = new ShapeDrawable();
 
@@ -331,8 +351,4 @@
         shapeDrawable.setDither(false);
         assertFalse(shapeDrawable.getPaint().isDither());
     }
-
-    public void testMutate() {
-        // How to load a ShapeDrawable from resources.
-    }
 }
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..7b170ed 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
@@ -16,11 +16,31 @@
 
 package android.graphics.drawable.cts;
 
-import junit.framework.TestCase;
-import android.graphics.drawable.ShapeDrawable;
+import static org.junit.Assert.assertNull;
 
-public class ShapeDrawable_ShaderFactoryTest extends TestCase {
+import android.graphics.Shader;
+import android.graphics.drawable.ShapeDrawable.ShaderFactory;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShapeDrawable_ShaderFactoryTest {
+    @Test
     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/StateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
index 2194a00..fb3445e 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
@@ -16,46 +16,59 @@
 
 package android.graphics.drawable.cts;
 
-import java.io.IOException;
+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 org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.R.attr;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
+import android.graphics.Color;
+import android.graphics.cts.R;
 import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.graphics.drawable.StateListDrawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
-import android.test.InstrumentationTestCase;
-import android.util.DisplayMetrics;
+import android.graphics.drawable.StateListDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.StateSet;
 import android.util.Xml;
 
-import android.graphics.cts.R;
+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;
 
-public class StateListDrawableTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StateListDrawableTest {
     private MockStateListDrawable mMockDrawable;
+
     private StateListDrawable mDrawable;
 
     private Resources mResources;
 
     private DrawableContainerState mDrawableContainerState;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        // While the two fields point to the same object, the second one is there to
+        // workaround the bug in CTS coverage tool that is not recognizing calls on
+        // subclasses.
         mDrawable = mMockDrawable = new MockStateListDrawable();
         mDrawableContainerState = (DrawableContainerState) mMockDrawable.getConstantState();
-        mResources = getInstrumentation().getTargetContext().getResources();
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
     }
 
+    @Test
     public void testStateListDrawable() {
         new StateListDrawable();
         // Check the values set in the constructor
@@ -63,46 +76,49 @@
         assertTrue(new MockStateListDrawable().hasCalledOnStateChanged());
     }
 
+    @Test
     public void testAddState() {
-        // Workaround for CTS coverage not recognizing calls on subclasses.
-        StateListDrawable dr = mMockDrawable;
-
         assertEquals(0, mDrawableContainerState.getChildCount());
 
         // nothing happens if drawable is null
         mMockDrawable.reset();
-        dr.addState(StateSet.WILD_CARD, null);
+        mDrawable.addState(StateSet.WILD_CARD, null);
         assertEquals(0, mDrawableContainerState.getChildCount());
         assertFalse(mMockDrawable.hasCalledOnStateChanged());
 
         // call onLevelChanged to assure that the correct drawable is selected.
         mMockDrawable.reset();
-        dr.addState(StateSet.WILD_CARD, new MockDrawable());
+        mDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(Color.YELLOW));
         assertEquals(1, mDrawableContainerState.getChildCount());
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
 
         mMockDrawable.reset();
-        dr.addState(new int[] { attr.state_focused, - attr.state_selected }, new MockDrawable());
+        mDrawable.addState(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected },
+                new ColorDrawable(Color.YELLOW));
         assertEquals(2, mDrawableContainerState.getChildCount());
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
 
         // call onLevelChanged will not throw NPE here because the first drawable with wild card
         // state is matched first. There is no chance that other drawables will be matched.
         mMockDrawable.reset();
-        dr.addState(null, new MockDrawable());
+        mDrawable.addState(null, new ColorDrawable(Color.YELLOW));
         assertEquals(3, mDrawableContainerState.getChildCount());
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
     }
 
+    @Test
     public void testIsStateful() {
         assertTrue(new StateListDrawable().isStateful());
     }
 
+    @Test
     public void testOnStateChange() {
-        mMockDrawable.addState(new int[] { attr.state_focused, - attr.state_selected },
-                new MockDrawable());
-        mMockDrawable.addState(StateSet.WILD_CARD, new MockDrawable());
-        mMockDrawable.addState(StateSet.WILD_CARD, new MockDrawable());
+        mMockDrawable.addState(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected },
+                new ColorDrawable(Color.YELLOW));
+        mMockDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(Color.YELLOW));
+        mMockDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(Color.YELLOW));
 
         // the method is not called if same state is set
         mMockDrawable.reset();
@@ -111,7 +127,8 @@
 
         // the method is called if different state is set
         mMockDrawable.reset();
-        mMockDrawable.setState(new int[] { attr.state_focused, - attr.state_selected });
+        mMockDrawable.setState(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected });
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
 
         mMockDrawable.reset();
@@ -119,10 +136,11 @@
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
 
         // check that correct drawable is selected.
-        mMockDrawable.onStateChange(new int[] { attr.state_focused, - attr.state_selected });
+        mMockDrawable.onStateChange(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected });
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[0]);
 
-        assertFalse(mMockDrawable.onStateChange(new int[] { attr.state_focused }));
+        assertFalse(mMockDrawable.onStateChange(new int[] { android.R.attr.state_focused }));
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[0]);
 
         assertTrue(mMockDrawable.onStateChange(StateSet.WILD_CARD));
@@ -133,20 +151,24 @@
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[1]);
     }
 
+    @Test
     public void testOnStateChangeWithWildCardAtFirst() {
-        mMockDrawable.addState(StateSet.WILD_CARD, new MockDrawable());
-        mMockDrawable.addState(new int[] { attr.state_focused, - attr.state_selected },
-                new MockDrawable());
+        mMockDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(Color.YELLOW));
+        mMockDrawable.addState(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected },
+                new ColorDrawable(Color.YELLOW));
 
         // matches the first wild card although the second one is more accurate
-        mMockDrawable.onStateChange(new int[] { attr.state_focused, - attr.state_selected });
+        mMockDrawable.onStateChange(
+                new int[] { android.R.attr.state_focused, - android.R.attr.state_selected });
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[0]);
     }
 
+    @Test
     public void testOnStateChangeWithNullStateSet() {
         assertEquals(0, mDrawableContainerState.getChildCount());
         try {
-            mMockDrawable.addState(null, new MockDrawable());
+            mMockDrawable.addState(null, new ColorDrawable(Color.YELLOW));
             fail("Should throw NullPointerException.");
         } catch (NullPointerException e) {
         }
@@ -159,26 +181,28 @@
         }
     }
 
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        runPreloadDensityTestForDrawable(R.drawable.state_list_density, false);
+        verifyPreloadDensityTestForDrawable(R.drawable.state_list_density, false);
     }
 
+    @Test
     public void testPreloadDensityConstantSize() throws XmlPullParserException, IOException {
-        runPreloadDensityTestForDrawable(R.drawable.state_list_density_constant_size, true);
+        verifyPreloadDensityTestForDrawable(R.drawable.state_list_density_constant_size, true);
     }
 
-    private void runPreloadDensityTestForDrawable(int drawableResId, boolean isConstantSize)
+    private void verifyPreloadDensityTestForDrawable(int drawableResId, boolean isConstantSize)
             throws XmlPullParserException, IOException {
         final Resources res = mResources;
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            runPreloadDensityTestForDrawableInner(res, densityDpi, drawableResId, isConstantSize);
+            verifyPreloadDensityTestForDrawableInner(res, densityDpi, drawableResId, isConstantSize);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void runPreloadDensityTestForDrawableInner(Resources res, int densityDpi,
+    private void verifyPreloadDensityTestForDrawableInner(Resources res, int densityDpi,
             int drawableResId, boolean isConstantSize) throws XmlPullParserException, IOException {
         // Capture initial state at default density.
         final XmlResourceParser parser = getResourceParser(drawableResId);
@@ -229,6 +253,7 @@
         assertEquals(origWidth1, origDrawable.getIntrinsicWidth());
     }
 
+    @Test
     public void testInflate() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.selector_correct);
 
@@ -243,7 +268,8 @@
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
         assertEquals(2, mDrawableContainerState.getChildCount());
         // check the android:state_* by calling setState
-        mMockDrawable.setState(new int[]{ attr.state_focused, - attr.state_pressed });
+        mMockDrawable.setState(
+                new int[]{ android.R.attr.state_focused, - android.R.attr.state_pressed });
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[0]);
         mMockDrawable.setState(StateSet.WILD_CARD);
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[1]);
@@ -265,7 +291,8 @@
         //assertNotNull(mDrawableContainerState.getConstantPadding());
         assertTrue(mMockDrawable.hasCalledOnStateChanged());
         assertEquals(1, mDrawableContainerState.getChildCount());
-        mMockDrawable.setState(new int[]{ - attr.state_pressed, attr.state_focused });
+        mMockDrawable.setState(
+                new int[]{ - android.R.attr.state_pressed, android.R.attr.state_focused });
         assertSame(mMockDrawable.getCurrent(), mDrawableContainerState.getChildren()[0]);
         mMockDrawable.setState(StateSet.WILD_CARD);
         assertNull(mMockDrawable.getCurrent());
@@ -278,27 +305,28 @@
         }
     }
 
-    public void testInflateWithNullParameters() throws XmlPullParserException, IOException{
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullResources() throws XmlPullParserException, IOException {
         XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
-        try {
-            mMockDrawable.inflate(null, parser, Xml.asAttributeSet(parser));
-            fail("Should throw XmlPullParserException if resource is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mMockDrawable.inflate(mResources, null, Xml.asAttributeSet(parser));
-            fail("Should throw XmlPullParserException if parser is null");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            mMockDrawable.inflate(mResources, parser, null);
-            fail("Should throw XmlPullParserException if AttributeSet is null");
-        } catch (NullPointerException e) {
-        }
+        // Should throw NullPointerException if resource is null
+        mMockDrawable.inflate(null, parser, Xml.asAttributeSet(parser));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullParser() throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
+        // Should throw NullPointerException if parser is null
+        mMockDrawable.inflate(mResources, null, Xml.asAttributeSet(parser));
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testInflateWithNullAttrSet() throws XmlPullParserException, IOException {
+        XmlResourceParser parser = getResourceParser(R.xml.level_list_correct);
+        // Should throw NullPointerException if AttributeSet is null
+        mMockDrawable.inflate(mResources, parser, null);
+    }
+
+    @Test
     public void testMutate() {
         StateListDrawable d1 =
             (StateListDrawable) mResources.getDrawable(R.drawable.statelistdrawable);
@@ -321,8 +349,7 @@
 
     private XmlResourceParser getResourceParser(int resId) throws XmlPullParserException,
             IOException {
-        XmlResourceParser parser = getInstrumentation().getTargetContext().getResources().getXml(
-                resId);
+        XmlResourceParser parser = mResources.getXml(resId);
         int type;
         while ((type = parser.next()) != XmlPullParser.START_TAG
                 && type != XmlPullParser.END_DOCUMENT) {
@@ -331,6 +358,8 @@
         return parser;
     }
 
+    // Since Mockito can't mock or spy on protected methods, we have a custom extension
+    // of StateListDrawable to track calls to protected onStateChange method.
     private class MockStateListDrawable extends StateListDrawable {
         private boolean mHasCalledOnStateChanged;
 
@@ -349,23 +378,4 @@
             return result;
         }
     }
-
-    private class MockDrawable extends Drawable {
-        @Override
-        public void draw(Canvas canvas) {
-        }
-
-        @Override
-        public int getOpacity() {
-            return 0;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-        }
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
index 7c6fe7c..1a3f774 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ThemedDrawableTest.java
@@ -16,31 +16,40 @@
 
 package android.graphics.drawable.cts;
 
-import android.annotation.TargetApi;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Shader.TileMode;
-import android.graphics.drawable.Drawable;
+import android.graphics.cts.R;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.NinePatchDrawable;
 import android.graphics.drawable.RippleDrawable;
-import android.os.Debug;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Gravity;
 
-import android.graphics.cts.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ThemedDrawableTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ThemedDrawableTest {
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         // Workaround for ContextImpl.setTheme() being broken.
         final Theme theme = mContext.getResources().newTheme();
         theme.applyStyle(R.style.Theme_ThemedDrawableTest, true);
@@ -48,19 +57,20 @@
         ctxTheme.setTo(theme);
     }
 
-    @Override
+    @Before
     public void testAndroidTestCaseSetupProperly() {
         final TypedArray t = mContext.obtainStyledAttributes(new int[]{R.attr.themeType});
         assertTrue("Theme was applied correctly", t.getInt(0, -1) == 0);
     }
 
+    @Test
     public void testBitmapDrawable() {
         BitmapDrawable d = (BitmapDrawable) mContext.getDrawable(R.drawable.bitmapdrawable_theme);
 
-        internalTestBitmapDrawable(d);
+        verifyBitmapDrawable(d);
     }
 
-    private void internalTestBitmapDrawable(BitmapDrawable d) {
+    private void verifyBitmapDrawable(BitmapDrawable d) {
         assertEquals(true, d.hasAntiAlias());
         assertEquals(true, d.isAutoMirrored());
         // assertEquals(true, d.hasDither());
@@ -72,12 +82,14 @@
         assertEquals(TileMode.MIRROR, d.getTileModeY());
     }
 
+    @Test
     public void testColorDrawable() {
         ColorDrawable d = (ColorDrawable) mContext.getDrawable(R.drawable.colordrawable_theme);
 
         assertEquals(Color.BLACK, d.getColor());
     }
 
+    @Test
     public void testGradientDrawable() {
         GradientDrawable d = (GradientDrawable) mContext.getDrawable(
                 R.drawable.gradientdrawable_theme);
@@ -122,19 +134,21 @@
         // assertEquals(1.0, d.getStrokeDashGap());
     }
 
+    @Test
     public void testNinePatchDrawable() {
         NinePatchDrawable d = (NinePatchDrawable) mContext.getDrawable(
                 R.drawable.ninepatchdrawable_theme);
 
-        internalTestNinePatchDrawable(d);
+        verifyNinePatchDrawable(d);
     }
 
-    private void internalTestNinePatchDrawable(NinePatchDrawable d) {
+    private void verifyNinePatchDrawable(NinePatchDrawable d) {
         assertEquals(true, d.isAutoMirrored());
         // assertEquals(true, d.hasDither());
         // assertNotNull(d.getNinePatch());
     }
 
+    @Test
     public void testRippleDrawable() {
         RippleDrawable d = (RippleDrawable) mContext.getDrawable(
                 R.drawable.rippledrawable_theme);
@@ -142,6 +156,7 @@
         // assertEquals(Color.BLACK, d.getColor());
     }
 
+    @Test
     public void testLayerDrawable() {
         LayerDrawable d = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable_theme);
 
@@ -150,14 +165,9 @@
         assertEquals(true, d.isAutoMirrored());
 
         BitmapDrawable bitmapDrawable  = (BitmapDrawable) d.getDrawable(0);
-        assertEquals(d, bitmapDrawable.getCallback());
-        internalTestBitmapDrawable(bitmapDrawable);
+        verifyBitmapDrawable(bitmapDrawable);
 
         NinePatchDrawable ninePatchDrawable = (NinePatchDrawable) d.getDrawable(1);
-        assertEquals(d, ninePatchDrawable.getCallback());
-        internalTestNinePatchDrawable(ninePatchDrawable);
-
-        Drawable themeDrawable = (Drawable) d.getDrawable(2);
-        assertEquals(d, themeDrawable.getCallback());
+        verifyNinePatchDrawable(ninePatchDrawable);
     }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
index c0ef1be..4bb37c3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java
@@ -16,150 +16,165 @@
 
 package android.graphics.drawable.cts;
 
-import android.graphics.cts.R;
+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.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.times;
+import static org.mockito.Mockito.verify;
 
-import android.content.res.Resources;
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.cts.R;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class TransitionDrawableTest extends InstrumentationTestCase {
-    private static final int COLOR1 = 0xff0000ff;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private static final int COLOR0 = 0xffff0000;
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TransitionDrawableTest {
+    private static final int COLOR1 = Color.BLUE;
+
+    private static final int COLOR0 = Color.RED;
 
     private static final int CANVAS_WIDTH = 10;
 
     private static final int CANVAS_HEIGHT = 10;
 
+    private Context mContext;
     private TransitionDrawable mTransitionDrawable;
-
     private Bitmap mBitmap;
-
     private Canvas mCanvas;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTransitionDrawable = (TransitionDrawable) getInstrumentation().getTargetContext()
-                .getResources().getDrawable(R.drawable.transition_test);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mTransitionDrawable = (TransitionDrawable) mContext.getDrawable(R.drawable.transition_test);
         mTransitionDrawable.setBounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
 
         mBitmap = Bitmap.createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT, Config.ARGB_8888);
         mCanvas = new Canvas(mBitmap);
     }
 
+    @Test
     public void testConstructor() {
-        Resources resources = getInstrumentation().getTargetContext().getResources();
         Drawable[] drawables = new Drawable[] {
-                resources.getDrawable(R.drawable.testimage),
-                resources.getDrawable(R.drawable.levellistdrawable)
+                mContext.getDrawable(R.drawable.testimage),
+                mContext.getDrawable(R.drawable.levellistdrawable)
         };
         new TransitionDrawable(drawables);
     }
 
+    @Test
     public void testStartTransition() {
-        MockCallBack cb = new MockCallBack();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         mTransitionDrawable.setCallback(cb);
 
         // start when there is no transition
-        cb.reset();
         mTransitionDrawable.startTransition(2000);
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransition(COLOR0, COLOR1, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransition(COLOR0, COLOR1, 2000);
 
         // start when there is a transition in progress
         makeTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.startTransition(2000);
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransition(COLOR0, COLOR1, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransition(COLOR0, COLOR1, 2000);
 
         // start when there is a reverse transition in progress
         makeReverseTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.startTransition(2000);
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransition(COLOR0, COLOR1, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransition(COLOR0, COLOR1, 2000);
 
         // should not accept negative duration
         mTransitionDrawable.startTransition(-1);
     }
 
+    @Test
     public void testResetTransition() {
-        MockCallBack cb = new MockCallBack();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         mTransitionDrawable.setCallback(cb);
 
         // reset when there is no transition
-        cb.reset();
         mTransitionDrawable.resetTransition();
-        assertTrue(cb.hasCalledInvalidateDrawable());
+        verify(cb, times(1)).invalidateDrawable(any());
 
         // reset when there is a transition in progress
         makeTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.resetTransition();
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransitionStart(COLOR0);
-        assertTransitionEnd(COLOR0, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransitionStart(COLOR0);
+        verifyTransitionEnd(COLOR0, 2000);
 
         // reset when there is a reverse transition in progress
         makeReverseTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.resetTransition();
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransitionStart(COLOR0);
-        assertTransitionEnd(COLOR0, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransitionStart(COLOR0);
+        verifyTransitionEnd(COLOR0, 2000);
     }
 
+    @Test
     public void testReverseTransition() {
-        MockCallBack cb = new MockCallBack();
+        Drawable.Callback cb = mock(Drawable.Callback.class);
         mTransitionDrawable.setCallback(cb);
 
         // reverse when there is no transition
-        cb.reset();
         mTransitionDrawable.reverseTransition(2000);
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransition(COLOR0, COLOR1, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransition(COLOR0, COLOR1, 2000);
 
         // reverse after the other transition ends
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.reverseTransition(2000);
-        assertTrue(cb.hasCalledInvalidateDrawable());
-        assertTransition(COLOR1, COLOR0, 2000);
+        verify(cb, times(1)).invalidateDrawable(any());
+        verifyTransition(COLOR1, COLOR0, 2000);
 
         // reverse when there is a transition in progress
         makeTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.reverseTransition(20000);
-        assertFalse(cb.hasCalledInvalidateDrawable());
+        verify(cb, never()).invalidateDrawable(any());
         int colorFrom = mBitmap.getPixel(0, 0);
-        assertTransition(colorFrom, COLOR0, 1500);
+        verifyTransition(colorFrom, COLOR0, 1500);
 
         // reverse when there is a reverse transition in progress
         makeReverseTransitionInProgress(2000, 1000);
-        cb.reset();
+        reset(cb);
         mTransitionDrawable.reverseTransition(20000);
-        assertFalse(cb.hasCalledInvalidateDrawable());
+        verify(cb, never()).invalidateDrawable(any());
         colorFrom = mBitmap.getPixel(0, 0);
-        assertTransition(colorFrom, COLOR1, 1500);
+        verifyTransition(colorFrom, COLOR1, 1500);
 
         // should not accept negative duration
         mTransitionDrawable.reverseTransition(-1);
     }
 
-    public void testDrawWithNUllCanvas() {
-        try {
-            mTransitionDrawable.draw(null);
-            fail("The method should check whether the canvas is null.");
-        } catch (NullPointerException e) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testDrawWithNullCanvas() {
+        mTransitionDrawable.draw(null);
     }
 
     //  This boolean takes effect when the drawable is drawn and the effect can not be tested.
+    @Test
     public void testAccessCrossFadeEnabled() {
         assertFalse(mTransitionDrawable.isCrossFadeEnabled());
 
@@ -170,30 +185,30 @@
         assertFalse(mTransitionDrawable.isCrossFadeEnabled());
     }
 
-    private void assertTransition(int colorFrom, int colorTo, long delay) {
-        assertTransitionStart(colorFrom);
-        assertTransitionInProgress(colorFrom, colorTo, delay / 2);
-        assertTransitionEnd(colorTo, delay);
+    private void verifyTransition(int colorFrom, int colorTo, long delay) {
+        verifyTransitionStart(colorFrom);
+        verifyTransitionInProgress(colorFrom, colorTo, delay / 2);
+        verifyTransitionEnd(colorTo, delay);
     }
 
-    private void assertTransitionStart(int colorFrom) {
-        mBitmap.eraseColor(0x00000000);
+    private void verifyTransitionStart(int colorFrom) {
+        mBitmap.eraseColor(Color.TRANSPARENT);
         mTransitionDrawable.draw(mCanvas);
-        assertColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
+        verifyColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
     }
 
-    private void assertTransitionInProgress(int colorFrom, int colorTo, long delay) {
+    private void verifyTransitionInProgress(int colorFrom, int colorTo, long delay) {
         drawAfterDelaySync(delay);
-        assertColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
-        assertColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
+        verifyColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
+        verifyColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
     }
 
-    private void assertTransitionEnd(int colorTo, long delay) {
+    private void verifyTransitionEnd(int colorTo, long delay) {
         drawAfterDelaySync(delay);
-        assertColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
+        verifyColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
     }
 
-    private void assertColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
+    private void verifyColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
         for (int i = x; i < x + w; i++) {
             for (int j = y; j < y + h; j++) {
                 assertEquals(color, bmp.getPixel(i, j));
@@ -201,7 +216,7 @@
         }
     }
 
-    private void assertColorNotFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
+    private void verifyColorNotFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
         for (int i = x; i < x + w; i++) {
             for (int j = y; j < y + h; j++) {
                 assertTrue(color != bmp.getPixel(i, j));
@@ -212,25 +227,23 @@
     private void makeReverseTransitionInProgress(int duration, int delay) {
         mTransitionDrawable.resetTransition();
         mTransitionDrawable.startTransition(2000);
-        assertTransition(COLOR0, COLOR1, 2000);
+        verifyTransition(COLOR0, COLOR1, 2000);
         mTransitionDrawable.reverseTransition(duration);
-        assertTransitionStart(COLOR1);
-        assertTransitionInProgress(COLOR1, COLOR0, delay);
+        verifyTransitionStart(COLOR1);
+        verifyTransitionInProgress(COLOR1, COLOR0, delay);
     }
 
     private void makeTransitionInProgress(int duration, int delay) {
         mTransitionDrawable.resetTransition();
         mTransitionDrawable.startTransition(duration);
-        assertTransitionStart(COLOR0);
-        assertTransitionInProgress(COLOR0, COLOR1, delay);
+        verifyTransitionStart(COLOR0);
+        verifyTransitionInProgress(COLOR0, COLOR1, delay);
     }
 
     private void drawAfterDelaySync(long delay) {
-        Thread t = new Thread(new Runnable() {
-            public void run() {
-                mBitmap.eraseColor(0x00000000);
-                mTransitionDrawable.draw(mCanvas);
-            }
+        Thread t = new Thread(() -> {
+            mBitmap.eraseColor(Color.TRANSPARENT);
+            mTransitionDrawable.draw(mCanvas);
         });
         try {
             Thread.sleep(delay);
@@ -241,29 +254,4 @@
             fail(e.getMessage());
         }
     }
-
-    private class MockCallBack implements Drawable.Callback {
-        private boolean mHasCalledInvalidateDrawable;
-
-        public boolean hasCalledInvalidateDrawable() {
-            return mHasCalledInvalidateDrawable;
-        }
-        public void reset() {
-            mHasCalledInvalidateDrawable = false;
-        }
-
-        public void invalidateDrawable(Drawable who) {
-            mHasCalledInvalidateDrawable = true;
-        }
-
-        public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        }
-
-        public void unscheduleDrawable(Drawable who, Runnable what) {
-        }
-
-        public int getResolvedLayoutDirection(Drawable who) {
-            return 0;
-        }
-    }
 }
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..61d5e08 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -16,8 +16,8 @@
 
 package android.graphics.drawable.cts;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -32,18 +32,26 @@
 import android.graphics.cts.R;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.VectorDrawable;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
 
+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.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-public class VectorDrawableTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class VectorDrawableTest {
     private static final String LOGTAG = "VectorDrawableTest";
 
     // Separate the test assets into different groups such that we could isolate the issue faster.
@@ -93,6 +101,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 +118,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[] {
@@ -185,38 +195,42 @@
     private Bitmap mBitmap;
     private Canvas mCanvas;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         final int width = IMAGE_WIDTH;
         final int height = IMAGE_HEIGHT;
 
         mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         mCanvas = new Canvas(mBitmap);
-        mResources = mContext.getResources();
+        mResources = InstrumentationRegistry.getTargetContext().getResources();
     }
 
     @MediumTest
+    @Test
     public void testBasicVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(BASIC_ICON_RES_IDS, BASIC_GOLDEN_IMAGES, null);
     }
 
     @MediumTest
+    @Test
     public void testLMVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(L_M_ICON_RES_IDS, L_M_GOLDEN_IMAGES, null);
     }
 
     @MediumTest
+    @Test
     public void testNVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(N_ICON_RES_IDS, N_GOLDEN_IMAGES, null);
     }
 
     @MediumTest
+    @Test
     public void testVectorDrawableGradient() throws XmlPullParserException, IOException {
         verifyVectorDrawables(GRADIENT_ICON_RES_IDS, GRADIENT_GOLDEN_IMAGES, null);
     }
 
     @MediumTest
+    @Test
     public void testColorStateList() throws XmlPullParserException, IOException {
         for (int i = 0; i < STATEFUL_STATE_SETS.length; i++) {
             verifyVectorDrawables(
@@ -319,12 +333,11 @@
             return "";
         }
 
-        final Resources res = getContext().getResources();
         final StringBuilder builder = new StringBuilder();
         for (int i = 0; i < stateSet.length; i++) {
             builder.append('_');
 
-            final String state = res.getResourceName(stateSet[i]);
+            final String state = mResources.getResourceName(stateSet[i]);
             final int stateIndex = state.indexOf("state_");
             if (stateIndex >= 0) {
                 builder.append(state.substring(stateIndex + 6));
@@ -337,6 +350,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetChangingConfigurations() {
         VectorDrawable vectorDrawable = new VectorDrawable();
         ConstantState constantState = vectorDrawable.getConstantState();
@@ -361,6 +375,7 @@
     }
 
     @SmallTest
+    @Test
     public void testGetConstantState() {
         VectorDrawable vectorDrawable = new VectorDrawable();
         ConstantState constantState = vectorDrawable.getConstantState();
@@ -374,12 +389,12 @@
     }
 
     @SmallTest
+    @Test
     public void testMutate() {
-        Resources resources = mContext.getResources();
         // d1 and d2 will be mutated, while d3 will not.
-        VectorDrawable d1 = (VectorDrawable) resources.getDrawable(R.drawable.vector_icon_create);
-        VectorDrawable d2 = (VectorDrawable) resources.getDrawable(R.drawable.vector_icon_create);
-        VectorDrawable d3 = (VectorDrawable) resources.getDrawable(R.drawable.vector_icon_create);
+        VectorDrawable d1 = (VectorDrawable) mResources.getDrawable(R.drawable.vector_icon_create);
+        VectorDrawable d2 = (VectorDrawable) mResources.getDrawable(R.drawable.vector_icon_create);
+        VectorDrawable d3 = (VectorDrawable) mResources.getDrawable(R.drawable.vector_icon_create);
         int originalAlpha = d2.getAlpha();
 
         d1.setAlpha(0x80);
@@ -407,6 +422,7 @@
     }
 
     @SmallTest
+    @Test
     public void testColorFilter() {
         PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, Mode.SRC_IN);
         VectorDrawable vectorDrawable = new VectorDrawable();
@@ -416,17 +432,18 @@
     }
 
     @SmallTest
+    @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final Resources res = getContext().getResources();
-        final int densityDpi = res.getConfiguration().densityDpi;
+        final int densityDpi = mResources.getConfiguration().densityDpi;
         try {
-            testPreloadDensityInner(res, densityDpi);
+            verifyPreloadDensityInner(mResources, densityDpi);
         } finally {
-            DrawableTestUtils.setResourcesDensity(res, densityDpi);
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
         }
     }
 
     @SmallTest
+    @Test
     public void testGetOpacity () throws XmlPullParserException, IOException {
         VectorDrawable vectorDrawable = new VectorDrawable();
 
@@ -440,7 +457,7 @@
                 vectorDrawable.getOpacity());
     }
 
-    private void testPreloadDensityInner(Resources res, int densityDpi)
+    private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
         final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ArcShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ArcShapeTest.java
index 78db7a9..aa3a19c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ArcShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ArcShapeTest.java
@@ -16,7 +16,8 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -25,9 +26,15 @@
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.drawable.shapes.ArcShape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class ArcShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArcShapeTest {
     private static final int TEST_WIDTH  = 100;
     private static final int TEST_HEIGHT = 200;
 
@@ -36,7 +43,7 @@
 
     private static final int TOLERANCE = 4; // tolerance in pixels
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         new ArcShape(1f, 5f);
 
@@ -45,7 +52,7 @@
         new ArcShape(-1f, -1f);
     }
 
-    @SmallTest
+    @Test
     public void testDraw() {
         // draw completely.
         ArcShape arcShape = new ArcShape(0.0f, 360.0f);
@@ -75,7 +82,7 @@
         assertEquals((double)SQUARE / 2 / Math.sqrt(2), count, TOLERANCE);
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Outline outline = new Outline();
         ArcShape shape;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/OvalShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/OvalShapeTest.java
index 6ecf37a..19977ee 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/OvalShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/OvalShapeTest.java
@@ -16,7 +16,9 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -26,9 +28,15 @@
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.graphics.drawable.shapes.OvalShape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class OvalShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class OvalShapeTest {
     private static final int TEST_WIDTH  = 100;
     private static final int TEST_HEIGHT = 200;
 
@@ -37,10 +45,12 @@
 
     private static final int TOLERANCE = 4; // tolerance in pixels
 
+    @Test
     public void testConstructor() {
         new OvalShape();
     }
 
+    @Test
     public void testDraw() {
         OvalShape ovalShape = new OvalShape();
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
@@ -68,7 +78,7 @@
         assertEquals((double)SQUARE / Math.sqrt(2), count, TOLERANCE);
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Outline outline = new Outline();
         Rect rect = new Rect();
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/PathShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/PathShapeTest.java
index b833d61..b7335e3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/PathShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/PathShapeTest.java
@@ -16,7 +16,9 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -26,15 +28,21 @@
 import android.graphics.Paint.Style;
 import android.graphics.Path;
 import android.graphics.drawable.shapes.PathShape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class PathShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PathShapeTest {
     private static final int TEST_COLOR_1 = 0xFF00FF00;
     private static final int TEST_COLOR_2 = 0xFFFF0000;
 
     private static final int TOLERANCE = 4;
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         new PathShape(new Path(), 1f, 5f);
 
@@ -43,7 +51,7 @@
         new PathShape(null, 0f, 0f);
     }
 
-    @SmallTest
+    @Test
     public void testDraw() {
         final int SHAPE_SIZE = 200;
 
@@ -90,20 +98,20 @@
         assertEquals(25, diagonal, TOLERANCE);
     }
 
-    @SmallTest
+    @Test
     public void testClone() throws CloneNotSupportedException {
         PathShape pathShape = new PathShape(new Path(), 1f, 5f);
         pathShape.resize(100f, 200f);
         PathShape clonedShape = pathShape.clone();
-        assertEquals(100f, pathShape.getWidth());
-        assertEquals(200f, pathShape.getHeight());
+        assertEquals(100f, pathShape.getWidth(), 0.0f);
+        assertEquals(200f, pathShape.getHeight(), 0.0f);
 
         assertNotSame(pathShape, clonedShape);
-        assertEquals(pathShape.getWidth(), clonedShape.getWidth());
-        assertEquals(pathShape.getHeight(), clonedShape.getHeight());
+        assertEquals(pathShape.getWidth(), clonedShape.getWidth(), 0.0f);
+        assertEquals(pathShape.getHeight(), clonedShape.getHeight(), 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Outline outline = new Outline();
         PathShape shape;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RectShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RectShapeTest.java
index 136770b..4cd6e15 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RectShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RectShapeTest.java
@@ -16,7 +16,10 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -27,20 +30,27 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.shapes.RectShape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RectShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RectShapeTest {
     private static final int TEST_WIDTH  = 100;
     private static final int TEST_HEIGHT = 200;
 
     private static final int TEST_COLOR_1 = 0xFF00FF00;
     private static final int TEST_COLOR_2 = 0xFFFF0000;
 
+    @Test
     public void testConstructor() {
         new RectShape();
     }
 
-    private void assertDrawSuccessfully(Bitmap bitmap, int width, int height, int color) {
+    private void verifyDrawSuccessfully(Bitmap bitmap, int width, int height, int color) {
         for (int i = 0; i < width; i++) {
             for (int j = 0; j < height; j++) {
                 assertEquals(color, bitmap.getPixel(i, j));
@@ -48,7 +58,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testDraw() {
         RectShape rectShape = new RectShape();
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
@@ -59,45 +69,45 @@
         rectShape.resize(TEST_WIDTH, TEST_HEIGHT);
 
         rectShape.draw(canvas, paint);
-        assertDrawSuccessfully(bitmap, TEST_WIDTH, TEST_HEIGHT, TEST_COLOR_1);
+        verifyDrawSuccessfully(bitmap, TEST_WIDTH, TEST_HEIGHT, TEST_COLOR_1);
 
         paint.setColor(TEST_COLOR_2);
         rectShape.draw(canvas, paint);
-        assertDrawSuccessfully(bitmap, TEST_WIDTH, TEST_HEIGHT, TEST_COLOR_2);
+        verifyDrawSuccessfully(bitmap, TEST_WIDTH, TEST_HEIGHT, TEST_COLOR_2);
     }
 
-    @SmallTest
+    @Test
     public void testClone() throws CloneNotSupportedException {
         RectShape rectShape = new RectShape();
         rectShape.resize(100f, 200f);
         RectShape clonedShape = rectShape.clone();
-        assertEquals(100f, rectShape.getWidth());
-        assertEquals(200f, rectShape.getHeight());
+        assertEquals(100f, rectShape.getWidth(), 0.0f);
+        assertEquals(200f, rectShape.getHeight(), 0.0f);
 
         assertNotSame(rectShape, clonedShape);
-        assertEquals(rectShape.getWidth(), clonedShape.getWidth());
-        assertEquals(rectShape.getHeight(), clonedShape.getHeight());
+        assertEquals(rectShape.getWidth(), clonedShape.getWidth(), 0.0f);
+        assertEquals(rectShape.getHeight(), clonedShape.getHeight(), 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testRect() {
         MyRectShape mockRectShape = new MyRectShape();
         RectShape rectShape = mockRectShape;
         RectF rect = mockRectShape.myRect();
-        assertEquals(0.0f, rect.left);
-        assertEquals(0.0f, rect.top);
-        assertEquals(0.0f, rect.right);
-        assertEquals(0.0f, rect.bottom);
+        assertEquals(0.0f, rect.left, 0.0f);
+        assertEquals(0.0f, rect.top, 0.0f);
+        assertEquals(0.0f, rect.right, 0.0f);
+        assertEquals(0.0f, rect.bottom, 0.0f);
 
         rectShape.resize(TEST_WIDTH, TEST_HEIGHT);
         rect = mockRectShape.myRect();
-        assertEquals(0.0f, rect.left);
-        assertEquals(0.0f, rect.top);
-        assertEquals((float) TEST_WIDTH, rect.right);
-        assertEquals((float) TEST_HEIGHT, rect.bottom);
+        assertEquals(0.0f, rect.left, 0.0f);
+        assertEquals(0.0f, rect.top, 0.0f);
+        assertEquals((float) TEST_WIDTH, rect.right, 0.0f);
+        assertEquals((float) TEST_HEIGHT, rect.bottom, 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Outline outline = new Outline();
         Rect rect = new Rect();
@@ -113,7 +123,7 @@
         shape.resize(100, 100);
         shape.getOutline(outline);
         assertFalse(outline.isEmpty());
-        assertEquals(0.0f, outline.getRadius());
+        assertEquals(0.0f, outline.getRadius(), 0.0f);
         assertTrue(outline.getRect(rect));
         assertEquals(0, rect.left);
         assertEquals(0, rect.top);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RoundRectShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RoundRectShapeTest.java
index 5209535..0db0f5d 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RoundRectShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/RoundRectShapeTest.java
@@ -16,7 +16,10 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -27,15 +30,22 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.shapes.RoundRectShape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class RoundRectShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RoundRectShapeTest {
     private static final int TEST_WIDTH  = 100;
     private static final int TEST_HEIGHT = 200;
 
     private static final int TEST_COLOR_1 = 0xFF00FF00;
     private static final int TEST_COLOR_2 = 0xFFFF0000;
 
+    @Test
     public void testConstructor() {
         new RoundRectShape(new float[8], new RectF(), new float[8]);
 
@@ -45,21 +55,21 @@
 
         new RoundRectShape(new float[8], new RectF(), null);
 
-        try {
-            new RoundRectShape(new float[7], new RectF(), new float[8]);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
-
         new RoundRectShape(null, new RectF(), new float[8]);
-
-        try {
-            new RoundRectShape(new float[8], new RectF(), new float[7]);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testConstructorTooFewOuterRadii() {
+        new RoundRectShape(new float[7], new RectF(), new float[8]);
+    }
+
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testConstructorTooFewInnerRadii() {
+        new RoundRectShape(new float[8], new RectF(), new float[7]);
+    }
+
+    @Test
     public void testDraw() {
         float[] outerR = new float[] { 12, 12, 0, 0, 0, 0, 0, 0 };
         RectF   inset = new RectF(6, 6, 6, 6);
@@ -82,19 +92,20 @@
         assertEquals(TEST_COLOR_2, bitmap.getPixel(TEST_WIDTH / 2, 0));
     }
 
+    @Test
     public void testClone() throws CloneNotSupportedException {
         RoundRectShape roundRectShape = new RoundRectShape(new float[8], new RectF(), new float[8]);
         roundRectShape.resize(100f, 200f);
         RoundRectShape clonedShape = roundRectShape.clone();
-        assertEquals(100f, roundRectShape.getWidth());
-        assertEquals(200f, roundRectShape.getHeight());
+        assertEquals(100f, roundRectShape.getWidth(), 0.0f);
+        assertEquals(200f, roundRectShape.getHeight(), 0.0f);
 
         assertNotSame(roundRectShape, clonedShape);
-        assertEquals(roundRectShape.getWidth(), clonedShape.getWidth());
-        assertEquals(roundRectShape.getHeight(), clonedShape.getHeight());
+        assertEquals(roundRectShape.getWidth(), clonedShape.getWidth(), 0.0f);
+        assertEquals(roundRectShape.getHeight(), clonedShape.getHeight(), 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Outline outline = new Outline();
         Rect rect = new Rect();
@@ -110,7 +121,7 @@
         shape.resize(100, 100);
         shape.getOutline(outline);
         assertFalse(outline.isEmpty());
-        assertEquals(0.0f, outline.getRadius());
+        assertEquals(0.0f, outline.getRadius(), 0.0f);
         assertTrue(outline.getRect(rect));
         assertEquals(0, rect.left);
         assertEquals(0, rect.top);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ShapeTest.java b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ShapeTest.java
index 7f0e1e0..d5d16c3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ShapeTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/shapes/cts/ShapeTest.java
@@ -16,7 +16,10 @@
 
 package android.graphics.drawable.shapes.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -25,39 +28,45 @@
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.drawable.shapes.Shape;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-public class ShapeTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ShapeTest {
     private static final int TEST_WIDTH  = 100;
     private static final int TEST_HEIGHT = 200;
 
     private static final int TEST_COLOR_1 = 0xFF00FF00;
     private static final int TEST_COLOR_2 = 0xFFFF0000;
 
-    @SmallTest
+    @Test
     public void testSize() {
         MockShape mockShape = new MockShape();
         assertFalse(mockShape.hasCalledOnResize());
 
         mockShape.resize(200f, 300f);
-        assertEquals(200f, mockShape.getWidth());
-        assertEquals(300f, mockShape.getHeight());
+        assertEquals(200f, mockShape.getWidth(), 0.0f);
+        assertEquals(300f, mockShape.getHeight(), 0.0f);
         assertTrue(mockShape.hasCalledOnResize());
 
         mockShape.resize(0f, 0f);
-        assertEquals(0f, mockShape.getWidth());
-        assertEquals(0f, mockShape.getHeight());
+        assertEquals(0f, mockShape.getWidth(), 0.0f);
+        assertEquals(0f, mockShape.getHeight(), 0.0f);
 
         mockShape.resize(Float.MAX_VALUE, Float.MAX_VALUE);
-        assertEquals(Float.MAX_VALUE, mockShape.getWidth());
-        assertEquals(Float.MAX_VALUE, mockShape.getHeight());
+        assertEquals(Float.MAX_VALUE, mockShape.getWidth(), 0.0f);
+        assertEquals(Float.MAX_VALUE, mockShape.getHeight(), 0.0f);
 
         mockShape.resize(-1, -1);
-        assertEquals(0f, mockShape.getWidth());
-        assertEquals(0f, mockShape.getHeight());
+        assertEquals(0f, mockShape.getWidth(), 0.0f);
+        assertEquals(0f, mockShape.getHeight(), 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testOnResize() {
         MockShape mockShape = new MockShape();
         assertFalse(mockShape.hasCalledOnResize());
@@ -76,26 +85,26 @@
         assertTrue(mockShape.hasCalledOnResize());
     }
 
-    @SmallTest
+    @Test
     public void testClone() throws CloneNotSupportedException {
         Shape shape = new MockShape();
         shape.resize(100f, 200f);
         Shape clonedShape = shape.clone();
-        assertEquals(100f, shape.getWidth());
-        assertEquals(200f, shape.getHeight());
+        assertEquals(100f, shape.getWidth(), 0.0f);
+        assertEquals(200f, shape.getHeight(), 0.0f);
 
         assertNotSame(shape, clonedShape);
-        assertEquals(shape.getWidth(), clonedShape.getWidth());
-        assertEquals(shape.getHeight(), clonedShape.getHeight());
+        assertEquals(shape.getWidth(), clonedShape.getWidth(), 0.0f);
+        assertEquals(shape.getHeight(), clonedShape.getHeight(), 0.0f);
     }
 
-    @SmallTest
+    @Test
     public void testHasAlpha() {
         Shape shape = new MockShape();
         assertTrue(shape.hasAlpha());
     }
 
-    @SmallTest
+    @Test
     public void testDraw() {
         Shape shape = new MockShape();
         Bitmap bitmap = Bitmap.createBitmap(TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
@@ -113,7 +122,7 @@
         assertEquals(0, bitmap.getPixel(0, 0));
     }
 
-    @SmallTest
+    @Test
     public void testGetOutline() {
         Shape shape = new MockShape();
         Outline outline = new Outline();
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..ecbb6d2
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java
@@ -0,0 +1,426 @@
+/*
+ * 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 static android.graphics.pdf.cts.Utils.verifyException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+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.filters.SmallTest;
+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;
+
+/**
+ * Tests {@link PdfDocument}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PdfDocumentTest {
+    private File mCacheDir;
+
+    @Before
+    public void setup() {
+        mCacheDir = InstrumentationRegistry.getTargetContext().getCacheDir();
+    }
+
+    @Test
+    public void getPagesEmptyDocAfterClose() {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+        assertEquals(0, doc.getPages().size());
+    }
+
+    @Test
+    public void closeClosedDoc() {
+        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", mCacheDir));
+
+        verifyException(() -> doc.writeTo(os), IllegalStateException.class);
+    }
+
+    @Test
+    public void startPageClosedDoc() {
+        PdfDocument doc = new PdfDocument();
+        doc.close();
+
+        verifyException(() -> doc.startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create()),
+                IllegalStateException.class);
+    }
+
+    @Test
+    public void finishPageTwiceDoc() {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        doc.finishPage(page);
+        verifyException(() -> doc.finishPage(page), IllegalStateException.class);
+
+        doc.close();
+    }
+
+    @Test
+    public void closeWithOpenPage() {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        verifyException(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", mCacheDir);
+        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", mCacheDir);
+        try (OutputStream os = new FileOutputStream(pdfFile)) {
+            verifyException(() -> doc.writeTo(os), IllegalStateException.class);
+        }
+
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void openTwoPages() {
+        PdfDocument doc = new PdfDocument();
+
+        PdfDocument.Page page = doc
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        verifyException(() -> doc.startPage(new PdfDocument.PageInfo.Builder(100, 100, 1).create()),
+                IllegalStateException.class);
+
+        doc.finishPage(page);
+        doc.close();
+    }
+
+    @Test
+    public void finishPageFromWrongDoc() {
+        PdfDocument doc1 = new PdfDocument();
+        PdfDocument doc2 = new PdfDocument();
+
+        PdfDocument.Page page1 = doc1
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        verifyException(() -> doc2.finishPage(page1), IllegalStateException.class);
+
+        PdfDocument.Page page2 = doc2
+                .startPage(new PdfDocument.PageInfo.Builder(100, 100, 0).create());
+        verifyException(() -> 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", mCacheDir);
+        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", mCacheDir);
+        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", mCacheDir);
+        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() {
+        PdfDocument doc = new PdfDocument();
+        verifyException(() -> doc.writeTo(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void startNullPage() {
+        PdfDocument doc = new PdfDocument();
+        verifyException(() -> doc.startPage(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void finishNullPage() {
+        PdfDocument doc = new PdfDocument();
+        verifyException(() -> doc.finishPage(null), IllegalArgumentException.class);
+        doc.close();
+    }
+
+    @Test
+    public void zeroWidthPage() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(0, 200, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativeWidthPage() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(-1, 200, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void zeroHeightPage() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 0, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativeHeightPage() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, -1, 0),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void negativePageNumber() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 200, -1),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectLeftNegative() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                .setContentRect(new Rect(-1, 0, 100, 200)), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectTopNegative() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                .setContentRect(new Rect(0, -1, 100, 200)), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectRightToHigh() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                .setContentRect(new Rect(0, 0, 101, 200)), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void contentRectBottomToHigh() {
+        verifyException(() -> new PdfDocument.PageInfo.Builder(100, 200, 0)
+                .setContentRect(new Rect(0, 0, 100, 201)), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void createPageWithFullContentRect() {
+        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() {
+        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() {
+        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() {
+        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() {
+        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..530ac1b
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -0,0 +1,366 @@
+/*
+ * 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 static android.graphics.pdf.cts.Utils.A4_HEIGHT_PTS;
+import static android.graphics.pdf.cts.Utils.A4_PORTRAIT;
+import static android.graphics.pdf.cts.Utils.A4_WIDTH_PTS;
+import static android.graphics.pdf.cts.Utils.A5_PORTRAIT;
+import static android.graphics.pdf.cts.Utils.createRenderer;
+import static android.graphics.pdf.cts.Utils.renderAndCompare;
+import static android.graphics.pdf.cts.Utils.renderWithTransform;
+import static android.graphics.pdf.cts.Utils.verifyException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+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.filters.SmallTest;
+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;
+
+/**
+ * All test for {@link PdfRenderer} beside the valid transformation parameter tests of {@link
+ * PdfRenderer.Page#render}.
+ */
+@SmallTest
+@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.getTargetContext();
+    }
+
+    @Test
+    public void constructRendererNull() throws Exception {
+        verifyException(() -> 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();
+        verifyException(() -> new PdfRenderer(fd), IOException.class);
+    }
+
+    @Test
+    public void useRendererAfterClose() throws Exception {
+        PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
+        renderer.close();
+
+        verifyException(renderer::close, IllegalStateException.class);
+        verifyException(renderer::getPageCount, IllegalStateException.class);
+        verifyException(renderer::shouldScaleForPrinting, IllegalStateException.class);
+        verifyException(() -> renderer.openPage(0), IllegalStateException.class);
+    }
+
+    @Test
+    public void usePageAfterClose() throws Exception {
+        PdfRenderer renderer = createRenderer(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();
+        verifyException(page::close, IllegalStateException.class);
+
+        // Legacy support. An IllegalStateException would be nice by unfortunately the legacy
+        // implementation returned NullPointerException
+        verifyException(() -> page.render(null, null, null, Page.RENDER_MODE_FOR_DISPLAY),
+                NullPointerException.class);
+
+        renderer.close();
+    }
+
+    @Test
+    public void closeWithOpenPage() throws Exception {
+        PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
+        Page page = renderer.openPage(0);
+
+        verifyException(renderer::close, IllegalStateException.class);
+
+        page.close();
+        renderer.close();
+    }
+
+    @Test
+    public void openTwoPages() throws Exception {
+        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
+            // Cannot open two pages at once
+            Page page = renderer.openPage(0);
+            verifyException(() -> renderer.openPage(1), IllegalStateException.class);
+
+            page.close();
+        }
+    }
+
+    @Test
+    public void testPageCount() throws Exception {
+        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
+            assertEquals(2, renderer.getPageCount());
+        }
+    }
+
+    @Test
+    public void testOpenPage() throws Exception {
+        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
+            verifyException(() -> renderer.openPage(-1), IllegalArgumentException.class);
+            Page page0 = renderer.openPage(0);
+            page0.close();
+            Page page1 = renderer.openPage(1);
+            page1.close();
+            verifyException(() -> renderer.openPage(2), IllegalArgumentException.class);
+        }
+    }
+
+    @Test
+    public void testPageSize() throws Exception {
+        try (PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
+             Page page = renderer.openPage(0)) {
+            assertEquals(A4_HEIGHT_PTS, page.getHeight());
+            assertEquals(A4_WIDTH_PTS, page.getWidth());
+        }
+    }
+
+    @Test
+    public void testPrintScaleDefault() throws Exception {
+        try (PdfRenderer renderer = createRenderer(A5_PORTRAIT, mContext)) {
+            assertTrue(renderer.shouldScaleForPrinting());
+        }
+    }
+
+    @Test
+    public void testPrintScalePDF16Default() throws Exception {
+        try (PdfRenderer renderer = createRenderer(A5_PORTRAIT_PRINTSCALING_DEFAULT, mContext)) {
+            assertTrue(renderer.shouldScaleForPrinting());
+        }
+    }
+
+    @Test
+    public void testPrintScalePDF16None() throws Exception {
+        try (PdfRenderer renderer = 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 = renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, 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 });
+
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, 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(A4_WIDTH_PTS / 4, A4_HEIGHT_PTS / 4);
+        // Scale to 75%
+        transform.postScale(0.75f, 0.75f);
+        // Clip
+        Rect clip = new Rect(20, 20, A4_WIDTH_PTS - 20, A4_HEIGHT_PTS - 20);
+
+        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, transform,
+                Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderStreched() throws Exception {
+        renderAndCompare(A4_WIDTH_PTS * 4 / 3, A4_HEIGHT_PTS * 3 / 4, A4_PORTRAIT, null, null,
+                Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithClip() throws Exception {
+        Rect clip = new Rect(20, 20, A4_WIDTH_PTS - 50, A4_HEIGHT_PTS - 50);
+        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
+                Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithAllClipped() throws Exception {
+        Rect clip = new Rect(A4_WIDTH_PTS / 2, A4_HEIGHT_PTS / 2, A4_WIDTH_PTS / 2,
+                A4_HEIGHT_PTS / 2);
+        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
+                Page.RENDER_MODE_FOR_DISPLAY, mContext);
+    }
+
+    @Test
+    public void renderWithBadLowerCornerOfClip() throws Exception {
+        Rect clip = new Rect(0, 0, A4_WIDTH_PTS + 20, A4_HEIGHT_PTS + 20);
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
+                        Page.RENDER_MODE_FOR_DISPLAY, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderWithBadUpperCornerOfClip() throws Exception {
+        Rect clip = new Rect(-20, -20, A4_WIDTH_PTS, A4_HEIGHT_PTS);
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
+                        Page.RENDER_MODE_FOR_DISPLAY, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderTwoModes() throws Exception {
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null,
+                        Page.RENDER_MODE_FOR_DISPLAY | Page.RENDER_MODE_FOR_PRINT, mContext),
+                IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderBadMode() throws Exception {
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null,
+                        1 << 30, mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderAllModes() throws Exception {
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null, -1,
+                        mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderNoMode() throws Exception {
+        verifyException(
+                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null, 0,
+                        mContext), IllegalArgumentException.class);
+    }
+
+    @Test
+    public void renderOnNullBitmap() throws Exception {
+        try (PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
+             Page page = renderer.openPage(0)) {
+            verifyException(() -> 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..4f186ea
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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 static android.graphics.pdf.cts.Utils.A4_HEIGHT_PTS;
+import static android.graphics.pdf.cts.Utils.A4_PORTRAIT;
+import static android.graphics.pdf.cts.Utils.A4_WIDTH_PTS;
+import static android.graphics.pdf.cts.Utils.renderAndCompare;
+
+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 android.support.test.filters.SmallTest;
+
+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[] { A4_WIDTH_PTS * 3 / 4, A4_WIDTH_PTS, A4_WIDTH_PTS * 4 / 3
+        };
+        int[] heights = new int[] { A4_HEIGHT_PTS * 3 / 4, A4_HEIGHT_PTS, A4_HEIGHT_PTS * 4 / 3
+        };
+        int[] rotations = new int[] { 0, 15, 90, 180 };
+        int[] translations = new int[] { -A4_HEIGHT_PTS / 2, 0, 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, A4_PORTRAIT, null,
+                                                    transformation, Page.RENDER_MODE_FOR_DISPLAY
+                                            });
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return params;
+    }
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    // Note that the size annotation refers to the "size" of each individual parameterized run,
+    // and not the "full" run.
+    @SmallTest
+    @Test
+    public void test() throws Exception {
+        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..2e2de3e
--- /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 static org.junit.Assert.fail;
+
+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;
+
+/**
+ * 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;
+        int totalPixels = a.getWidth() * a.getHeight();
+        for (int i = 0; i < totalPixels; i++) {
+            if (aPx[i] != bPx[i]) {
+                badPixels++;
+            }
+        }
+
+        return ((float) badPixels) / totalPixels;
+    }
+
+    /**
+     * 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 an exception of a certain type.
+     *
+     * @param r             The {@link Invokable} to run
+     * @param expectedClass The expected exception type
+     */
+    static void verifyException(@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);
+                fail("Expected: " + expectedClass.getName() + ", got: " + e.getClass().getName());
+            }
+        }
+
+        fail("Expected to have " + expectedClass.getName() + " 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/ByteBufferTest.java b/tests/tests/graphics/src/android/opengl/cts/ByteBufferTest.java
new file mode 100644
index 0000000..8d596b4
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/ByteBufferTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.opengl.cts;
+
+import android.support.test.filters.SmallTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+
+import static android.opengl.GLES30.GL_BUFFER_MAP_POINTER;
+import static android.opengl.GLES30.GL_DYNAMIC_READ;
+import static android.opengl.GLES30.GL_MAP_READ_BIT;
+import static android.opengl.GLES30.GL_UNIFORM_BUFFER;
+import static android.opengl.GLES30.glBindBuffer;
+import static android.opengl.GLES30.glBufferData;
+import static android.opengl.GLES30.glDeleteBuffers;
+import static android.opengl.GLES30.glGenBuffers;
+import static android.opengl.GLES30.glGetBufferPointerv;
+import static android.opengl.GLES30.glMapBufferRange;
+import static android.opengl.GLES30.glUnmapBuffer;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for functions that return a ByteBuffer.
+ */
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class) // DO NOT USE AndroidJUnit4, it messes up threading
+public class ByteBufferTest extends GlTestBase {
+    @Test
+    public void testMapBufferRange() {
+        // Always pass on ES 2.0
+        if (Egl14Utils.getMajorVersion() >= 3) {
+            int[] buffer = new int[1];
+            glGenBuffers(1, buffer, 0);
+            glBindBuffer(GL_UNIFORM_BUFFER, buffer[0]);
+            glBufferData(GL_UNIFORM_BUFFER, 1024, null, GL_DYNAMIC_READ);
+
+            Buffer mappedBuffer = glMapBufferRange(GL_UNIFORM_BUFFER, 0, 1024, GL_MAP_READ_BIT);
+
+            assertNotNull(mappedBuffer);
+            assertTrue(mappedBuffer instanceof ByteBuffer);
+
+            Buffer pointerBuffer = glGetBufferPointerv(GL_UNIFORM_BUFFER, GL_BUFFER_MAP_POINTER);
+            assertNotNull(pointerBuffer);
+            assertTrue(pointerBuffer instanceof ByteBuffer);
+
+            glUnmapBuffer(GL_UNIFORM_BUFFER);
+
+            glBindBuffer(GL_UNIFORM_BUFFER, 0);
+            glDeleteBuffers(1, buffer, 0);
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
index bade5a8..4d3b679 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureCtsActivity.java
@@ -15,15 +15,11 @@
  */
 package android.opengl.cts;
 
-import android.graphics.cts.R;
-
 import android.app.Activity;
-import android.content.Intent;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
+import android.graphics.cts.R;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -31,7 +27,7 @@
 
     private static final String TAG = "CompressedTextureCtsActivity";
 
-    protected Resources mResources;
+    private Resources mResources;
 
     private CompressedTextureSurfaceView mCompressedTextureView = null;
 
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
index 3a2e00f..c81a3b9 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureLoader.java
@@ -15,31 +15,19 @@
  */
 package android.opengl.cts;
 
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.Buffer;
-import java.nio.ByteOrder;
-import java.util.HashMap;
-
-import android.graphics.cts.R;
-
-import android.app.Activity;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-
+import android.graphics.Bitmap;
 import android.opengl.ETC1;
 import android.opengl.ETC1Util;
 import android.opengl.GLES20;
 
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
 
 public class CompressedTextureLoader {
-    private static final String TAG = "CompressedTextureLoader";
-
     public static final String TEXTURE_UNCOMPRESSED = "UNCOMPRESSED";
     public static final String TEXTURE_ETC1 = "ETC1";
     public static final String TEXTURE_S3TC = "S3TC";
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
index 9437c58..6ca404b 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureSurfaceView.java
@@ -16,42 +16,25 @@
 
 package android.opengl.cts;
 
-import java.io.IOException;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-import android.graphics.cts.R;
-
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
-import android.graphics.SurfaceTexture;
-import android.opengl.ETC1;
-import android.opengl.ETC1Util;
 import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
 import android.opengl.GLUtils;
 import android.opengl.Matrix;
 import android.util.Log;
-import android.view.Surface;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-class CompressedTextureSurfaceView extends GLSurfaceView {
-    private static final String TAG = "CompressedTextureSurfaceView";
-    private static final int SLEEP_TIME_MS = 1000;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
 
+class CompressedTextureSurfaceView extends GLSurfaceView {
     CompressedTextureRender mRenderer;
 
     public CompressedTextureSurfaceView(Context context,
@@ -60,16 +43,11 @@
         super(context);
 
         setEGLContextClientVersion(2);
-        mRenderer = new CompressedTextureRender(context, base, compressed);
+        mRenderer = new CompressedTextureRender(base, compressed);
         setRenderer(mRenderer);
         setRenderMode(RENDERMODE_WHEN_DIRTY);
     }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-    }
-
     public boolean getTestPassed() throws InterruptedException {
         return mRenderer.getTestPassed();
     }
@@ -119,13 +97,10 @@
         private int muMVPMatrixHandle;
         private int maPositionHandle;
         private int maTextureHandle;
-        private int msTextureHandle;
 
         private int mColorTargetID;
         private int mFrameBufferObjectID;
 
-        private boolean updateSurface = false;
-
         private boolean mTestPassed;
         private CountDownLatch mDoneSignal;
 
@@ -145,8 +120,7 @@
             return mTestPassed;
         }
 
-        public CompressedTextureRender(Context context,
-                                       Bitmap base,
+        public CompressedTextureRender(Bitmap base,
                                        CompressedTextureLoader.Texture compressed) {
             mBaseTexture = base;
             mCompressedTexture = compressed;
@@ -360,10 +334,6 @@
             }
         }
 
-        synchronized public void onFrameAvailable(SurfaceTexture surface) {
-            updateSurface = true;
-        }
-
         private int loadShader(int shaderType, String source) {
             int shader = GLES20.glCreateShader(shaderType);
             if (shader != 0) {
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
index 09902df..137c8d4 100644
--- a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
@@ -16,43 +16,58 @@
 
 package android.opengl.cts;
 
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
+import static org.junit.Assert.assertTrue;
 
-/**
- */
-public class CompressedTextureTest extends ActivityInstrumentationTestCase2<CompressedTextureCtsActivity> {
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 
-    public CompressedTextureTest() {
-        super("android.graphics.cts", CompressedTextureCtsActivity.class);
-    }
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CompressedTextureTest {
+    @Rule
+    public ActivityTestRule<CompressedTextureCtsActivity> mActivityRule =
+            new ActivityTestRule<>(CompressedTextureCtsActivity.class, false, false);
 
     private void launchTest(String format) throws Exception {
-        Bundle extras = new Bundle();
-        extras.putString("TextureFormat", format);
-        CompressedTextureCtsActivity activity = launchActivity("android.graphics.cts",
-                CompressedTextureCtsActivity.class, extras);
+        Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
+                CompressedTextureCtsActivity.class);
+        intent.putExtra("TextureFormat", format);
+        CompressedTextureCtsActivity activity = mActivityRule.launchActivity(intent);
         activity.finish();
         assertTrue(activity.getPassed());
     }
 
+    @Test
     public void testTextureUncompressed() throws Exception {
         launchTest(CompressedTextureLoader.TEXTURE_UNCOMPRESSED);
     }
 
+    @Test
     public void testTextureETC1() throws Exception {
         launchTest(CompressedTextureLoader.TEXTURE_ETC1);
     }
 
+    @Test
     public void testTexturePVRTC() throws Exception {
         launchTest(CompressedTextureLoader.TEXTURE_PVRTC);
     }
 
+    @Test
     public void testTextureS3TC() throws Exception {
         launchTest(CompressedTextureLoader.TEXTURE_S3TC);
     }
 
-    /*public void testTextureATC() throws Exception {
+    @Ignore
+    @Test
+    public void testTextureATC() throws Exception {
         launchTest(CompressedTextureLoader.TEXTURE_ATC);
-    }*/
+    }
 }
diff --git a/tests/tests/graphics/src/android/opengl/cts/Egl10Utils.java b/tests/tests/graphics/src/android/opengl/cts/Egl10Utils.java
new file mode 100644
index 0000000..83aa158
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/Egl10Utils.java
@@ -0,0 +1,116 @@
+/*
+ * 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.opengl.cts;
+
+import android.opengl.EGL14;
+import android.opengl.EGLExt;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLDisplay;
+
+final class Egl10Utils {
+    private Egl10Utils() {
+    }
+
+    static EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, int[] configSpec) {
+        int[] value = new int[1];
+        if (!egl.eglChooseConfig(display, configSpec, null, 0,
+                value)) {
+            throw new IllegalArgumentException("eglChooseConfig failed");
+        }
+
+        int numConfigs = value[0];
+        if (numConfigs <= 0) {
+            throw new IllegalArgumentException("No configs match configSpec");
+        }
+
+        EGLConfig[] configs = new EGLConfig[numConfigs];
+        if (!egl.eglChooseConfig(display, configSpec, configs, numConfigs, value)) {
+            throw new IllegalArgumentException("eglChooseConfig#2 failed");
+        }
+        EGLConfig config = chooseConfig(egl, display, configs, configSpec);
+        if (config == null) {
+            throw new IllegalArgumentException("No config chosen");
+        }
+        return config;
+    }
+
+    static int[] filterConfigSpec(int[] configSpec, int version) {
+        if (version != 2 && version != 3) {
+            return configSpec;
+        }
+
+        int len = configSpec.length;
+        int[] newConfigSpec = new int[len + 2];
+        System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
+
+        newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
+        if (version == 2) {
+            newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;  /* EGL_OPENGL_ES2_BIT */
+        } else {
+            newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
+        }
+        newConfigSpec[len + 1] = EGL10.EGL_NONE;
+
+        return newConfigSpec;
+    }
+
+    private static EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+            EGLConfig[] configs, int[] configSpec) {
+
+        int redSize = findValue(configSpec, EGL10.EGL_RED_SIZE);
+        int greenSize = findValue(configSpec, EGL10.EGL_GREEN_SIZE);
+        int blueSize = findValue(configSpec, EGL10.EGL_BLUE_SIZE);
+        int alphaSize = findValue(configSpec, EGL10.EGL_ALPHA_SIZE);
+        int depthSize = findValue(configSpec, EGL10.EGL_DEPTH_SIZE);
+        int stencilSize = findValue(configSpec, EGL10.EGL_STENCIL_SIZE);
+
+        for (EGLConfig config : configs) {
+            int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE);
+            int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE);
+            if ((d >= depthSize) && (s >= stencilSize)) {
+                int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE);
+                int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE);
+                int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE);
+                int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE);
+                if ((r == redSize) && (g == greenSize) && (b == blueSize) && (a == alphaSize)) {
+                    return config;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static int findValue(int[] configSpec, int name) {
+        for (int i = 0; i < configSpec.length; i += 2) {
+            if (configSpec[i] == name) {
+                return configSpec[i + 1];
+            }
+        }
+        return 0;
+    }
+
+    private static int findConfigAttrib(EGL10 egl, EGLDisplay display,
+            EGLConfig config, int attribute) {
+        int[] value = new int[1];
+        if (egl.eglGetConfigAttrib(display, config, attribute, value)) {
+            return value[0];
+        }
+        return 0;
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/Egl14Utils.java b/tests/tests/graphics/src/android/opengl/cts/Egl14Utils.java
new file mode 100644
index 0000000..677accc
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/Egl14Utils.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.opengl.cts;
+
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLExt;
+import android.opengl.EGLSurface;
+import android.opengl.GLES20;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utilities to test EGL APIs.
+ */
+final class Egl14Utils {
+    private Egl14Utils() {
+    }
+
+    static int getMajorVersion() {
+        // Section 6.1.5 of the OpenGL ES specification indicates the GL version
+        // string strictly follows this format:
+        //
+        // OpenGL<space>ES<space><version number><space><vendor-specific information>
+        //
+        // In addition section 6.1.5 describes the version number thusly:
+        //
+        // "The version number is either of the form major number.minor number or
+        // major number.minor number.release number, where the numbers all have one
+        // or more digits. The release number and vendor specific information are
+        // optional."
+        String version = GLES20.glGetString(GLES20.GL_VERSION);
+        Pattern pattern = Pattern.compile("OpenGL ES ([0-9]+)\\.([0-9]+)");
+        Matcher matcher = pattern.matcher(version);
+        if (matcher.find()) {
+            return Integer.parseInt(matcher.group(1));
+        }
+        return 2;
+    }
+
+    /**
+     * Returns an initialized default display.
+     */
+    static EGLDisplay createEglDisplay() {
+        EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+        if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
+            throw new IllegalStateException("no EGL display");
+        }
+
+        int[] major = new int[1];
+        int[] minor = new int[1];
+        if (!EGL14.eglInitialize(eglDisplay, major, 0, minor, 0)) {
+            throw new IllegalStateException("error in eglInitialize");
+        }
+
+        return eglDisplay;
+    }
+
+    /**
+     * Returns a new GL ES 2.0 context for the specified {@code eglDisplay}.
+     */
+    static EGLContext createEglContext(EGLDisplay eglDisplay) {
+        return createEglContext(eglDisplay, getEglConfig(eglDisplay, 2), 2);
+    }
+
+    /**
+     * Returns a new GL ES context for the specified display, config and version.
+     */
+    static EGLContext createEglContext(EGLDisplay eglDisplay, EGLConfig eglConfig, int version) {
+        int[] contextAttributes = { EGL14.EGL_CONTEXT_CLIENT_VERSION, version, EGL14.EGL_NONE };
+        return EGL14.eglCreateContext(eglDisplay, eglConfig,
+                EGL14.EGL_NO_CONTEXT, contextAttributes, 0);
+    }
+
+    /**
+     * Destroys the GL context identified by {@code eglDisplay} and {@code eglContext}.
+     */
+    static void destroyEglContext(EGLDisplay eglDisplay, EGLContext eglContext) {
+        EGL14.eglMakeCurrent(eglDisplay,
+                EGL14.EGL_NO_SURFACE,
+                EGL14.EGL_NO_SURFACE,
+                EGL14.EGL_NO_CONTEXT);
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("error releasing context: " + error);
+        }
+
+        EGL14.eglDestroyContext(eglDisplay, eglContext);
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("error destroying context: " + error);
+        }
+    }
+
+    static void releaseAndTerminate(EGLDisplay eglDisplay) {
+        int error;
+        EGL14.eglReleaseThread();
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("error releasing thread: " + error);
+        }
+
+        EGL14.eglTerminate(eglDisplay);
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("error terminating display: " + error);
+        }
+    }
+
+    static EGLConfig getEglConfig(EGLDisplay eglDisplay, int version) {
+        // Get an EGLConfig.
+        int renderableType = EGL14.EGL_OPENGL_ES2_BIT;
+        if (version == 3) {
+            renderableType = EGLExt.EGL_OPENGL_ES3_BIT_KHR;
+        }
+        final int RED_SIZE = 8;
+        final int GREEN_SIZE = 8;
+        final int BLUE_SIZE = 8;
+        final int ALPHA_SIZE = 8;
+        final int DEPTH_SIZE = 0;
+        final int STENCIL_SIZE = 0;
+        final int[] DEFAULT_CONFIGURATION = new int[] {
+                EGL14.EGL_RENDERABLE_TYPE, renderableType,
+                EGL14.EGL_RED_SIZE, RED_SIZE,
+                EGL14.EGL_GREEN_SIZE, GREEN_SIZE,
+                EGL14.EGL_BLUE_SIZE, BLUE_SIZE,
+                EGL14.EGL_ALPHA_SIZE, ALPHA_SIZE,
+                EGL14.EGL_DEPTH_SIZE, DEPTH_SIZE,
+                EGL14.EGL_STENCIL_SIZE, STENCIL_SIZE,
+                EGL14.EGL_NONE};
+
+        int[] configsCount = new int[1];
+        EGLConfig[] eglConfigs = new EGLConfig[1];
+        if (!EGL14.eglChooseConfig(
+                eglDisplay, DEFAULT_CONFIGURATION, 0, eglConfigs, 0, 1, configsCount, 0)) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+        return eglConfigs[0];
+    }
+
+    /**
+     * Checks for a GL error using {@link GLES20#glGetError()}.
+     *
+     * @throws RuntimeException if there is a GL error
+     */
+    static void checkGlError() {
+        int errorCode;
+        if ((errorCode = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("gl error: " + Integer.toHexString(errorCode));
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java b/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
index 1468382..95ed618 100644
--- a/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/EglConfigTest.java
@@ -16,9 +16,19 @@
 
 package android.opengl.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Instrumentation;
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+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 javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -28,24 +38,24 @@
 /**
  * Test that gets a list of EGL configurations and tries to use each one in a GLSurfaceView.
  */
-public class EglConfigTest extends ActivityInstrumentationTestCase2<EglConfigCtsActivity> {
-
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class EglConfigTest {
     private static final int EGL_OPENGL_ES_BIT = 0x1;
-
     private static final int EGL_OPENGL_ES2_BIT = 0x4;
 
     private Instrumentation mInstrumentation;
 
-    public EglConfigTest() {
-        super("android.graphics.cts", EglConfigCtsActivity.class);
+    @Rule
+    public ActivityTestRule<EglConfigCtsActivity> mActivityRule =
+            new ActivityTestRule<>(EglConfigCtsActivity.class, false, false);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-    }
-
+    @Test
     public void testEglConfigs() throws Exception {
         int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
         int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
@@ -57,11 +67,12 @@
     private void runConfigTests(int[] configIds, int contextClientVersion)
             throws InterruptedException {
         for (int configId : configIds) {
-            Bundle extras = new Bundle();
-            extras.putInt(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
-            extras.putInt(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA, contextClientVersion);
-            EglConfigCtsActivity activity = launchActivity("android.graphics.cts",
-                    EglConfigCtsActivity.class, extras);
+            Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
+                    EglConfigCtsActivity.class);
+            intent.putExtra(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
+            intent.putExtra(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA,
+                    contextClientVersion);
+            EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
             activity.waitToFinishDrawing();
             // TODO(b/30948621): Remove the sleep below once b/30948621 is fixed.
             Thread.sleep(500);
diff --git a/tests/tests/graphics/src/android/opengl/cts/EglContextTest.java b/tests/tests/graphics/src/android/opengl/cts/EglContextTest.java
index 8f5ced7..3cfd2d5 100644
--- a/tests/tests/graphics/src/android/opengl/cts/EglContextTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/EglContextTest.java
@@ -16,33 +16,33 @@
 
 package android.opengl.cts;
 
-import android.app.Activity;
 import android.opengl.EGL14;
-import android.opengl.EGLConfig;
 import android.opengl.EGLContext;
 import android.opengl.EGLDisplay;
-import android.opengl.GLES20;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests using EGL contexts.
  */
-public class EglContextTest extends ActivityInstrumentationTestCase2<Activity> {
-
-    public EglContextTest() {
-        super(Activity.class);
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EglContextTest {
     /**
      * Tests creating then releasing an EGL context.
      */
+    @Test
     public void testCreateAndReleaseContext() {
         EGLDisplay eglDisplay = null;
         EGLContext eglContext = null;
         try {
-            eglDisplay = createEglDisplay();
-            eglContext = createEglContext(eglDisplay);
-            destroyEglContext(eglDisplay, eglContext);
+            eglDisplay = Egl14Utils.createEglDisplay();
+            eglContext = Egl14Utils.createEglContext(eglDisplay);
+            Egl14Utils.destroyEglContext(eglDisplay, eglContext);
+            Egl14Utils.releaseAndTerminate(eglDisplay);
             eglDisplay = null;
             eglContext = null;
         } finally {
@@ -55,108 +55,4 @@
             }
         }
     }
-
-    /**
-     * Returns an initialized default display.
-     */
-    private static EGLDisplay createEglDisplay() {
-        EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
-        if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
-            throw new IllegalStateException("no EGL display");
-        }
-
-        int[] major = new int[1];
-        int[] minor = new int[1];
-        if (!EGL14.eglInitialize(eglDisplay, major, 0, minor, 0)) {
-            throw new IllegalStateException("error in eglInitialize");
-        }
-        checkGlError();
-
-        return eglDisplay;
-    }
-
-    /**
-     * Returns a new GL context for the specified {@code eglDisplay}.
-     */
-    private static EGLContext createEglContext(EGLDisplay eglDisplay) {
-        int[] contextAttributes = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE };
-        EGLContext eglContext = EGL14.eglCreateContext(eglDisplay,
-                getEglConfig(eglDisplay), EGL14.EGL_NO_CONTEXT, contextAttributes, 0);
-        checkGlError();
-
-        return eglContext;
-    }
-
-    /**
-     * Destroys the GL context identifier by {@code eglDisplay} and {@code eglContext}.
-     */
-    private static void destroyEglContext(EGLDisplay eglDisplay, EGLContext eglContext) {
-        EGL14.eglMakeCurrent(eglDisplay,
-                EGL14.EGL_NO_SURFACE,
-                EGL14.EGL_NO_SURFACE,
-                EGL14.EGL_NO_CONTEXT);
-        int error = EGL14.eglGetError();
-        if (error != EGL14.EGL_SUCCESS) {
-            throw new RuntimeException("error releasing context: " + error);
-        }
-
-        EGL14.eglDestroyContext(eglDisplay, eglContext);
-        error = EGL14.eglGetError();
-        if (error != EGL14.EGL_SUCCESS) {
-            throw new RuntimeException("error destroying context: " + error);
-        }
-
-        EGL14.eglReleaseThread();
-        error = EGL14.eglGetError();
-        if (error != EGL14.EGL_SUCCESS) {
-            throw new RuntimeException("error releasing thread: " + error);
-        }
-
-        EGL14.eglTerminate(eglDisplay);
-        error = EGL14.eglGetError();
-        if (error != EGL14.EGL_SUCCESS) {
-            throw new RuntimeException("error terminating display: " + error);
-        }
-    }
-
-    private static EGLConfig getEglConfig(EGLDisplay eglDisplay) {
-        // Get an EGLConfig.
-        final int EGL_OPENGL_ES2_BIT = 4;
-        final int RED_SIZE = 8;
-        final int GREEN_SIZE = 8;
-        final int BLUE_SIZE = 8;
-        final int ALPHA_SIZE = 8;
-        final int DEPTH_SIZE = 0;
-        final int STENCIL_SIZE = 0;
-        final int[] DEFAULT_CONFIGURATION = new int[] {
-                EGL14.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                EGL14.EGL_RED_SIZE, RED_SIZE,
-                EGL14.EGL_GREEN_SIZE, GREEN_SIZE,
-                EGL14.EGL_BLUE_SIZE, BLUE_SIZE,
-                EGL14.EGL_ALPHA_SIZE, ALPHA_SIZE,
-                EGL14.EGL_DEPTH_SIZE, DEPTH_SIZE,
-                EGL14.EGL_STENCIL_SIZE, STENCIL_SIZE,
-                EGL14.EGL_NONE};
-
-        int[] configsCount = new int[1];
-        EGLConfig[] eglConfigs = new EGLConfig[1];
-        if (!EGL14.eglChooseConfig(
-                eglDisplay, DEFAULT_CONFIGURATION, 0, eglConfigs, 0, 1, configsCount, 0)) {
-            throw new RuntimeException("eglChooseConfig failed");
-        }
-        return eglConfigs[0];
-    }
-
-    /**
-     * Checks for a GL error using {@link GLES20#glGetError()}.
-     *
-     * @throws RuntimeException if there is a GL error
-     */
-    private static void checkGlError() {
-        int errorCode;
-        if ((errorCode = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
-            throw new RuntimeException("gl error: " + Integer.toHexString(errorCode));
-        }
-    }
-
 }
diff --git a/tests/tests/graphics/src/android/opengl/cts/EglSurfacesTest.java b/tests/tests/graphics/src/android/opengl/cts/EglSurfacesTest.java
new file mode 100644
index 0000000..c909eeb
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/EglSurfacesTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.opengl.cts;
+
+import android.opengl.EGL14;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Tests using EGL surfaces.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EglSurfacesTest {
+    @Test
+    public void testCreatePixmapSurface() {
+        // NOTE: This test must use EGL10, which is why we don't reuse GlTestBase
+        EGL10 egl = (EGL10) EGLContext.getEGL();
+        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+        if (display == EGL10.EGL_NO_DISPLAY) {
+            throw new RuntimeException("eglGetDisplay failed");
+        }
+
+        int[] version = new int[2];
+        if (!egl.eglInitialize(display, version)) {
+            throw new RuntimeException("eglInitialize failed");
+        }
+
+        EGLConfig config = Egl10Utils.chooseConfig(egl, display,
+                Egl10Utils.filterConfigSpec(new int[] {
+                        EGL10.EGL_RED_SIZE, 8,
+                        EGL10.EGL_GREEN_SIZE, 8,
+                        EGL10.EGL_BLUE_SIZE, 8,
+                        EGL10.EGL_ALPHA_SIZE, 0,
+                        EGL10.EGL_DEPTH_SIZE, 0,
+                        EGL10.EGL_STENCIL_SIZE, 0,
+                        EGL10.EGL_NONE }, 2)
+        );
+
+        int[] contextAttribs = {
+                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+                EGL10.EGL_NONE
+        };
+
+        EGLContext context = egl.eglCreateContext(display, config,
+                EGL10.EGL_NO_CONTEXT, contextAttribs);
+
+        boolean unsupported = false;
+        try {
+            //noinspection deprecation
+            egl.eglCreatePixmapSurface(display, config, null, null);
+        } catch (UnsupportedOperationException e) {
+            unsupported = true;
+        }
+
+        egl.eglDestroyContext(display, context);
+        egl.eglTerminate(display);
+
+        if (!unsupported) {
+            fail("eglCreatePixmapSurface is supported");
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewCtsActivity.java b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewCtsActivity.java
index 9557406..f38094c 100644
--- a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewCtsActivity.java
+++ b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewCtsActivity.java
@@ -47,60 +47,11 @@
 
     private GLSurfaceView mView;
 
-    /** To override the blank renderer, or other settings, these
-     * static set* methods must be called before onCreate() is called.
-     * If using ActivityInstrumentationTestCase2, that means the set
-     * methods need to be called before calling getActivity in the
-     * test setUp().
-     */
-    private static GLSurfaceView.Renderer mRenderer = null;
-    public static void setRenderer(GLSurfaceView.Renderer renderer) {
-        mRenderer = renderer;
-    }
-    public static void resetRenderer() {
-        mRenderer = null;
-    }
-
-    private static int mRenderMode = 0;
-    private static boolean mRenderModeSet = false;
-    public static void setRenderMode(int renderMode) {
-        mRenderModeSet = true;
-        mRenderMode = renderMode;
-    }
-    public static void resetRenderMode() {
-        mRenderModeSet = false;
-        mRenderMode = 0;
-    }
-
-    private static int mGlVersion = 0;
-    private static boolean mGlVersionSet = false;
-    public static void setGlVersion(int glVersion) {
-        mGlVersionSet = true;
-        mGlVersion = glVersion;
-    }
-    public static void resetGlVersion() {
-        mGlVersionSet = false;
-        mGlVersion = 0;
-    }
-
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mView = new GLSurfaceView(this);
-        // Only set this if explicitly asked for
-        if (mGlVersionSet) {
-            mView.setEGLContextClientVersion(mGlVersion);
-        }
-        // Use no-op renderer by default
-        if (mRenderer == null) {
-            mView.setRenderer(new Renderer());
-        } else {
-            mView.setRenderer(mRenderer);
-        }
-        // Only set this if explicitly asked for
-        if (mRenderModeSet) {
-            mView.setRenderMode(mRenderMode);
-        }
+        mView.setRenderer(new Renderer());
         this.requestWindowFeature(Window.FEATURE_NO_TITLE);
         setContentView(mView);
     }
diff --git a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
index f603419..54547bd 100644
--- a/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/GLSurfaceViewTest.java
@@ -16,17 +16,24 @@
 
 package android.opengl.cts;
 
-
 import android.opengl.GLSurfaceView;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Tests for the GLSurfaceView class.
  */
-public class GLSurfaceViewTest extends
-        ActivityInstrumentationTestCase2<GLSurfaceViewCtsActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class GLSurfaceViewTest {
 
     private static final int NUM_PAUSE_RESUME_ITERATIONS_WITHOUT_DELAY = 1000;
 
@@ -40,14 +47,13 @@
 
     private GLSurfaceViewCtsActivity mActivity;
 
-    public GLSurfaceViewTest() {
-        super("android.graphics.cts", GLSurfaceViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<GLSurfaceViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GLSurfaceViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     /**
@@ -58,10 +64,9 @@
      * pause/resume sequences without crashing. The delay is used to allow
      * asynchronous events to occur in between the pause and resume operations.
      * </p>
-     *
-     * @throws InterruptedException
      */
     @UiThreadTest
+    @Test
     public void testPauseResumeWithDelay() throws InterruptedException {
         GLSurfaceView view = mActivity.getView();
         for (int i = 0; i < NUM_PAUSE_RESUME_ITERATIONS_WITH_DELAY; i++) {
@@ -87,6 +92,7 @@
      * </p>
      */
     @UiThreadTest
+    @Test
     public void testPauseResumeWithoutDelay() {
         GLSurfaceView view = mActivity.getView();
         for (int i = 0; i < NUM_PAUSE_RESUME_ITERATIONS_WITHOUT_DELAY; i++) {
diff --git a/tests/tests/graphics/src/android/opengl/cts/GlTestBase.java b/tests/tests/graphics/src/android/opengl/cts/GlTestBase.java
new file mode 100644
index 0000000..2350b40
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/GlTestBase.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.opengl.cts;
+
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.Timeout;
+
+import static android.opengl.EGL14.EGL_HEIGHT;
+import static android.opengl.EGL14.EGL_NONE;
+import static android.opengl.EGL14.EGL_NO_CONTEXT;
+import static android.opengl.EGL14.EGL_NO_DISPLAY;
+import static android.opengl.EGL14.EGL_NO_SURFACE;
+import static android.opengl.EGL14.EGL_SUCCESS;
+import static android.opengl.EGL14.EGL_WIDTH;
+import static android.opengl.EGL14.eglCreatePbufferSurface;
+import static android.opengl.EGL14.eglDestroySurface;
+import static android.opengl.EGL14.eglGetError;
+import static android.opengl.EGL14.eglMakeCurrent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+/**
+ * Test base for OpenGL ES 2+ tests. This test class initializes and
+ * cleanup EGL before and after each test. Subclasses MUST NOT use
+ * the AndroidJUnit4 runner but JUnit's BlockJUnit4ClassRunner to
+ * guarantee that all methods are run on the same thread (this would
+ * otherwise cause issues with EGL/GL's thread management).
+ *
+ * This implementation relies on EGL14. Do not use this class to
+ * test EGL10.
+ */
+public class GlTestBase {
+    private static EGLDisplay sEglDisplay;
+
+    private EGLContext mEglContext;
+    private EGLSurface mEglSurface;
+
+    @Rule
+    public Timeout mTimeout = new Timeout(2000);
+
+    @BeforeClass
+    public static void initEgl() {
+        sEglDisplay = Egl14Utils.createEglDisplay();
+        assertNotSame(EGL_NO_DISPLAY, sEglDisplay);
+    }
+
+    @AfterClass
+    public static void terminateEgl() {
+        Egl14Utils.releaseAndTerminate(sEglDisplay);
+    }
+
+    @Before
+    public void createContext() {
+        // Requesting OpenGL ES 2.0 context will return an ES 3.0 context on capable devices
+        EGLConfig eglConfig = Egl14Utils.getEglConfig(sEglDisplay, 2);
+        assertEquals(EGL_SUCCESS, eglGetError());
+
+        mEglContext = Egl14Utils.createEglContext(sEglDisplay, eglConfig, 2);
+        assertNotSame(EGL_NO_CONTEXT, eglConfig);
+
+        mEglSurface = eglCreatePbufferSurface(sEglDisplay, eglConfig, new int[] {
+                EGL_WIDTH, 1,
+                EGL_HEIGHT, 1,
+                EGL_NONE
+        }, 0);
+        assertNotSame(EGL_NO_SURFACE, mEglSurface);
+
+        eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext);
+        assertEquals(EGL_SUCCESS, eglGetError());
+    }
+
+    @After
+    public void cleanupContext() {
+        eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        eglDestroySurface(sEglDisplay, mEglSurface);
+        Egl14Utils.destroyEglContext(sEglDisplay, mEglContext);
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index 77c6da1..e930d7f 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -16,15 +16,27 @@
 
 package android.opengl.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -35,8 +47,9 @@
 /**
  * Test for checking whether the ro.opengles.version property is set to the correct value.
  */
-public class OpenGlEsVersionTest
-        extends ActivityInstrumentationTestCase2<OpenGlEsVersionCtsActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class OpenGlEsVersionTest {
 
     private static final String TAG = OpenGlEsVersionTest.class.getSimpleName();
 
@@ -47,37 +60,38 @@
 
     private OpenGlEsVersionCtsActivity mActivity;
 
-    public OpenGlEsVersionTest() {
-        super("android.graphics.cts", OpenGlEsVersionCtsActivity.class);
+    @Rule
+    public ActivityTestRule<OpenGlEsVersionCtsActivity> mActivityRule =
+            new ActivityTestRule<>(OpenGlEsVersionCtsActivity.class);
+
+    @Rule
+    public ActivityTestRule<OpenGlEsVersionCtsActivity> mActivityRelaunchRule =
+            new ActivityTestRule<>(OpenGlEsVersionCtsActivity.class, false, false);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testOpenGlEsVersion() throws InterruptedException {
         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);
+        verifyGlVersionString(1, 1);
         if (detectedMajorVersion == 2) {
             restartActivityWithClientVersion(2);
-            assertGlVersionString(2);
+            verifyGlVersionString(2, getMinorVersion(reportedVersion));
         } else if (detectedMajorVersion == 3) {
             restartActivityWithClientVersion(3);
-            assertGlVersionString(3);
+            verifyGlVersionString(3, getMinorVersion(reportedVersion));
         }
     }
 
+    @Test
     public void testRequiredExtensions() throws InterruptedException {
         int reportedVersion = getVersionFromActivityManager(mActivity);
         // We only have required extensions on ES3.1+
@@ -102,6 +116,7 @@
         }
     }
 
+    @Test
     public void testExtensionPack() throws InterruptedException {
         // Requirements:
         // 1. If the device claims support for the system feature, the extension must be available.
@@ -123,16 +138,14 @@
         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);
     }
 
+    @Test
     public void testOpenGlEsVersionForVrHighPerformance() throws InterruptedException {
         if (!supportsVrHighPerformance())
             return;
@@ -147,6 +160,7 @@
             (major == 3 && minor >= 2) || major > 3);
     }
 
+    @Test
     public void testRequiredExtensionsForVrHighPerformance() throws InterruptedException {
         if (!supportsVrHighPerformance())
             return;
@@ -288,29 +302,29 @@
     }
 
     /**
-     * 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 verifyGlVersionString(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. */
     private void restartActivityWithClientVersion(int version) {
         mActivity.finish();
-        setActivity(null);
 
-        try {
-            Intent intent = OpenGlEsVersionCtsActivity.createIntent(version);
-            setActivityIntent(intent);
-            mActivity = getActivity();
-        } finally {
-            setActivityIntent(null);
-        }
+        Intent intent = OpenGlEsVersionCtsActivity.createIntent(version);
+        mActivity = mActivityRelaunchRule.launchActivity(intent);
     }
 
     /**
diff --git a/tests/tests/graphics/src/android/opengl/cts/ParamsTest.java b/tests/tests/graphics/src/android/opengl/cts/ParamsTest.java
new file mode 100644
index 0000000..96fd81e
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/ParamsTest.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 android.opengl.cts;
+
+import android.support.test.filters.SmallTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import java.nio.IntBuffer;
+
+import static android.opengl.GLES20.glDeleteBuffers;
+import static android.opengl.GLES30.glGenBuffers;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for parameters validation.
+ */
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class) // DO NOT USE AndroidJUnit4, it messes up threading
+public class ParamsTest extends GlTestBase {
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullBufferParam() {
+        glGenBuffers(1, null);
+    }
+
+    @Test
+    public void testBufferParam() {
+        IntBuffer buffer = IntBuffer.allocate(1);
+        glGenBuffers(1, buffer);
+
+        assertTrue(buffer.get() > 0);
+
+        buffer.rewind();
+        glDeleteBuffers(1, buffer);
+    }
+}
diff --git a/tests/tests/graphics2/Android.mk b/tests/tests/graphics2/Android.mk
index daf3713..8cd0d5d 100644
--- a/tests/tests/graphics2/Android.mk
+++ b/tests/tests/graphics2/Android.mk
@@ -21,7 +21,9 @@
 # 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 += \
+     android-support-test \
+     ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/graphics2/AndroidTest.xml b/tests/tests/graphics2/AndroidTest.xml
index 2f9961b..0099848 100644
--- a/tests/tests/graphics2/AndroidTest.xml
+++ b/tests/tests/graphics2/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.graphics2.cts" />
+        <option name="runtime-hint" value="7m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
index 647fc30..402b204 100644
--- a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
+++ b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
@@ -27,18 +26,19 @@
 import android.view.TextureView;
 import android.view.View;
 
+import junit.framework.Assert;
+
 import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.Assert;
-
 
 public class TextureViewCameraActivity extends Activity implements
         TextureView.SurfaceTextureListener {
     private static final int CAPTURE_SCREEN_INTERVAL = 10;
     private static final float SCREEN_ROTATION_RATE = 1.0f;
     private static final int MAX_FRAME_UPDATE = 40;
+
     private Camera mCamera;
     private TextureView mTextureView;
     private int mUpdateCounter = 0;
diff --git a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewTest.java b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewTest.java
index c84919a..c68504c 100644
--- a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewTest.java
+++ b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewTest.java
@@ -16,33 +16,42 @@
 
 package android.graphics2.cts;
 
-import android.graphics2.cts.TextureViewCameraActivity;
+import static org.junit.Assert.assertTrue;
+
 import android.hardware.Camera;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.LargeTest;
+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;
 
-public class TextureViewTest extends ActivityInstrumentationTestCase2<TextureViewCameraActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TextureViewTest {
     private static final long WAIT_TIMEOUT_IN_SECS = 10;
+
     private TextureViewCameraActivity mActivity;
-    public TextureViewTest() {
-        super(TextureViewCameraActivity.class);
+    private int mNumberOfCameras;
+
+    @Rule
+    public ActivityTestRule<TextureViewCameraActivity> mActivityRule =
+            new ActivityTestRule<>(TextureViewCameraActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mNumberOfCameras = Camera.getNumberOfCameras();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        if (Camera.getNumberOfCameras() < 1) {
-            return;
-        }
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testTextureViewActivity() throws InterruptedException {
-        if (Camera.getNumberOfCameras() < 1) {
+        if (mNumberOfCameras < 1) {
             return;
         }
         assertTrue(mActivity.waitForCompletion(WAIT_TIMEOUT_IN_SECS));
     }
-
 }
 
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 69dbe2e..723a3f8 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -14,36 +14,6 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# Reusable Sensor test classes and helpers
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := cts-sensors-tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil
-
-LOCAL_JAVA_LIBRARIES := platform-test-annotations
-
-LOCAL_SDK_VERSION := current
-
-# TODO: sensors need to be refactored out into their own namespace: android.hardware.sensors.cts
-LOCAL_SRC_FILES := $(call all-java-files-under, src/android/hardware/cts/helpers)
-LOCAL_SRC_FILES += \
-    src/android/hardware/cts/SensorTestCase.java \
-    src/android/hardware/cts/SingleSensorTests.java \
-    src/android/hardware/cts/SensorIntegrationTests.java \
-    src/android/hardware/cts/SensorBatchingTests.java \
-    src/android/hardware/cts/SensorTest.java \
-    src/android/hardware/cts/SensorManagerStaticTest.java \
-    src/android/hardware/cts/SensorAdditionalInfoTest.java
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-
 # CtsHardwareTestCases package
 
 include $(CLEAR_VARS)
@@ -56,10 +26,9 @@
 LOCAL_COMPATIBILITY_SUITE := cts
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil \
     compatibility-device-util \
     ctstestrunner \
-    mockito-target \
+    mockito-target-minus-junit4 \
     android-ex-camera2
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 1e4cedf..7a98a2a 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -23,7 +23,6 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.BODY_SENSORS" />
     <uses-permission android:name="android.permission.TRANSMIT_IR" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.USE_FINGERPRINT" />
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index 3d42c87..e33ffa0 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -18,17 +18,10 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHardwareTestCases.apk" />
     </target_preparer>
-    <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
-    sensors -->
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="dumpsys sensorservice restrict .cts." />
-        <option name="teardown-command" value="dumpsys sensorservice enable" />
-    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.hardware.cts" />
-        <option name="runtime-hint" value="47m28s" />
+        <option name="runtime-hint" value="14s" />
         <!-- test-timeout unit is ms, value = 60 min -->
         <option name="test-timeout" value="3600000" />
     </test>
-
 </configuration>
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
old mode 100755
new mode 100644
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
deleted file mode 100644
index 2da6a3b..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ /dev/null
@@ -1,373 +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 android.hardware.cts.helpers;
-
-import junit.framework.Assert;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener2;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.util.Log;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
- * events or for a specific time, or waiting for a flush to complete. This class performs
- * verifications and will throw {@link AssertionError}s if there are any errors. It may also wrap
- * another {@link SensorEventListener2}.
- */
-public class TestSensorEventListener implements SensorEventListener2 {
-    public static final String LOG_TAG = "TestSensorEventListener";
-
-    private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
-    private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
-
-    private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<>();
-    private final ArrayList<Long> mTimeStampFlushCompleteEvents = new ArrayList<>();
-    private final List<CountDownLatch> mEventLatches = new ArrayList<>();
-    private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
-    private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
-
-    private final Handler mHandler;
-    private final TestSensorEnvironment mEnvironment;
-
-    // Wakelock for keeping the system running after terminate criterion is met.
-    // Useful for CtsVerifier test cases in which cpu can sleep if usb is not connected.
-    private final PowerManager.WakeLock mTestSensorEventListenerWakeLock;
-
-    /**
-     * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
-     */
-    @Deprecated
-    public TestSensorEventListener() {
-        this(null /* environment */);
-    }
-
-    /**
-     * Construct a {@link TestSensorEventListener}.
-     */
-    public TestSensorEventListener(TestSensorEnvironment environment) {
-        this(environment, null /* handler */);
-    }
-
-    /**
-     * Construct a {@link TestSensorEventListener}.
-     */
-    public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
-        mEnvironment = environment;
-        mHandler = handler;
-        PowerManager pm = (PowerManager) environment.getContext().getSystemService(
-                Context.POWER_SERVICE);
-        mTestSensorEventListenerWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                "TestSensorEventListenerWakeLock");
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onSensorChanged(SensorEvent event) {
-        long timestampNs = SystemClock.elapsedRealtimeNanos();
-        checkHandler();
-        synchronized (mCollectedEvents) {
-            mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
-        }
-        synchronized (mEventLatches) {
-            for (CountDownLatch latch : mEventLatches) {
-                latch.countDown();
-                if (latch.getCount() == 0 && !mTestSensorEventListenerWakeLock.isHeld()) {
-                    mTestSensorEventListenerWakeLock.acquire();
-                }
-            }
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        checkHandler();
-    }
-
-    /**
-     * @param eventCount
-     * @return A CountDownLatch initialzed with eventCount and decremented as sensor events arrive
-     * for this listerner.
-     */
-    public CountDownLatch getLatchForSensorEvents(int eventCount) {
-        CountDownLatch latch = new CountDownLatch(eventCount);
-        synchronized (mEventLatches) {
-            mEventLatches.add(latch);
-        }
-        return latch;
-    }
-
-    /**
-     * @return A CountDownLatch initialzed with 1 and decremented as a flush complete arrives
-     * for this listerner.
-     */
-    public CountDownLatch getLatchForFlushCompleteEvent() {
-        CountDownLatch latch = new CountDownLatch(1);
-        synchronized (mFlushLatches) {
-            mFlushLatches.add(latch);
-        }
-        return latch;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFlushCompleted(Sensor sensor) {
-        checkHandler();
-        long timestampNs = SystemClock.elapsedRealtimeNanos();
-        synchronized (mTimeStampFlushCompleteEvents) {
-           mTimeStampFlushCompleteEvents.add(timestampNs);
-        }
-        synchronized (mFlushLatches) {
-            for (CountDownLatch latch : mFlushLatches) {
-                latch.countDown();
-            }
-        }
-    }
-
-    /**
-     * @return The handler (if any) associated with the instance.
-     */
-    public Handler getHandler() {
-        return mHandler;
-    }
-
-    /**
-     * @return A list of {@link TestSensorEvent}s collected by the listener.
-     */
-    public List<TestSensorEvent> getCollectedEvents() {
-        synchronized (mCollectedEvents){
-            return Collections.unmodifiableList((List<TestSensorEvent>) mCollectedEvents.clone());
-        }
-    }
-
-    /**
-     * Clears the internal list of collected {@link TestSensorEvent}s.
-     */
-    public void clearEvents() {
-        synchronized (mCollectedEvents) {
-            mCollectedEvents.clear();
-        }
-    }
-
-
-    /**
-     * Utility method to log the collected events to a file.
-     * It will overwrite the file if it already exists, the file is created in a relative directory
-     * named 'events' under the sensor test directory (part of external storage).
-     */
-    public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs,
-            long testStartTimeMs, long testStopTimeMs)
-        throws IOException {
-        StringBuilder builder = new StringBuilder();
-        builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
-        builder.append("SamplingRateOverloaded=")
-                .append(mEnvironment.isSensorSamplingRateOverloaded()).append(", ");
-        builder.append("RequestedSamplingPeriod=")
-                .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
-        builder.append("MaxReportLatency=")
-                .append(mEnvironment.getMaxReportLatencyUs()).append("us, ");
-        builder.append("StartedTimestamp=")
-                .append(testStartTimeMs).append("ms, ");
-        builder.append("StoppedTimestamp=")
-                .append(testStopTimeMs).append("ms");
-        synchronized (mCollectedEvents) {
-            int i = 0, j = 0;
-            while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
-                if (mCollectedEvents.get(i).receivedTimestamp <
-                        mTimeStampFlushCompleteEvents.get(j)) {
-                    TestSensorEvent event = mCollectedEvents.get(i);
-                    if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
-                            event.receivedTimestamp/1000000) {
-                        builder.append("\n");
-                        builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
-                        deviceWakeUpTimeMs = -1;
-                    }
-                    builder.append("\n");
-                    builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
-                    builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
-                        append("ms, ");
-                    builder.append("Accuracy=").append(event.accuracy).append(", ");
-                    builder.append("Values=").append(Arrays.toString(event.values));
-                    ++i;
-                } else {
-                    builder.append("\n");
-                    builder.append("ReceivedTimestamp=")
-                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
-                    .append("ms Flush complete Event");
-                    ++j;
-                }
-            }
-            for (;i < mCollectedEvents.size(); ++i) {
-                TestSensorEvent event = mCollectedEvents.get(i);
-                if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
-                        event.receivedTimestamp/1000000) {
-                    builder.append("\n");
-                    builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
-                    deviceWakeUpTimeMs = -1;
-                }
-                builder.append("\n");
-                builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
-                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
-                    append("ms, ");
-                builder.append("Accuracy=").append(event.accuracy).append(", ");
-                builder.append("Values=").append(Arrays.toString(event.values));
-            }
-            for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
-                builder.append("\n");
-                builder.append("ReceivedTimestamp=")
-                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
-                    .append("ms Flush complete Event");
-            }
-        }
-
-        File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
-        File logFile = new File(eventsDirectory, fileName);
-        FileWriter fileWriter = new FileWriter(logFile, false /* append */);
-        try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
-            writer.write(builder.toString());
-        }
-    }
-
-    /**
-     * Wait for {@link #onFlushCompleted(Sensor)} to be called.
-     *
-     * A wake lock may be acquired at the return if operation is successful. Do
-     * {@link releaseWakeLock()} if the wakelock is not necessary.
-     *
-     * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
-     */
-    public void waitForFlushComplete(CountDownLatch latch,
-                                      boolean clearCollectedEvents) throws InterruptedException {
-        if (clearCollectedEvents) {
-            clearEvents();
-        }
-        try {
-            String message = SensorCtsHelper.formatAssertionMessage(
-                    "WaitForFlush",
-                    mEnvironment,
-                    "timeout=%dus",
-                    FLUSH_TIMEOUT_US);
-            Assert.assertTrue(message, latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
-        } finally {
-            synchronized (mFlushLatches) {
-                mFlushLatches.remove(latch);
-            }
-        }
-    }
-
-    /**
-     * Collect a specific number of {@link TestSensorEvent}s.
-     *
-     * A wake lock may be acquired at the return if operation is successful. Do
-     * {@link releaseWakeLock()} if the wakelock is not necessary.
-     *
-     * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
-     */
-    public void waitForEvents(CountDownLatch latch, int eventCount,
-                               boolean clearCollectedEvents) throws InterruptedException {
-        if (clearCollectedEvents) {
-            clearEvents();
-        }
-        try {
-            long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
-            // timeout is 2 * event count * expected period + batch timeout + default wait
-            // we multiply by two as not to raise an error in this function even if the events are
-            // streaming at a lower rate than expected, as long as it's not streaming twice as slow
-            // as expected
-            long timeoutUs = (2 * eventCount * samplingPeriodUs)
-                    + mEnvironment.getMaxReportLatencyUs()
-                    + EVENT_TIMEOUT_US;
-            boolean success = latch.await(timeoutUs, TimeUnit.MICROSECONDS);
-            if (!success) {
-                String message = SensorCtsHelper.formatAssertionMessage(
-                        "WaitForEvents",
-                        mEnvironment,
-                        "requested=%d, received=%d, timeout=%dus",
-                        eventCount,
-                        eventCount - latch.getCount(),
-                        timeoutUs);
-                Assert.fail(message);
-            }
-        } finally {
-            synchronized (mEventLatches) {
-                mEventLatches.remove(latch);
-            }
-        }
-    }
-
-    /**
-     * Collect {@link TestSensorEvent} for a specific duration.
-     */
-    public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
-        SensorCtsHelper.sleep(duration, timeUnit);
-    }
-
-    /**
-     * Asserts that sensor events arrived in the proper thread if a {@link Handler} was associated
-     * with the current instance.
-     *
-     * If no events were received this assertion will be evaluated to {@code true}.
-     */
-    public void assertEventsReceivedInHandler() {
-        int eventsOutsideHandler = mEventsReceivedOutsideHandler.get();
-        String message = String.format(
-                "Events arrived outside the associated Looper. Expected=0, Found=%d",
-                eventsOutsideHandler);
-        Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
-    }
-
-    public void releaseWakeLock() {
-        if (mTestSensorEventListenerWakeLock.isHeld()) {
-            mTestSensorEventListenerWakeLock.release();
-        }
-    }
-
-    /**
-     * Keeps track of the number of events that arrived in a different {@link Looper} than the one
-     * associated with the {@link TestSensorEventListener}.
-     */
-    private void checkHandler() {
-        if (mHandler != null && mHandler.getLooper() != Looper.myLooper()) {
-            mEventsReceivedOutsideHandler.incrementAndGet();
-        }
-    }
-}
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
index 2decd12..74045d5 100644
--- a/tests/tests/icu/AndroidTest.xml
+++ b/tests/tests/icu/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -24,6 +25,6 @@
         <option name="instrumentation-arg" key="core-root-classes"
                 value="android.icu.cts.coverage.TestAll,android.icu.dev.test.TestAll" />
         <option name="core-expectation" value="/android/icu/cts/expectations/icu-known-failures.txt" />
-        <option name="runtime-hint" value="30m19s" />
+        <option name="runtime-hint" value="18m30s" />
     </test>
 </configuration>
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index d62a97e..7672d2f 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 := \
   libjninamespacea1 \
diff --git a/tests/tests/jni/AndroidTest.xml b/tests/tests/jni/AndroidTest.xml
index 8ec1df6..c1746de 100644
--- a/tests/tests/jni/AndroidTest.xml
+++ b/tests/tests/jni/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.jni.cts" />
+        <option name="runtime-hint" value="12m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
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 8fe7a3b..68828ac 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -28,7 +28,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
         android-support-test \
         core-tests-support \
-        ctsdeviceutil \
+        compatibility-device-util \
         ctstestrunner \
         guava
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/Asn1Utils.java b/tests/tests/keystore/src/android/keystore/cts/Asn1Utils.java
index 131dbcd..5e75fa7 100644
--- a/tests/tests/keystore/src/android/keystore/cts/Asn1Utils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/Asn1Utils.java
@@ -30,6 +30,8 @@
 import com.android.org.bouncycastle.asn1.DEROctetString;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.String;
 import java.math.BigInteger;
 import java.security.cert.CertificateParsingException;
 import java.util.Date;
@@ -68,6 +70,15 @@
         return derOctectString.getOctets();
     }
 
+    public static ASN1Encodable getAsn1EncodableFromBytes(byte[] bytes)
+            throws CertificateParsingException {
+        try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
+            return asn1InputStream.readObject();
+        } catch (IOException e) {
+            throw new CertificateParsingException("Failed to parse Encodable", e);
+        }
+    }
+
     public static ASN1Sequence getAsn1SequenceFromBytes(byte[] bytes)
             throws CertificateParsingException {
         try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
@@ -109,6 +120,17 @@
         return builder.build();
     }
 
+    public static String getStringFromAsn1OctetStreamAssumingUTF8(ASN1Encodable encodable)
+            throws CertificateParsingException, UnsupportedEncodingException {
+        if (!(encodable instanceof ASN1OctetString)) {
+            throw new CertificateParsingException(
+                    "Expected octet string, found " + encodable.getClass().getName());
+        }
+
+        ASN1OctetString octetString = (ASN1OctetString) encodable;
+        return new String(octetString.getOctets(), "UTF-8");
+    }
+
     public static Date getDateFromAsn1(ASN1Primitive value) throws CertificateParsingException {
         return new Date(getLongFromAsn1(value));
     }
diff --git a/tests/tests/keystore/src/android/keystore/cts/AttestationApplicationId.java b/tests/tests/keystore/src/android/keystore/cts/AttestationApplicationId.java
new file mode 100644
index 0000000..42f8ea7
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AttestationApplicationId.java
@@ -0,0 +1,182 @@
+/*
+ * 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.keystore.cts;
+
+import com.android.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.org.bouncycastle.asn1.ASN1Set;
+
+import java.security.cert.CertificateParsingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+
+public class AttestationApplicationId implements java.lang.Comparable<AttestationApplicationId> {
+    private static final int PACKAGE_INFOS_INDEX = 0;
+    private static final int SIGNATURE_DIGESTS_INDEX = 1;
+
+    private final List<AttestationPackageInfo> packageInfos;
+    private final List<byte[]> signatureDigests;
+
+    public AttestationApplicationId(Context context)
+            throws NoSuchAlgorithmException, NameNotFoundException {
+        PackageManager pm = context.getPackageManager();
+        int uid = context.getApplicationInfo().uid;
+        String[] packageNames = pm.getPackagesForUid(uid);
+        if (packageNames == null || packageNames.length == 0) {
+            throw new NameNotFoundException("No names found for uid");
+        }
+        packageInfos = new ArrayList<AttestationPackageInfo>();
+        for (String packageName : packageNames) {
+            // get the package info for the given package name including
+            // the signatures
+            PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+            packageInfos.add(new AttestationPackageInfo(packageName, packageInfo.versionCode));
+        }
+        // The infos must be sorted, the implementation of Comparable relies on it.
+        packageInfos.sort(null);
+
+        // compute the sha256 digests of the signature blobs
+        signatureDigests = new ArrayList<byte[]>();
+        PackageInfo packageInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
+        for (Signature signature : packageInfo.signatures) {
+            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+            signatureDigests.add(sha256.digest(signature.toByteArray()));
+        }
+        // The digests must be sorted. the implementation of Comparable relies on it
+        signatureDigests.sort(new ByteArrayComparator());
+    }
+
+    public AttestationApplicationId(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Sequence)) {
+            throw new CertificateParsingException(
+                    "Expected sequence for AttestationApplicationId, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+        packageInfos = parseAttestationPackageInfos(sequence.getObjectAt(PACKAGE_INFOS_INDEX));
+        // The infos must be sorted, the implementation of Comparable relies on it.
+        packageInfos.sort(null);
+        signatureDigests = parseSignatures(sequence.getObjectAt(SIGNATURE_DIGESTS_INDEX));
+        // The digests must be sorted. the implementation of Comparable relies on it
+        signatureDigests.sort(new ByteArrayComparator());
+    }
+
+    public List<AttestationPackageInfo> getAttestationPackageInfos() {
+        return packageInfos;
+    }
+
+    public List<byte[]> getSignatureDigests() {
+        return signatureDigests;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("AttestationApplicationId:");
+        int noOfInfos = packageInfos.size();
+        int i = 1;
+        for (AttestationPackageInfo info : packageInfos) {
+            sb.append("\n### Package info " + i + "/" + noOfInfos + " ###\n");
+            sb.append(info);
+        }
+        i = 1;
+        int noOfSigs = signatureDigests.size();
+        for (byte[] sig : signatureDigests) {
+            sb.append("\nSignature digest " + i++ + "/" + noOfSigs + ":");
+            for (byte b : sig) {
+                sb.append(String.format(" %02X", b));
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public int compareTo(AttestationApplicationId other) {
+        int res = Integer.compare(packageInfos.size(), other.packageInfos.size());
+        if (res != 0) return res;
+        for (int i = 0; i < packageInfos.size(); ++i) {
+            res = packageInfos.get(i).compareTo(other.packageInfos.get(i));
+            if (res != 0) return res;
+        }
+        res = Integer.compare(signatureDigests.size(), other.signatureDigests.size());
+        if (res != 0) return res;
+        ByteArrayComparator cmp = new ByteArrayComparator();
+        for (int i = 0; i < signatureDigests.size(); ++i) {
+            res = cmp.compare(signatureDigests.get(i), other.signatureDigests.get(i));
+            if (res != 0) return res;
+        }
+        return res;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof AttestationApplicationId)
+                && (0 == compareTo((AttestationApplicationId) o));
+    }
+
+    private List<AttestationPackageInfo> parseAttestationPackageInfos(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Set)) {
+            throw new CertificateParsingException(
+                    "Expected set for AttestationApplicationsInfos, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Set set = (ASN1Set) asn1Encodable;
+        List<AttestationPackageInfo> result = new ArrayList<AttestationPackageInfo>();
+        for (ASN1Encodable e : set) {
+            result.add(new AttestationPackageInfo(e));
+        }
+        return result;
+    }
+
+    private List<byte[]> parseSignatures(ASN1Encodable asn1Encodable)
+            throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Set)) {
+            throw new CertificateParsingException("Expected set for Signature digests, found "
+                    + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Set set = (ASN1Set) asn1Encodable;
+        List<byte[]> result = new ArrayList<byte[]>();
+
+        for (ASN1Encodable e : set) {
+            result.add(Asn1Utils.getByteArrayFromAsn1(e));
+        }
+        return result;
+    }
+
+    private class ByteArrayComparator implements java.util.Comparator<byte[]> {
+        @Override
+        public int compare(byte[] a, byte[] b) {
+            int res = Integer.compare(a.length, b.length);
+            if (res != 0) return res;
+            for (int i = 0; i < a.length; ++i) {
+                res = Byte.compare(a[i], b[i]);
+                if (res != 0) return res;
+            }
+            return res;
+        }
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AttestationPackageInfo.java b/tests/tests/keystore/src/android/keystore/cts/AttestationPackageInfo.java
new file mode 100644
index 0000000..294fda8
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AttestationPackageInfo.java
@@ -0,0 +1,83 @@
+/*
+ * 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.keystore.cts;
+
+import com.android.org.bouncycastle.asn1.ASN1Encodable;
+import com.android.org.bouncycastle.asn1.ASN1Sequence;
+
+import java.security.cert.CertificateParsingException;
+
+import java.io.UnsupportedEncodingException;
+
+public class AttestationPackageInfo implements java.lang.Comparable<AttestationPackageInfo> {
+    private static final int PACKAGE_NAME_INDEX = 0;
+    private static final int VERSION_INDEX = 1;
+
+    private final String packageName;
+    private final int version;
+
+    public AttestationPackageInfo(String packageName, int version) {
+        this.packageName = packageName;
+        this.version = version;
+    }
+
+    public AttestationPackageInfo(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+        if (!(asn1Encodable instanceof ASN1Sequence)) {
+            throw new CertificateParsingException(
+                    "Expected sequence for AttestationPackageInfo, found "
+                            + asn1Encodable.getClass().getName());
+        }
+
+        ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
+        try {
+            packageName = Asn1Utils.getStringFromAsn1OctetStreamAssumingUTF8(
+                    sequence.getObjectAt(PACKAGE_NAME_INDEX));
+        } catch (UnsupportedEncodingException e) {
+            throw new CertificateParsingException(
+                    "Converting octet stream to String triggered an UnsupportedEncodingException",
+                    e);
+        }
+        version = Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERSION_INDEX));
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder().append("Package name: ").append(getPackageName())
+                .append("\nVersion: " + getVersion()).toString();
+    }
+
+    @Override
+    public int compareTo(AttestationPackageInfo other) {
+        int res = packageName.compareTo(other.packageName);
+        if (res != 0) return res;
+        res = Integer.compare(version, other.version);
+        if (res != 0) return res;
+        return res;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof AttestationPackageInfo)
+                && (0 == compareTo((AttestationPackageInfo) o));
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AuthorizationList.java b/tests/tests/keystore/src/android/keystore/cts/AuthorizationList.java
index 36aa6b6..d488b26 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AuthorizationList.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AuthorizationList.java
@@ -32,6 +32,7 @@
 import com.android.org.bouncycastle.asn1.ASN1Sequence;
 import com.android.org.bouncycastle.asn1.ASN1SequenceParser;
 import com.android.org.bouncycastle.asn1.ASN1TaggedObject;
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
 
 import java.io.IOException;
 import java.security.cert.CertificateParsingException;
@@ -118,6 +119,7 @@
     private static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
     private static final int KM_TAG_OS_VERSION = KM_UINT | 705;
     private static final int KM_TAG_OS_PATCHLEVEL = KM_UINT | 706;
+    private static final int KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709;
 
     // Map for converting padding values to strings
     private static final ImmutableMap<Integer, String> paddingMap = ImmutableMap
@@ -172,6 +174,7 @@
     private RootOfTrust rootOfTrust;
     private Integer osVersion;
     private Integer osPatchLevel;
+    private AttestationApplicationId attestationApplicationId;
 
     public AuthorizationList(ASN1Encodable sequence) throws CertificateParsingException {
         if (!(sequence instanceof ASN1Sequence)) {
@@ -253,6 +256,10 @@
                 case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK:
                     rootOfTrust = new RootOfTrust(value);
                     break;
+                case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
+                    attestationApplicationId = new AttestationApplicationId(Asn1Utils
+                            .getAsn1EncodableFromBytes(Asn1Utils.getByteArrayFromAsn1(value)));
+                    break;
                 case KM_TAG_ALL_APPLICATIONS & KEYMASTER_TAG_TYPE_MASK:
                     allApplications = true;
                     break;
@@ -481,6 +488,10 @@
         return osPatchLevel;
     }
 
+    public AttestationApplicationId getAttestationApplicationId() {
+        return attestationApplicationId;
+    }
+
     @Override
     public String toString() {
         StringBuilder s = new StringBuilder();
@@ -562,6 +573,9 @@
             s.append("\nOS Patchlevel: ").append(osPatchLevel);
         }
 
+        if (attestationApplicationId != null) {
+            s.append("\nAttestation Application Id:").append(attestationApplicationId);
+        }
         return s.toString();
     }
 }
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 130a9ee..4c27d0e 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -50,7 +50,7 @@
 import static org.junit.matchers.JUnitMatchers.hasItems;
 
 import com.google.common.collect.ImmutableSet;
-
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.security.KeyStoreException;
@@ -457,8 +457,18 @@
         }
     }
 
+    private void checkAttestationApplicationId(Attestation attestation)
+            throws NoSuchAlgorithmException, NameNotFoundException {
+        AttestationApplicationId aaid = null;
+        assertNull(attestation.getTeeEnforced().getAttestationApplicationId());
+        aaid = attestation.getSoftwareEnforced().getAttestationApplicationId();
+        assertNotNull(aaid);
+        assertEquals(new AttestationApplicationId(getContext()), aaid);
+    }
+
     private void checkKeyIndependentAttestationInfo(byte[] challenge, int purposes, Date startTime,
-            boolean includesValidityDates, Attestation attestation) {
+            boolean includesValidityDates, Attestation attestation)
+            throws NoSuchAlgorithmException, NameNotFoundException {
         checkAttestationSecurityLevelDependentParams(attestation);
         assertNotNull(attestation.getAttestationChallenge());
         assertTrue(Arrays.equals(challenge, attestation.getAttestationChallenge()));
@@ -470,6 +480,7 @@
         checkValidityPeriod(attestation, startTime, includesValidityDates);
         checkFlags(attestation);
         checkOrigin(attestation);
+        checkAttestationApplicationId(attestation);
     }
 
     private int getSystemPatchLevel() {
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
index caa6336..77cde44 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
@@ -61,26 +61,6 @@
         }
     }
 
-    public void testGetPrivateKeyOnMainThreadFails() throws InterruptedException {
-        final CountDownLatch waiter = new CountDownLatch(1);
-        new Handler(getContext().getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    KeyChain.getPrivateKey(getContext(), "");
-                    fail("IllegalStateException was expected for calling "
-                            + "KeyChain.getPrivateKey(Context, String) on main thread");
-                } catch (IllegalStateException expected) {
-                } catch (Exception invalid) {
-                    fail("Expected IllegalStateException, received " + invalid);
-                } finally {
-                    waiter.countDown();
-                }
-            }
-        });
-        waiter.await();
-    }
-
     /**
      * Tests whether the required algorithms are backed by a Keymaster HAL that
      * binds the key material to the specific device it was created or imported
diff --git a/tests/tests/libcorefileio/AndroidTest.xml b/tests/tests/libcorefileio/AndroidTest.xml
index 9baa713..e21d3a2 100644
--- a/tests/tests/libcorefileio/AndroidTest.xml
+++ b/tests/tests/libcorefileio/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.libcorefileio.cts" />
+        <option name="runtime-hint" value="14m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/libcorelegacy22/AndroidTest.xml b/tests/tests/libcorelegacy22/AndroidTest.xml
index cdc6611..a313035 100644
--- a/tests/tests/libcorelegacy22/AndroidTest.xml
+++ b/tests/tests/libcorelegacy22/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.libcorelegacy22.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index 6a8b9d3..bfd9a08 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil ctstestrunner
+    compatibility-device-util ctstestrunner
 
 LOCAL_SDK_VERSION := test_current
 
@@ -47,7 +47,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/location/src/android/location/cts/BaseMockLocationTest.java b/tests/tests/location/src/android/location/cts/BaseMockLocationTest.java
index 14019be..7b08da8 100644
--- a/tests/tests/location/src/android/location/cts/BaseMockLocationTest.java
+++ b/tests/tests/location/src/android/location/cts/BaseMockLocationTest.java
@@ -16,7 +16,8 @@
 
 package android.location.cts;
 
-import android.cts.util.LocationUtils;
+import com.android.compatibility.common.util.LocationUtils;
+
 import android.test.InstrumentationTestCase;
 
 /**
diff --git a/tests/tests/location2/AndroidTest.xml b/tests/tests/location2/AndroidTest.xml
index 5829249..31f4684 100644
--- a/tests/tests/location2/AndroidTest.xml
+++ b/tests/tests/location2/AndroidTest.xml
@@ -21,6 +21,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.location2.cts" />
+        <option name="runtime-hint" value="10m30s" />
     </test>
 
 </configuration>
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index eda78e8..1886093 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 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/AndroidTest.xml b/tests/tests/media/AndroidTest.xml
index 070ab28..08ee0a0 100644
--- a/tests/tests/media/AndroidTest.xml
+++ b/tests/tests/media/AndroidTest.xml
@@ -27,6 +27,6 @@
         <option name="package" value="android.media.cts" />
         <!-- test-timeout unit is ms, value = 30 min -->
         <option name="test-timeout" value="1800000" />
-        <option name="runtime-hint" value="3h45m" />
+        <option name="runtime-hint" value="4h" />
     </test>
 </configuration>
diff --git a/tests/tests/media/assets/image_exif_byte_order_ii.jpg b/tests/tests/media/assets/image_exif_byte_order_ii.jpg
deleted file mode 100644
index 477cd3a..0000000
--- a/tests/tests/media/assets/image_exif_byte_order_ii.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/assets/image_exif_byte_order_mm.jpg b/tests/tests/media/assets/image_exif_byte_order_mm.jpg
deleted file mode 100644
index 78ac703..0000000
--- a/tests/tests/media/assets/image_exif_byte_order_mm.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/assets/lg_g4_iso_800.dng b/tests/tests/media/assets/lg_g4_iso_800.dng
deleted file mode 100644
index 5fcc720..0000000
--- a/tests/tests/media/assets/lg_g4_iso_800.dng
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/binary_counter_320x240_30fps_600frames.mp4 b/tests/tests/media/res/raw/binary_counter_320x240_30fps_600frames.mp4
new file mode 100644
index 0000000..6609614
--- /dev/null
+++ b/tests/tests/media/res/raw/binary_counter_320x240_30fps_600frames.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/image_exif_byte_order_ii.jpg b/tests/tests/media/res/raw/image_exif_byte_order_ii.jpg
deleted file mode 100644
index 477cd3a..0000000
--- a/tests/tests/media/res/raw/image_exif_byte_order_ii.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/image_exif_byte_order_mm.jpg b/tests/tests/media/res/raw/image_exif_byte_order_mm.jpg
deleted file mode 100644
index 78ac703..0000000
--- a/tests/tests/media/res/raw/image_exif_byte_order_mm.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/lg_g4_iso_800.dng b/tests/tests/media/res/raw/lg_g4_iso_800.dng
deleted file mode 100644
index 5fcc720..0000000
--- a/tests/tests/media/res/raw/lg_g4_iso_800.dng
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro.3gp b/tests/tests/media/res/raw/video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro.3gp
new file mode 100644
index 0000000..1fa3474
--- /dev/null
+++ b/tests/tests/media/res/raw/video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro.3gp
Binary files differ
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index bc34177..338e9fc 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -90,8 +90,8 @@
         <item>0.0040</item>
         <item>0.0</item>
         <item>442/100</item>
-        <item>0/1</item>
-        <item>0</item>
+        <item />
+        <item />
         <item>1970:01:17</item>
         <item>53/1,50/1,423/100</item>
         <item>N</item>
@@ -105,4 +105,304 @@
         <item>1</item>
         <item>0</item>
     </array>
+    <array name="volantis_jpg">
+        <item>false</item>
+        <item>0</item>
+        <item>0</item>
+        <item>true</item>
+        <item>37.423</item>
+        <item>-122.162</item>
+        <item>0.0</item>
+        <item>htc</item>
+        <item>Nexus 9</item>
+        <item>1.2904</item>
+        <item>2016:03:09 17:36:42</item>
+        <item>0.0083</item>
+        <item>64</item>
+        <item>3097/1000</item>
+        <item />
+        <item />
+        <item>2016:03:09</item>
+        <item>37/1,25/1,2291/100</item>
+        <item>N</item>
+        <item>122/1,9/1,4330/100</item>
+        <item>W</item>
+        <item />
+        <item>08:35:34</item>
+        <item>720</item>
+        <item>1280</item>
+        <item>175</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+    <array name="sony_rx_100_arw">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>SONY</item>
+        <item>DSC-RX100M3</item>
+        <item>2.0000</item>
+        <item>2015:01:15 16:49:05</item>
+        <item>0.0050</item>
+        <item>16.0</item>
+        <item>880/100</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3648</item>
+        <item>5472</item>
+        <item>125</item>
+        <item>8</item>
+        <item>0</item>
+    </array>
+    <array name="canon_g7x_cr2">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>Canon</item>
+        <item>Canon PowerShot G7 X</item>
+        <item>8.0000</item>
+        <item>2015:01:15 16:53:05</item>
+        <item>0.0005</item>
+        <item>16.0</item>
+        <item>8800/1000</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3648</item>
+        <item>5472</item>
+        <item>12800</item>
+        <item>8</item>
+        <item>1</item>
+    </array>
+    <array name="fuji_x20_raf">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>FUJIFILM</item>
+        <item>X20</item>
+        <item>3.6000</item>
+        <item>2015:01:15 18:20:53</item>
+        <item>0.0130</item>
+        <item>16.0</item>
+        <item>1040/100</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3000</item>
+        <item>4000</item>
+        <item>100</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+    <array name="nikon_1aw1_nef">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>true</item>
+        <item>53.83652</item>
+        <item>10.69828</item>
+        <item>0.0</item>
+        <item>NIKON CORPORATION</item>
+        <item>NIKON 1 AW1</item>
+        <item>5.6000</item>
+        <item>2015:10:27 14:10:12</item>
+        <item>0.0080</item>
+        <item>0</item>
+        <item>275/10</item>
+        <item />
+        <item />
+        <item>2015:10:27</item>
+        <item>53/1,501915/10000,0/1</item>
+        <item>N</item>
+        <item>10/1,418974/10000,0/1</item>
+        <item>E</item>
+        <item />
+        <item>13:10:12</item>
+        <item>3072</item>
+        <item>4608</item>
+        <item>200</item>
+        <item>8</item>
+        <item>0</item>
+    </array>
+    <array name="nikon_p330_nrw">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>true</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>NIKON</item>
+        <item>COOLPIX P7800</item>
+        <item>2.0000</item>
+        <item>2015:02:17 14:24:21</item>
+        <item>0.0005</item>
+        <item>16.0</item>
+        <item>60/10</item>
+        <item>0/1</item>
+        <item>0</item>
+        <item>0000:00:00</item>
+        <item>0/1,0/1,0/1</item>
+        <item />
+        <item>0/1,0/1,0/1</item>
+        <item />
+        <item />
+        <item>00:00:00</item>
+        <item>3000</item>
+        <item>4000</item>
+        <item>3200</item>
+        <item>8</item>
+        <item>0</item>
+    </array>
+    <array name="pentax_k5_pef">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>PENTAX</item>
+        <item>PENTAX K-5</item>
+        <item>8.0000</item>
+        <item>2013:11:05 23:07:10</item>
+        <item>0.1250</item>
+        <item>16.0</item>
+        <item>2625/100</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3284</item>
+        <item>4992</item>
+        <item>100</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+    <array name="olympus_e_pl3_orf">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>OLYMPUS IMAGING CORP.</item>
+        <item>E-PL3</item>
+        <item>8.0000</item>
+        <item>2013:05:15 11:04:46</item>
+        <item>0.0400</item>
+        <item>24.0</item>
+        <item>45/1</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>2272</item>
+        <item>3024</item>
+        <item>200</item>
+        <item>1</item>
+        <item>0</item>
+    </array>
+    <array name="panasonic_gm5_rw2">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>Panasonic</item>
+        <item>DMC-GM5</item>
+        <item>8.0000</item>
+        <item>2015:01:14 17:06:04</item>
+        <item>0.0500</item>
+        <item>16.0</item>
+        <item>160/10</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3448</item>
+        <item>4592</item>
+        <item>200</item>
+        <item>8</item>
+        <item>1</item>
+    </array>
+    <array name="samsung_nx3000_srw">
+        <item>true</item>
+        <item>160</item>
+        <item>120</item>
+        <item>false</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>0.0</item>
+        <item>SAMSUNG</item>
+        <item>NX3000</item>
+        <item>5.6000</item>
+        <item>2016:01:14 12:45:32</item>
+        <item>0.1670</item>
+        <item>0</item>
+        <item>50/1</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>3648</item>
+        <item>5472</item>
+        <item>100</item>
+        <item>8</item>
+        <item>0</item>
+    </array>
 </resources>
diff --git a/tests/tests/media/res/values/strings.xml b/tests/tests/media/res/values/strings.xml
new file mode 100644
index 0000000..b01b8ec
--- /dev/null
+++ b/tests/tests/media/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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>
+    <string name="test_user_route_name">User route\'s name for test</string>
+    <string name="test_route_category_name">Route category\'s name for test</string>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/AudioAttributesTest.java b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
index 99ab1ab..58f5313 100644
--- a/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
@@ -16,10 +16,11 @@
 
 package android.media.cts;
 
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioAttributes;
 import android.os.Parcel;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 public class AudioAttributesTest extends CtsAndroidTestCase {
 
     // -----------------------------------------------------------------
diff --git a/tests/tests/media/src/android/media/cts/AudioFormatTest.java b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
index 100e3b4..e37f64e 100644
--- a/tests/tests/media/src/android/media/cts/AudioFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
@@ -16,10 +16,11 @@
 
 package android.media.cts;
 
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.os.Parcel;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 public class AudioFormatTest extends CtsAndroidTestCase {
 
     // -----------------------------------------------------------------
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerStub.java b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
index 947acec..9e0c74c 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerStub.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
@@ -19,7 +19,6 @@
 import android.media.cts.R;
 
 import android.app.Activity;
-import android.cts.util.CTSResult;
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioManager;
@@ -27,11 +26,18 @@
 import android.media.MediaPlayer;
 import android.os.Bundle;
 
+import com.android.compatibility.common.util.CTSResult;
+
 public class AudioManagerStub extends Activity {
     private final int MP3_TO_PLAY = R.raw.testmp3;
     private MediaPlayer mMediaPlayer;
     private AudioManager mAudioManager;
     private static CTSResult mCTSResult;
+    private static final int[] STREAM_TYPES = {
+            AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM,
+            AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM,
+            AudioManager.STREAM_NOTIFICATION, AudioManager.STREAM_DTMF,
+            AudioManager.STREAM_ACCESSIBILITY };
 
     public static void setCTSResult(CTSResult cr) {
         mCTSResult = cr;
@@ -51,7 +57,7 @@
     protected void onPause() {
         super.onPause();
         try {
-            for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+            for (int i : STREAM_TYPES) {
                 mAudioManager.setStreamMute(i, false);
                 mAudioManager.setStreamSolo(i, false);
             }
@@ -65,7 +71,7 @@
     protected void onResume() {
         super.onResume();
         try {
-            for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+            for (int i : STREAM_TYPES) {
                 mAudioManager.setStreamMute(i, true);
                 mAudioManager.setStreamSolo(i, true);
             }
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index c32be5c..a1754d1 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -468,7 +468,8 @@
             int[] streams = {AudioManager.STREAM_ALARM,
                     AudioManager.STREAM_MUSIC,
                     AudioManager.STREAM_VOICE_CALL,
-                    AudioManager.STREAM_RING};
+                    AudioManager.STREAM_RING,
+                    AudioManager.STREAM_ACCESSIBILITY};
 
             mAudioManager.adjustVolume(ADJUST_RAISE, 0);
             mAudioManager.adjustSuggestedStreamVolume(
diff --git a/tests/tests/media/src/android/media/cts/AudioNativeTest.java b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
index 7301cc7..c4861ad 100644
--- a/tests/tests/media/src/android/media/cts/AudioNativeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
@@ -19,10 +19,11 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 public class AudioNativeTest extends CtsAndroidTestCase {
     public static final int MAX_CHANNEL_COUNT = 2;
     public static final int MAX_INDEX_MASK = (1 << MAX_CHANNEL_COUNT) - 1;
diff --git a/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java b/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java
index 6156095..a05698d 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlayRoutingNative.java
@@ -19,13 +19,13 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.content.Context;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.AudioRouting;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.ndkaudio.AudioPlayer;
 
 import java.lang.annotation.Retention;
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordNative.java b/tests/tests/media/src/android/media/cts/AudioRecordNative.java
index 3c7632e..d6e8f6d 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordNative.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordNative.java
@@ -18,9 +18,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.cts.util.CtsAndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index b1455bd..78a13a0 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioRecord;
@@ -34,6 +33,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
index 1de6302..665bfa1 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
@@ -17,13 +17,14 @@
 package android.media.cts;
 
 import android.content.pm.PackageManager;
-import android.cts.util.PollingCheck;
 import android.media.AudioFormat;
 import android.media.AudioRecord;
 import android.media.MediaRecorder.AudioSource;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index 7c1bb37..e42f4e2 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -17,7 +17,6 @@
 package android.media.cts;
 
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -28,6 +27,8 @@
 import android.os.Parcel;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
index cf1a406..f82e1c5 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -28,6 +27,8 @@
 import android.media.PlaybackParams;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import java.nio.ByteBuffer;
 import java.nio.FloatBuffer;
 import java.nio.ShortBuffer;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackNative.java b/tests/tests/media/src/android/media/cts/AudioTrackNative.java
index 54746ae..065dd3a 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackNative.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackNative.java
@@ -18,9 +18,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.cts.util.CtsAndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
index a1a2f3a..7c81816 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
@@ -22,7 +22,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
@@ -31,6 +30,8 @@
 import android.media.AudioTrack;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import java.io.BufferedInputStream;
 import java.io.InputStream;
 import java.util.ArrayList;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index ad103bd..13484b2 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -28,6 +27,7 @@
 import android.media.PlaybackParams;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
index 971bfb3..04666f4 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
@@ -16,7 +16,6 @@
 
 package android.media.cts;
 
-import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
@@ -25,6 +24,7 @@
 import android.os.Looper;
 import android.os.Message;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
diff --git a/tests/tests/media/src/android/media/cts/CodecUtils.java b/tests/tests/media/src/android/media/cts/CodecUtils.java
index 5b56f6f..1097f41 100644
--- a/tests/tests/media/src/android/media/cts/CodecUtils.java
+++ b/tests/tests/media/src/android/media/cts/CodecUtils.java
@@ -16,18 +16,22 @@
 
 package android.media.cts;
 
+import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.media.cts.CodecImage;
 import android.media.Image;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecList;
+import android.os.Environment;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.security.MessageDigest;
-import java.util.ArrayList;
 
 public class CodecUtils  {
     private static final String TAG = "CodecUtils";
@@ -226,5 +230,35 @@
         }
         return result.toString();
     }
+
+    /**
+     * This method reads the binarybar code on the top row of a bitmap. Each 16x16
+     * block is one digit, with black=0 and white=1. LSB is on the left.
+     */
+    public static int readBinaryCounterFromBitmap(Bitmap bitmap) {
+        int numDigits = bitmap.getWidth() / 16;
+        int counter = 0;
+        for (int i = 0; i < numDigits; i++) {
+            int rgb = bitmap.getPixel(i * 16 + 8, 8);
+            if (Color.red(rgb) > 128) {
+                counter |= (1 << i);
+            }
+        }
+        return counter;
+    }
+
+    public static void saveBitmapToFile(Bitmap bitmap, String filename) {
+        try {
+            File outputFile = new File(Environment.getExternalStorageDirectory(), filename);
+
+            Log.d(TAG, "Saving bitmap to: " + outputFile);
+            FileOutputStream outputStream = new FileOutputStream(outputFile);
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);
+            outputStream.flush();
+            outputStream.close();
+        } catch(Exception e) {
+            Log.e(TAG, "Failed to save to file: " + e);
+        }
+    }
 }
 
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
index 9b1dc81..bbbbb3f 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -19,13 +19,14 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.cts.util.MediaUtils;
 import android.graphics.Bitmap;
 import android.media.MediaFormat;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.view.View;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
index 5600312..ead1201 100644
--- a/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.media.cts.CodecUtils;
 import android.media.Image;
 import android.media.MediaCodec;
@@ -32,6 +31,7 @@
 import android.util.Range;
 
 import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MediaUtils;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 3025306..08d8d74 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -22,7 +22,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.media.cts.CodecUtils;
 import android.media.Image;
@@ -39,6 +38,7 @@
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import com.android.compatibility.common.util.MediaUtils;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 
diff --git a/tests/tests/media/src/android/media/cts/DecoderTestAacDrc.java b/tests/tests/media/src/android/media/cts/DecoderTestAacDrc.java
index 131cb55..997967c 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTestAacDrc.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTestAacDrc.java
@@ -21,7 +21,6 @@
 import android.app.Instrumentation;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.cts.DecoderTest.AudioParameter;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
@@ -31,6 +30,8 @@
 import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 import static org.junit.Assert.*;
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index f70f83a..2fc04f2 100755
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -16,7 +16,6 @@
 
 package android.media.cts;
 
-import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.media.Image;
 import android.media.MediaCodec;
@@ -24,9 +23,13 @@
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.opengl.GLES20;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -34,7 +37,6 @@
 
 import javax.microedition.khronos.opengles.GL10;
 
-
 /**
  * Generates a series of video frames, encodes them, decodes them, and tests for significant
  * divergence from the original.
@@ -47,6 +49,8 @@
  * file, and read it back in from disk.  The data we're generating is just an elementary
  * stream, so we'd need to perform additional steps to make that happen.
  */
+@SmallTest
+@RequiresDevice
 public class EncodeDecodeTest extends AndroidTestCase {
     private static final String TAG = "EncodeDecodeTest";
     private static final boolean VERBOSE = false;           // lots of logging
@@ -390,7 +394,7 @@
                 return;
             }
             if (VERBOSE) Log.d(TAG, "found codec: " + codec);
-            
+
             String codec_decoder = mcl.findDecoderForFormat(format);
             if (codec_decoder == null) {
                 Log.e(TAG, "Unable to find an appropriate codec for " + format);
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java
index 48fcb65..9a3392a 100755
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java
@@ -29,6 +29,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -59,6 +61,8 @@
  * The test puts up a series of colored screens, expecting to see all of them, and in order.
  * Any black screens that appear before or after are ignored.
  */
+@SmallTest
+@RequiresDevice
 public class EncodeVirtualDisplayTest extends AndroidTestCase {
     private static final String TAG = "EncodeVirtualTest";
     private static final boolean VERBOSE = false;           // lots of logging
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index c42dad5..9dbcd5e 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -43,6 +43,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -76,6 +78,8 @@
  * detect any issues. The test itself does not check the output as it is already done in other
  * tests.
  */
+@SmallTest
+@RequiresDevice
 public class EncodeVirtualDisplayWithCompositionTest extends AndroidTestCase {
     private static final String TAG = "EncodeVirtualDisplayWithCompositionTest";
     private static final boolean DBG = true;
@@ -419,52 +423,55 @@
                 Log.i(TAG, "start encoding");
             }
             EncodingHelper encodingHelper = new EncodingHelper();
-            mEncodingSurface = encodingHelper.startEncoding(maxSize.getWidth(), maxSize.getHeight(),
-                    mEncoderEventListener);
-            GlCompositor compositor = new GlCompositor();
-            if (DBG) {
-                Log.i(TAG, "start composition");
-            }
-            compositor.startComposition(mEncodingSurface, maxSize.getWidth(), maxSize.getHeight(),
-                    numDisplays);
-            for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+            try {
+                mEncodingSurface = encodingHelper.startEncoding(
+                        maxSize.getWidth(), maxSize.getHeight(), mEncoderEventListener);
+                GlCompositor compositor = new GlCompositor();
                 if (DBG) {
-                    Log.i(TAG, "create display");
+                    Log.i(TAG, "start composition");
                 }
-                for (int k = 0; k < numDisplays; k++) {
-                    virtualDisplays[k] =
-                        new VirtualDisplayPresentation(getContext(),
-                                compositor.getWindowSurface(k),
-                                maxSize.getWidth()/numDisplays, maxSize.getHeight());
-                    virtualDisplays[k].createVirtualDisplay();
-                    virtualDisplays[k].createPresentation();
-                }
-                if (DBG) {
-                    Log.i(TAG, "start rendering");
-                }
-                for (int k = 0; k < NUM_RENDERING; k++) {
-                    for (int l = 0; l < numDisplays; l++) {
-                        virtualDisplays[l].doRendering(COLOR_RED);
+                compositor.startComposition(mEncodingSurface,
+                        maxSize.getWidth(), maxSize.getHeight(), numDisplays);
+                for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+                    if (DBG) {
+                        Log.i(TAG, "create display");
                     }
-                    // do not care how many frames are actually rendered.
-                    Thread.sleep(1);
+                    for (int k = 0; k < numDisplays; k++) {
+                        virtualDisplays[k] =
+                            new VirtualDisplayPresentation(getContext(),
+                                    compositor.getWindowSurface(k),
+                                    maxSize.getWidth()/numDisplays, maxSize.getHeight());
+                        virtualDisplays[k].createVirtualDisplay();
+                        virtualDisplays[k].createPresentation();
+                    }
+                    if (DBG) {
+                        Log.i(TAG, "start rendering");
+                    }
+                    for (int k = 0; k < NUM_RENDERING; k++) {
+                        for (int l = 0; l < numDisplays; l++) {
+                            virtualDisplays[l].doRendering(COLOR_RED);
+                        }
+                        // do not care how many frames are actually rendered.
+                        Thread.sleep(1);
+                    }
+                    for (int k = 0; k < numDisplays; k++) {
+                        virtualDisplays[k].dismissPresentation();
+                        virtualDisplays[k].destroyVirtualDisplay();
+                    }
+                    compositor.recreateWindows();
                 }
-                for (int k = 0; k < numDisplays; k++) {
-                    virtualDisplays[k].dismissPresentation();
-                    virtualDisplays[k].destroyVirtualDisplay();
+                if (DBG) {
+                    Log.i(TAG, "stop composition");
                 }
-                compositor.recreateWindows();
+                compositor.stopComposition();
+            } finally {
+                if (DBG) {
+                    Log.i(TAG, "stop encoding");
+                }
+                encodingHelper.stopEncoding();
+                assertTrue(mCodecConfigReceived);
+                assertTrue(mCodecBufferReceived);
             }
-            if (DBG) {
-                Log.i(TAG, "stop composition");
-            }
-            compositor.stopComposition();
-            if (DBG) {
-                Log.i(TAG, "stop encoding");
-            }
-            encodingHelper.stopEncoding();
-            assertTrue(mCodecConfigReceived);
-            assertTrue(mCodecBufferReceived);
         }
     }
 
@@ -549,15 +556,15 @@
                 throw new RuntimeException("encoder "+ MIME_TYPE + " not support : " + format.toString());
             }
 
-            mEncoder = MediaCodec.createByCodecName(codecName);
-            mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
-            mEncodingSurface = mEncoder.createInputSurface();
-            mEncoder.start();
-            mInitCompleted.release();
-            if (DBG) {
-                Log.i(TAG, "starting encoder");
-            }
             try {
+                mEncoder = MediaCodec.createByCodecName(codecName);
+                mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+                mEncodingSurface = mEncoder.createInputSurface();
+                mEncoder.start();
+                mInitCompleted.release();
+                if (DBG) {
+                    Log.i(TAG, "starting encoder");
+                }
                 ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
                 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                 while (!mStopEncoding) {
@@ -592,11 +599,15 @@
                 e.printStackTrace();
                 throw e;
             } finally {
-                mEncoder.stop();
-                mEncoder.release();
-                mEncoder = null;
-                mEncodingSurface.release();
-                mEncodingSurface = null;
+                if (mEncoder != null) {
+                    mEncoder.stop();
+                    mEncoder.release();
+                    mEncoder = null;
+                }
+                if (mEncodingSurface != null) {
+                    mEncodingSurface.release();
+                    mEncodingSurface = null;
+                }
             }
         }
     }
diff --git a/tests/tests/media/src/android/media/cts/EncoderTest.java b/tests/tests/media/src/android/media/cts/EncoderTest.java
index e086347..cf2e8f6 100644
--- a/tests/tests/media/src/android/media/cts/EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/EncoderTest.java
@@ -19,7 +19,6 @@
 import android.media.cts.R;
 
 import android.content.Context;
-import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
@@ -28,6 +27,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.InputStream;
 import java.nio.BufferOverflowException;
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index c346dad..2d94e91 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -28,10 +28,12 @@
 import android.system.OsConstants;
 
 import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.IOException;
 import java.lang.reflect.Type;
@@ -45,14 +47,24 @@
 
     private static final double DIFFERENCE_TOLERANCE = .001;
 
-    // List of files.
+    private static final String EXTERNAL_BASE_DIRECTORY = "/test/images/";
+
+    // This base directory is needed for the files listed below.
+    // These files will be available for download in Android O release.
+    // Link: https://source.android.com/compatibility/cts/downloads.html#cts-media-files
     private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
     private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
     private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
-    private static final int[] IMAGE_RESOURCES = new int[] {
-            R.raw.image_exif_byte_order_ii,  R.raw.image_exif_byte_order_mm, R.raw.lg_g4_iso_800 };
-    private static final String[] IMAGE_FILENAMES = new String[] {
-            EXIF_BYTE_ORDER_II_JPEG, EXIF_BYTE_ORDER_MM_JPEG, LG_G4_ISO_800_DNG };
+    private static final String SONY_RX_100_ARW = "sony_rx_100.arw";
+    private static final String CANON_G7X_CR2 = "canon_g7x.cr2";
+    private static final String FUJI_X20_RAF = "fuji_x20.raf";
+    private static final String NIKON_1AW1_NEF = "nikon_1aw1.nef";
+    private static final String NIKON_P330_NRW = "nikon_p330.nrw";
+    private static final String OLYMPUS_E_PL3_ORF = "olympus_e_pl3.orf";
+    private static final String PANASONIC_GM5_RW2 = "panasonic_gm5.rw2";
+    private static final String PENTAX_K5_PEF = "pentax_k5.pef";
+    private static final String SAMSUNG_NX3000_SRW = "samsung_nx3000.srw";
+    private static final String VOLANTIS_JPEG = "volantis.jpg";
 
     private static final String[] EXIF_TAGS = {
             ExifInterface.TAG_MAKE,
@@ -160,55 +172,13 @@
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
-            String outputPath = new File(Environment.getExternalStorageDirectory(),
-                    IMAGE_FILENAMES[i]).getAbsolutePath();
-            try (InputStream inputStream = getContext().getResources().openRawResource(
-                    IMAGE_RESOURCES[i])) {
-                try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {
-                    Streams.copy(inputStream, outputStream);
-                }
-            }
-        }
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
-            String imageFilePath = new File(Environment.getExternalStorageDirectory(),
-                    IMAGE_FILENAMES[i]).getAbsolutePath();
-            File imageFile = new File(imageFilePath);
-            if (imageFile.exists()) {
-                imageFile.delete();
-            }
-        }
-
-        super.tearDown();
-    }
-
-    public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
-        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_II_JPEG, R.array.exifbyteorderii_jpg);
-    }
-
-    public void testReadExifDataFromExifByteOrderMMJpeg() throws Throwable {
-        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_MM_JPEG, R.array.exifbyteordermm_jpg);
-    }
-
-    public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
-        testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
-    }
-
     private void printExifTagsAndValues(String fileName, ExifInterface exifInterface) {
         // Prints thumbnail information.
         if (exifInterface.hasThumbnail()) {
-            byte[] thumbnailBytes = exifInterface.getThumbnail();
+            byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
             if (thumbnailBytes != null) {
                 Log.v(TAG, fileName + " Thumbnail size = " + thumbnailBytes.length);
-                Bitmap bitmap = BitmapFactory.decodeByteArray(
-                        thumbnailBytes, 0, thumbnailBytes.length);
+                Bitmap bitmap = exifInterface.getThumbnailBitmap();
                 if (bitmap == null) {
                     Log.e(TAG, fileName + " Corrupted thumbnail!");
                 } else {
@@ -220,7 +190,7 @@
                         + "A thumbnail is expected.");
             }
         } else {
-            if (exifInterface.getThumbnail() != null) {
+            if (exifInterface.getThumbnailBytes() != null) {
                 Log.e(TAG, fileName + " Unexpected result: A thumbnail was found. "
                         + "No thumbnail is expected.");
             } else {
@@ -261,6 +231,8 @@
         if (stringValue != null) {
             stringValue = stringValue.trim();
         }
+        stringValue = (stringValue == "") ? null : stringValue;
+
         assertEquals(expectedValue, stringValue);
     }
 
@@ -272,10 +244,9 @@
         // Checks a thumbnail image.
         assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
         if (expectedValue.hasThumbnail) {
-            byte[] thumbnailBytes = exifInterface.getThumbnail();
+            byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
             assertNotNull(thumbnailBytes);
-            Bitmap thumbnailBitmap =
-                    BitmapFactory.decodeByteArray(thumbnailBytes, 0, thumbnailBytes.length);
+            Bitmap thumbnailBitmap = exifInterface.getThumbnailBitmap();
             assertNotNull(thumbnailBitmap);
             assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
             assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
@@ -320,8 +291,9 @@
         assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
     }
 
-    private void testExifInterfaceCommon(File imageFile, ExpectedValue expectedValue)
+    private void testExifInterfaceCommon(String fileName, ExpectedValue expectedValue)
             throws IOException {
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
         String verboseTag = imageFile.getName();
 
         // Creates via path.
@@ -329,18 +301,8 @@
         assertNotNull(exifInterface);
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
 
-        // Creates from an asset file.
         InputStream in = null;
-        try {
-            in = getContext().getAssets().open(imageFile.getName());
-            exifInterface = new ExifInterface(in);
-            compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-
         // Creates via InputStream.
-        in = null;
         try {
             in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
             exifInterface = new ExifInterface(in);
@@ -362,8 +324,9 @@
         }
     }
 
-    private void testSaveAttributes_withFileName(File imageFile, ExpectedValue expectedValue)
+    private void testSaveAttributes_withFileName(String fileName, ExpectedValue expectedValue)
             throws IOException {
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
         String verboseTag = imageFile.getName();
 
         ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
@@ -384,8 +347,9 @@
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
     }
 
-    private void testSaveAttributes_withFileDescriptor(File imageFile, ExpectedValue expectedValue)
+    private void testSaveAttributes_withFileDescriptor(String fileName, ExpectedValue expectedValue)
             throws IOException {
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
         String verboseTag = imageFile.getName();
 
         FileDescriptor fd = null;
@@ -417,48 +381,95 @@
         }
     }
 
-    private void testSaveAttributes_withInputStream(File imageFile, ExpectedValue expectedValue)
-            throws IOException {
-        InputStream in = null;
-        try {
-            in = getContext().getAssets().open(imageFile.getName());
-            ExifInterface exifInterface = new ExifInterface(in);
-            exifInterface.saveAttributes();
-        } catch (IOException e) {
-            // Expected. saveAttributes is not supported with an ExifInterface object which was
-            // created with InputStream.
-            return;
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-        fail("Should not reach here!");
-    }
-
     private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
             throws IOException {
         ExpectedValue expectedValue = new ExpectedValue(
                 getContext().getResources().obtainTypedArray(typedArrayResourceId));
-        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
 
-        // Test for reading from various inputs.
-        testExifInterfaceCommon(imageFile, expectedValue);
+        // Test for reading from external data storage.
+        fileName = EXTERNAL_BASE_DIRECTORY + fileName;
+        testExifInterfaceCommon(fileName, expectedValue);
 
         // Test for saving attributes.
-        testSaveAttributes_withFileName(imageFile, expectedValue);
-        testSaveAttributes_withFileDescriptor(imageFile, expectedValue);
-        testSaveAttributes_withInputStream(imageFile, expectedValue);
+        testSaveAttributes_withFileName(fileName, expectedValue);
+        testSaveAttributes_withFileDescriptor(fileName, expectedValue);
     }
 
     private void testExifInterfaceForRaw(String fileName, int typedArrayResourceId)
             throws IOException {
         ExpectedValue expectedValue = new ExpectedValue(
                 getContext().getResources().obtainTypedArray(typedArrayResourceId));
-        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
 
-        // Test for reading from various inputs.
-        testExifInterfaceCommon(imageFile, expectedValue);
+        // Test for reading from external data storage.
+        fileName = EXTERNAL_BASE_DIRECTORY + fileName;
+        testExifInterfaceCommon(fileName, expectedValue);
 
         // Since ExifInterface does not support for saving attributes for RAW files, do not test
         // about writing back in here.
     }
+
+    public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
+        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_II_JPEG, R.array.exifbyteorderii_jpg);
+    }
+
+    public void testReadExifDataFromExifByteOrderMMJpeg() throws Throwable {
+        testExifInterfaceForJpeg(EXIF_BYTE_ORDER_MM_JPEG, R.array.exifbyteordermm_jpg);
+    }
+
+    public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
+        testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
+    }
+
+    public void testDoNotFailOnCorruptedImage() throws Throwable {
+        // To keep the compatibility with old versions of ExifInterface, even on a corrupted image,
+        // it shouldn't raise any exceptions except an IOException when unable to open a file.
+        byte[] bytes = new byte[1024];
+        try {
+            new ExifInterface(new ByteArrayInputStream(bytes));
+            // Always success
+        } catch (IOException e) {
+            fail("Should not reach here!");
+        }
+    }
+
+    public void testReadExifDataFromVolantisJpg() throws Throwable {
+        // Test if it is possible to parse the volantis generated JPEG smoothly.
+        testExifInterfaceForJpeg(VOLANTIS_JPEG, R.array.volantis_jpg);
+    }
+
+    public void testReadExifDataFromSonyRX100Arw() throws Throwable {
+        testExifInterfaceForRaw(SONY_RX_100_ARW, R.array.sony_rx_100_arw);
+    }
+
+    public void testReadExifDataFromCanonG7XCr2() throws Throwable {
+        testExifInterfaceForRaw(CANON_G7X_CR2, R.array.canon_g7x_cr2);
+    }
+
+    public void testReadExifDataFromFujiX20Raf() throws Throwable {
+        testExifInterfaceForRaw(FUJI_X20_RAF, R.array.fuji_x20_raf);
+    }
+
+    public void testReadExifDataFromNikon1AW1Nef() throws Throwable {
+        testExifInterfaceForRaw(NIKON_1AW1_NEF, R.array.nikon_1aw1_nef);
+    }
+
+    public void testReadExifDataFromNikonP330Nrw() throws Throwable {
+        testExifInterfaceForRaw(NIKON_P330_NRW, R.array.nikon_p330_nrw);
+    }
+
+    public void testReadExifDataFromOlympusEPL3Orf() throws Throwable {
+        testExifInterfaceForRaw(OLYMPUS_E_PL3_ORF, R.array.olympus_e_pl3_orf);
+    }
+
+    public void testReadExifDataFromPanasonicGM5Rw2() throws Throwable {
+        testExifInterfaceForRaw(PANASONIC_GM5_RW2, R.array.panasonic_gm5_rw2);
+    }
+
+    public void testReadExifDataFromPentaxK5Pef() throws Throwable {
+        testExifInterfaceForRaw(PENTAX_K5_PEF, R.array.pentax_k5_pef);
+    }
+
+    public void testReadExifDataFromSamsungNX3000Srw() throws Throwable {
+        testExifInterfaceForRaw(SAMSUNG_NX3000_SRW, R.array.samsung_nx3000_srw);
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
index f1b2972..dcac8f0 100644
--- a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
@@ -22,7 +22,6 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
-import android.cts.util.MediaUtils;
 import android.graphics.Rect;
 import android.graphics.ImageFormat;
 import android.media.cts.CodecUtils;
@@ -45,6 +44,8 @@
 
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
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..75fc1dd 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -16,12 +16,14 @@
 package android.media.cts;
 
 import android.content.ComponentName;
-import android.cts.util.PollingCheck;
 import android.media.browse.MediaBrowser;
 import android.media.browse.MediaBrowser.MediaItem;
 import android.os.Bundle;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.PollingCheck;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -30,6 +32,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 +69,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 +134,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 +183,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 +240,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..557e41c 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -16,7 +16,6 @@
 package android.media.cts;
 
 import android.content.pm.PackageManager;
-import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.AudioCapabilities;
@@ -37,6 +36,7 @@
 import android.util.Log;
 
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.IOException;
 import java.util.HashSet;
@@ -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/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index a223348..c19523b 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -19,7 +19,6 @@
 import android.media.cts.R;
 
 import android.content.res.AssetFileDescriptor;
-import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
 import android.media.MediaCodec.CodecException;
@@ -34,10 +33,14 @@
 import android.opengl.GLES20;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.view.Surface;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -56,6 +59,8 @@
  * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
  * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
  */
+@SmallTest
+@RequiresDevice
 public class MediaCodecTest extends AndroidTestCase {
     private static final String TAG = "MediaCodecTest";
     private static final boolean VERBOSE = false;           // lots of logging
@@ -82,6 +87,13 @@
     private boolean mAudioEncoderHadError = false;
     private volatile boolean mVideoEncodingOngoing = false;
 
+    private static final int INPUT_RESOURCE_ID =
+            R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
+
+    // The test should fail if the decoder never produces output frames for the input.
+    // Time out decoding, as we have no way to query whether the decoder will produce output.
+    private static final int DECODING_TIMEOUT_MS = 10000;
+
     /**
      * Tests:
      * <br> Exceptions for MediaCodec factory methods
@@ -144,6 +156,8 @@
             return false;
         }
 
+        final boolean isVideoEncoder = isEncoder && mimeType.startsWith("video/");
+
         // create codec (enter Initialized State)
         MediaCodec codec;
 
@@ -238,14 +252,34 @@
                 fail("createInputSurface should not work on a decoder");
             }
         } catch (IllegalStateException e) { // expected for decoder and audio encoder
-            if (isEncoder && format.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+            if (isVideoEncoder) {
                 throw e;
             }
         }
 
+        // test getInputBuffers before start()
+        try {
+            ByteBuffer[] buffers = codec.getInputBuffers();
+            fail("getInputBuffers called before start() should throw exception");
+        } catch (IllegalStateException e) { // expected
+        }
+
         // start codec (enter Executing state)
         codec.start();
 
+        // test getInputBuffers after start()
+        try {
+            ByteBuffer[] buffers = codec.getInputBuffers();
+            if (buffers == null) {
+                fail("getInputBuffers called after start() should not return null");
+            }
+            if (isVideoEncoder && buffers.length > 0) {
+                fail("getInputBuffers returned non-zero length array with input surface");
+            }
+        } catch (IllegalStateException e) {
+            fail("getInputBuffers called after start() shouldn't throw exception");
+        }
+
         // test a few commands
         try {
             codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
@@ -521,6 +555,103 @@
         callbackThread.join();
     }
 
+    public void testAsyncFlushAndReset() throws Exception, InterruptedException {
+        testAsyncReset(false /* testStop */);
+    }
+
+    public void testAsyncStopAndReset() throws Exception, InterruptedException {
+        testAsyncReset(true /* testStop */);
+    }
+
+    private void testAsyncReset(boolean testStop) throws Exception, InterruptedException {
+        // Test video and audio 10x each
+        for (int i = 0; i < 10; i++) {
+            testAsyncReset(false /* audio */, (i % 2) == 0 /* swap */, testStop);
+        }
+        for (int i = 0; i < 10; i++) {
+            testAsyncReset(true /* audio */, (i % 2) == 0 /* swap */, testStop);
+        }
+    }
+
+    /*
+     * This method simulates a race between flush (or stop) and reset() called from
+     * two threads. Neither call should get stuck. This should be run multiple rounds.
+     */
+    private void testAsyncReset(boolean audio, boolean swap, final boolean testStop)
+            throws Exception, InterruptedException {
+        String mimeTypePrefix  = audio ? "audio/" : "video/";
+        final MediaExtractor mediaExtractor = getMediaExtractorForMimeType(
+                INPUT_RESOURCE_ID, mimeTypePrefix);
+        MediaFormat mediaFormat = mediaExtractor.getTrackFormat(
+                mediaExtractor.getSampleTrackIndex());
+        if (!MediaUtils.checkDecoderForFormat(mediaFormat)) {
+            return; // skip
+        }
+
+        OutputSurface outputSurface = audio ? null : new OutputSurface(1, 1);
+        final Surface surface = outputSurface == null ? null : outputSurface.getSurface();
+
+        String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
+        final MediaCodec mediaCodec = MediaCodec.createDecoderByType(mimeType);
+
+        try {
+            mediaCodec.configure(mediaFormat, surface, null /* crypto */, 0 /* flags */);
+
+            mediaCodec.start();
+
+            assertTrue(runDecodeTillFirstOutput(mediaCodec, mediaExtractor));
+
+            Thread flushingThread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (testStop) {
+                            mediaCodec.stop();
+                        } else {
+                            mediaCodec.flush();
+                        }
+                    } catch (IllegalStateException e) {
+                        // This is okay, since we're simulating a race between flush and reset.
+                        // If reset executed first, flush could fail.
+                    }
+                }
+            });
+
+            Thread resettingThread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    mediaCodec.reset();
+                }
+            });
+
+            // start flushing (or stopping) and resetting in two threads
+            if (swap) {
+                flushingThread.start();
+                resettingThread.start();
+            } else {
+                resettingThread.start();
+                flushingThread.start();
+            }
+
+            // wait for at most 5 sec, and check if the thread exits properly
+            flushingThread.join(5000);
+            assertFalse(flushingThread.isAlive());
+
+            resettingThread.join(5000);
+            assertFalse(resettingThread.isAlive());
+        } finally {
+            if (mediaCodec != null) {
+                mediaCodec.release();
+            }
+            if (mediaExtractor != null) {
+                mediaExtractor.release();
+            }
+            if (outputSurface != null) {
+                outputSurface.release();
+            }
+        }
+    }
+
     private static class FlushThread extends Thread {
         final MediaCodec mEncoder;
         final CountDownLatch mBuffersExhausted;
@@ -856,13 +987,6 @@
     }
 
     private void testDecodeAfterFlush(final boolean audio) throws InterruptedException {
-        final int INPUT_RESOURCE_ID =
-                R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
-
-        // The test should fail if the decoder never produces output frames for the input.
-        // Time out decoding, as we have no way to query whether the decoder will produce output.
-        final int DECODING_TIMEOUT_MS = 10000;
-
         final AtomicBoolean completed = new AtomicBoolean(false);
         Thread decodingThread = new Thread(new Runnable() {
             @Override
@@ -1520,7 +1644,7 @@
             if (!encoder && info.isEncoder()) {
                 continue;
             }
-            
+
             for (String type : info.getSupportedTypes()) {
                 if (type.equalsIgnoreCase(mimeType)) {
                     return true;
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index b8ec617..9ec4956 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -15,11 +15,13 @@
  */
 package android.media.cts;
 
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
 import android.media.session.PlaybackState.CustomAction;
 import android.net.Uri;
 import android.os.Bundle;
@@ -52,6 +54,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();
@@ -240,9 +258,40 @@
             assertTrue(mCallback.mOnPrepareFromUriCalled);
             assertEquals(uri, mCallback.mUri);
             assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
+
+            mCallback.reset();
+            final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
+            controls.setRepeatMode(repeatMode);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnSetRepeatModeCalled);
+            assertEquals(repeatMode, mCallback.mRepeatMode);
+
+            mCallback.reset();
+            final boolean shuffleModeEnabled = true;
+            controls.setShuffleModeEnabled(shuffleModeEnabled);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnSetShuffleModeEnabledCalled);
+            assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
         }
     }
 
+    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;
@@ -254,6 +303,8 @@
         private String mCommand;
         private Bundle mExtras;
         private ResultReceiver mCommandCallback;
+        private int mRepeatMode;
+        private boolean mShuffleModeEnabled;
 
         private boolean mOnPlayCalled;
         private boolean mOnPauseCalled;
@@ -274,6 +325,8 @@
         private boolean mOnPrepareFromMediaIdCalled;
         private boolean mOnPrepareFromSearchCalled;
         private boolean mOnPrepareFromUriCalled;
+        private boolean mOnSetRepeatModeCalled;
+        private boolean mOnSetShuffleModeEnabledCalled;
 
         public void reset() {
             mSeekPosition = -1;
@@ -286,6 +339,8 @@
             mExtras = null;
             mCommand = null;
             mCommandCallback = null;
+            mShuffleModeEnabled = false;
+            mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
 
             mOnPlayCalled = false;
             mOnPauseCalled = false;
@@ -306,6 +361,8 @@
             mOnPrepareFromMediaIdCalled = false;
             mOnPrepareFromSearchCalled = false;
             mOnPrepareFromUriCalled = false;
+            mOnSetRepeatModeCalled = false;
+            mOnSetShuffleModeEnabledCalled = false;
         }
 
         @Override
@@ -415,7 +472,7 @@
         @Override
         public void onCustomAction(String action, Bundle extras) {
             synchronized (mWaitLock) {
-                mOnCustomActionCalled= true;
+                mOnCustomActionCalled = true;
                 mAction = action;
                 mExtras = extras;
                 mWaitLock.notify();
@@ -479,5 +536,23 @@
                 mWaitLock.notify();
             }
         }
+
+        @Override
+        public void onSetRepeatMode(int repeatMode) {
+            synchronized (mWaitLock) {
+                mOnSetRepeatModeCalled = true;
+                mRepeatMode = repeatMode;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onSetShuffleModeEnabled(boolean enabled) {
+            synchronized (mWaitLock) {
+                mOnSetShuffleModeEnabledCalled = true;
+                mShuffleModeEnabled = enabled;
+                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/MediaMetadataRetrieverTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
index 890073c..22f2481 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataRetrieverTest.java
@@ -20,14 +20,29 @@
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.media.MediaDataSource;
 import android.media.MediaMetadataRetriever;
+import android.graphics.Bitmap;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.compatibility.common.util.MediaUtils;
+
+import static android.media.MediaMetadataRetriever.OPTION_CLOSEST;
+import static android.media.MediaMetadataRetriever.OPTION_CLOSEST_SYNC;
+import static android.media.MediaMetadataRetriever.OPTION_NEXT_SYNC;
+import static android.media.MediaMetadataRetriever.OPTION_PREVIOUS_SYNC;
 
 import java.io.IOException;
 
+@SmallTest
+@RequiresDevice
 public class MediaMetadataRetrieverTest extends AndroidTestCase {
+    private static final String TAG = "MediaMetadataRetrieverTest";
+    private static final boolean SAVE_BITMAP_OUTPUT = false;
+
     protected Resources mResources;
     protected MediaMetadataRetriever mRetriever;
 
@@ -211,4 +226,80 @@
     public void testThumbnailHEVC() {
         testThumbnail(R.raw.bbb_s1_720x480_mp4_hevc_mp3_1600kbps_30fps_aac_he_6ch_240kbps_48000hz);
     }
+
+
+    /**
+     * The following tests verifies MediaMetadataRetriever.getFrameAtTime behavior.
+     *
+     * We use a simple stream with binary counter at the top to check which frame
+     * is actually captured. The stream is 30fps with 600 frames in total. It has
+     * I/P/B frames, with I interval of 30. Due to the encoding structure, pts starts
+     * at 66666 (instead of 0), so we have I frames at 66666, 1066666, ..., etc..
+     *
+     * For each seek option, we check the following five cases:
+     *     1) frame time falls right on a sync frame
+     *     2) frame time is near the middle of two sync frames but closer to the previous one
+     *     3) frame time is near the middle of two sync frames but closer to the next one
+     *     4) frame time is shortly before a sync frame
+     *     5) frame time is shortly after a sync frame
+     */
+    public void testGetFrameAtTimePreviousSync() {
+        int[][] testCases = {
+                { 2066666, 60 }, { 2500000, 60 }, { 2600000, 60 }, { 3000000, 60 }, { 3200000, 90}};
+        testGetFrameAtTime(OPTION_PREVIOUS_SYNC, testCases);
+    }
+
+    public void testGetFrameAtTimeNextSync() {
+        int[][] testCases = {
+                { 2066666, 60 }, { 2500000, 90 }, { 2600000, 90 }, { 3000000, 90 }, { 3200000, 120}};
+        testGetFrameAtTime(OPTION_NEXT_SYNC, testCases);
+    }
+
+    public void testGetFrameAtTimeClosestSync() {
+        int[][] testCases = {
+                { 2066666, 60 }, { 2500000, 60 }, { 2600000, 90 }, { 3000000, 90 }, { 3200000, 90}};
+        testGetFrameAtTime(OPTION_CLOSEST_SYNC, testCases);
+    }
+
+    public void testGetFrameAtTimeClosest() {
+        int[][] testCases = {
+                { 2066666, 60 }, { 2500001, 73 }, { 2599999, 76 }, { 3016000, 88 }, { 3184000, 94}};
+        testGetFrameAtTime(OPTION_CLOSEST, testCases);
+    }
+
+    private void testGetFrameAtTime(int option, int[][] testCases) {
+        int resId = R.raw.binary_counter_320x240_30fps_600frames;
+        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+        Resources resources = getContext().getResources();
+        AssetFileDescriptor afd = resources.openRawResourceFd(resId);
+
+        retriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        try {
+            afd.close();
+        } catch (IOException e) {
+            fail("Unable to close file");
+        }
+        for (int[] testCase : testCases) {
+            getVideoFrameAndVerify(retriever, testCase[0], testCase[1], option);
+        }
+        retriever.release();
+    }
+
+    private void getVideoFrameAndVerify(
+            MediaMetadataRetriever retriever, long timeUs, long expectedCounter, int option) {
+        try {
+            Bitmap bitmap = retriever.getFrameAtTime(timeUs, option);
+            if (bitmap == null) {
+                fail("Failed to get bitmap at time " + timeUs + " with option " + option);
+            }
+            assertEquals("Counter value incorrect at time " + timeUs + " with option " + option,
+                    expectedCounter, CodecUtils.readBinaryCounterFromBitmap(bitmap));
+
+            if (SAVE_BITMAP_OUTPUT) {
+                CodecUtils.saveBitmapToFile(bitmap, "test" + timeUs + ".jpg");
+            }
+        } catch (Exception e) {
+            fail("Exception getting bitmap: " + e);
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 562feba..dc82f48 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -62,6 +62,17 @@
     }
 
     /**
+     * Test: make sure the muxer handles video, audio and metadata tracks correctly.
+     */
+    public void testVideoAudioMedatadata() throws Exception {
+        int source =
+                R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro;
+        String outputFile = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
+                .getAbsolutePath();
+        cloneAndVerify(source, outputFile, 3, 90);
+    }
+
+    /**
      * Test: make sure the muxer handles audio track only file correctly.
      */
     public void testAudioOnly() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
index 30d0feb..5fc71ff 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
@@ -15,7 +15,6 @@
  */
 package android.media.cts;
 
-import android.cts.util.MediaUtils;
 import android.media.MediaPlayer;
 import android.os.Handler;
 import android.os.Looper;
@@ -23,6 +22,8 @@
 import android.os.SystemClock;
 import android.webkit.cts.CtsTestServer;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import org.apache.http.HttpServerConnection;
 
 import org.apache.http.impl.DefaultHttpServerConnection;
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
index ae314d2..429d56e 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
@@ -17,10 +17,14 @@
 package android.media.cts;
 
 import android.os.Bundle;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.ActivityInstrumentationTestCase2;
 
 /**
  */
+@SmallTest
+@RequiresDevice
 public class MediaPlayerSurfaceTest extends ActivityInstrumentationTestCase2<MediaPlayerSurfaceStubActivity> {
 
     public MediaPlayerSurfaceTest() {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 71deb67..2cf5443 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
-import android.cts.util.MediaUtils;
 import android.graphics.Rect;
 import android.hardware.Camera;
 import android.media.AudioManager;
@@ -45,8 +44,12 @@
 import android.os.PowerManager;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
@@ -66,6 +69,8 @@
  * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
  * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
  */
+@SmallTest
+@RequiresDevice
 public class MediaPlayerTest extends MediaPlayerTestBase {
 
     private String RECORDED_FILE;
@@ -104,10 +109,6 @@
         }
     }
 
-    public void testonInputBufferFilledSigsegv() throws Exception {
-        testIfMediaServerDied(R.raw.on_input_buffer_filled_sigsegv);
-    }
-
     public void testFlacHeapOverflow() throws Exception {
         testIfMediaServerDied(R.raw.heap_oob_flac);
     }
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index 95cb43c..ec3b442 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -19,10 +19,11 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.media.MediaPlayer;
 import android.test.ActivityInstrumentationTestCase2;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.IOException;
 import java.util.logging.Logger;
 
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 2d38933..700ecfd 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -16,7 +16,6 @@
 package android.media.cts;
 
 import android.content.pm.PackageManager;
-import android.cts.util.MediaUtils;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -33,12 +32,16 @@
 import android.media.MediaMetadataRetriever;
 import android.os.Environment;
 import android.os.ConditionVariable;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.view.Surface;
 
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -48,6 +51,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@SmallTest
+@RequiresDevice
 public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
     private final String TAG = "MediaRecorderTest";
     private final String OUTPUT_PATH;
@@ -208,6 +213,44 @@
         checkOutputExist();
     }
 
+    public void testRecorderMPEG2TS() throws Exception {
+        int width;
+        int height;
+        Camera camera = null;
+        if (!hasCamera()) {
+            MediaUtils.skipTest("no camera");
+            return;
+        }
+        if (!hasMicrophone() || !hasAac()) {
+            MediaUtils.skipTest("no audio codecs or microphone");
+            return;
+        }
+        // Try to get camera profile for QUALITY_LOW; if unavailable,
+        // set the video size to default value.
+        CamcorderProfile profile = CamcorderProfile.get(
+                0 /* cameraId */, CamcorderProfile.QUALITY_LOW);
+        if (profile != null) {
+            width = profile.videoFrameWidth;
+            height = profile.videoFrameHeight;
+        } else {
+            width = VIDEO_WIDTH;
+            height = VIDEO_HEIGHT;
+        }
+        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
+        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+        mMediaRecorder.setVideoSize(width, height);
+        mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE_IN_BPS);
+        mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
+        mMediaRecorder.prepare();
+        mMediaRecorder.start();
+        Thread.sleep(RECORD_TIME_MS);
+        mMediaRecorder.stop();
+        checkOutputExist();
+    }
+
     @UiThreadTest
     public void testSetCamera() throws Exception {
         recordVideoUsingCamera(false, false);
@@ -450,7 +493,7 @@
     }
 
     public void testRecorderAudio() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
@@ -458,7 +501,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);
@@ -466,14 +509,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);
@@ -481,7 +524,7 @@
     }
 
     public void testSetMaxDuration() throws Exception {
-        if (!hasMicrophone() || !hasAmrNb()) {
+        if (!hasMicrophone() || !hasAac()) {
             MediaUtils.skipTest("no audio codecs or microphone");
             return;
         }
@@ -492,7 +535,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();
@@ -557,13 +600,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/MediaRouterTest.java b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
index 33544b9..115a212 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouterTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
@@ -15,11 +15,21 @@
  */
 package android.media.cts;
 
+import android.media.cts.R;
+
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
 import android.media.MediaRouter;
+import android.media.MediaRouter.RouteGroup;
 import android.media.MediaRouter.RouteCategory;
 import android.media.MediaRouter.RouteInfo;
 import android.media.MediaRouter.UserRouteInfo;
+import android.media.RemoteControlClient;
 import android.test.InstrumentationTestCase;
 
 import java.util.List;
@@ -30,15 +40,35 @@
  */
 public class MediaRouterTest extends InstrumentationTestCase {
 
+    private static final int TEST_ROUTE_NAME_RESOURCE_ID = R.string.test_user_route_name;
+    private static final int TEST_CATEGORY_NAME_RESOURCE_ID = R.string.test_route_category_name;
+    private static final int TEST_ICON_RESOURCE_ID = R.drawable.single_face;
+    private static final int TEST_MAX_VOLUME = 100;
+    private static final int TEST_VOLUME = 17;
+    private static final int TEST_VOLUME_DIRECTION = -2;
+    private static final int TEST_PLAYBACK_STREAM = AudioManager.STREAM_ALARM;
+    private static final int TEST_VOLUME_HANDLING = RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+    private static final int TEST_PLAYBACK_TYPE = RouteInfo.PLAYBACK_TYPE_LOCAL;
+    private static final CharSequence TEST_ROUTE_DESCRIPTION = "test_user_route_description";
+    private static final CharSequence TEST_STATUS = "test_user_route_status";
+    private static final CharSequence TEST_GROUPABLE_CATEGORY_NAME = "test_groupable_category_name";
+
     private MediaRouter mMediaRouter;
     private RouteCategory mTestCategory;
+    private RouteCategory mTestGroupableCategory;
+    private CharSequence mTestRouteName;
+    private Drawable mTestIconDrawable;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         final Context context = getInstrumentation().getContext();
         mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
-        mTestCategory = mMediaRouter.createRouteCategory("testCategory", false);
+        mTestCategory = mMediaRouter.createRouteCategory(TEST_CATEGORY_NAME_RESOURCE_ID, false);
+        mTestGroupableCategory = mMediaRouter.createRouteCategory(TEST_GROUPABLE_CATEGORY_NAME,
+                true);
+        mTestRouteName = getInstrumentation().getContext().getText(TEST_ROUTE_NAME_RESOURCE_ID);
+        mTestIconDrawable = getInstrumentation().getContext().getDrawable(TEST_ICON_RESOURCE_ID);
     }
 
     protected void tearDown() throws Exception {
@@ -46,71 +76,548 @@
         super.tearDown();
     }
 
-    public void testSelectRoute() throws Exception {
+    /**
+     * Test {@link MediaRouter#selectRoute(int, RouteInfo)}.
+     */
+    public void testSelectRoute() {
         RouteInfo prevSelectedRoute = mMediaRouter.getSelectedRoute(
                 MediaRouter.ROUTE_TYPE_LIVE_AUDIO | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
                 | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        assertNotNull(prevSelectedRoute);
 
-        final String newRouteName = "User route's name";
-        UserRouteInfo newRoute = mMediaRouter.createUserRoute(mTestCategory);
-        newRoute.setName(newRouteName);
-        mMediaRouter.addUserRoute(newRoute);
-        mMediaRouter.selectRoute(newRoute.getSupportedTypes(), newRoute);
+        UserRouteInfo userRoute = mMediaRouter.createUserRoute(mTestCategory);
+        mMediaRouter.addUserRoute(userRoute);
+        mMediaRouter.selectRoute(userRoute.getSupportedTypes(), userRoute);
 
         RouteInfo nowSelectedRoute = mMediaRouter.getSelectedRoute(MediaRouter.ROUTE_TYPE_USER);
-        assertEquals(newRoute, nowSelectedRoute);
+        assertEquals(userRoute, nowSelectedRoute);
         assertEquals(mTestCategory, nowSelectedRoute.getCategory());
 
         mMediaRouter.selectRoute(prevSelectedRoute.getSupportedTypes(), prevSelectedRoute);
     }
 
-    public void testGetRouteCount() throws Exception {
+    /**
+     * Test {@link MediaRouter#getRouteCount()}.
+     */
+    public void testGetRouteCount() {
         final int count = mMediaRouter.getRouteCount();
         assertTrue("By default, a media router has at least one route.", count > 0);
 
-        UserRouteInfo userRoute1 = mMediaRouter.createUserRoute(mTestCategory);
-        mMediaRouter.addUserRoute(userRoute1);
+        UserRouteInfo userRoute0 = mMediaRouter.createUserRoute(mTestCategory);
+        mMediaRouter.addUserRoute(userRoute0);
         assertEquals(count + 1, mMediaRouter.getRouteCount());
 
-        mMediaRouter.removeUserRoute(userRoute1);
+        mMediaRouter.removeUserRoute(userRoute0);
         assertEquals(count, mMediaRouter.getRouteCount());
 
-        UserRouteInfo userRoute2 = mMediaRouter.createUserRoute(mTestCategory);
+        UserRouteInfo userRoute1 = mMediaRouter.createUserRoute(mTestCategory);
+        mMediaRouter.addUserRoute(userRoute0);
         mMediaRouter.addUserRoute(userRoute1);
-        mMediaRouter.addUserRoute(userRoute2);
         assertEquals(count + 2, mMediaRouter.getRouteCount());
 
         mMediaRouter.clearUserRoutes();
         assertEquals(count, mMediaRouter.getRouteCount());
     }
 
-    public void testRouteCategory() throws Exception {
+    /**
+     * Test {@link MediaRouter#getRouteAt(int)}.
+     */
+    public void testGetRouteAt() throws Exception {
+        UserRouteInfo userRoute0 = mMediaRouter.createUserRoute(mTestCategory);
+        UserRouteInfo userRoute1 = mMediaRouter.createUserRoute(mTestCategory);
+        mMediaRouter.addUserRoute(userRoute0);
+        mMediaRouter.addUserRoute(userRoute1);
+
+        int count = mMediaRouter.getRouteCount();
+        assertEquals(userRoute0, mMediaRouter.getRouteAt(count - 2));
+        assertEquals(userRoute1, mMediaRouter.getRouteAt(count - 1));
+    }
+
+    /**
+     * Test {@link MediaRouter.UserRouteInfo}.
+     */
+    public void testUserRouteInfo() {
+        UserRouteInfo userRoute = mMediaRouter.createUserRoute(mTestCategory);
+        assertTrue(userRoute.isEnabled());
+        assertFalse(userRoute.isConnecting());
+        assertEquals(mTestCategory, userRoute.getCategory());
+        assertEquals(RouteInfo.DEVICE_TYPE_UNKNOWN, userRoute.getDeviceType());
+        assertEquals(RouteInfo.PLAYBACK_TYPE_REMOTE, userRoute.getPlaybackType());
+
+        // Test setName by CharSequence object.
+        userRoute.setName(mTestRouteName);
+        assertEquals(mTestRouteName, userRoute.getName());
+
+        userRoute.setName(null);
+        assertNull(userRoute.getName());
+
+        // Test setName by resource ID.
+        // The getName() method tries to find the resource in application resources which was stored
+        // when the media router is first initialized. In contrast, getName(Context) method tries to
+        // find the resource in a given context's resources. So if we call getName(Context) with a
+        // context which has the same resources, two methods will return the same value.
+        userRoute.setName(TEST_ROUTE_NAME_RESOURCE_ID);
+        assertEquals(mTestRouteName, userRoute.getName());
+        assertEquals(mTestRouteName, userRoute.getName(getInstrumentation().getContext()));
+
+        userRoute.setDescription(TEST_ROUTE_DESCRIPTION);
+        assertEquals(TEST_ROUTE_DESCRIPTION, userRoute.getDescription());
+
+        userRoute.setStatus(TEST_STATUS);
+        assertEquals(TEST_STATUS, userRoute.getStatus());
+
+        Object tag = new Object();
+        userRoute.setTag(tag);
+        assertEquals(tag, userRoute.getTag());
+
+        userRoute.setPlaybackStream(TEST_PLAYBACK_STREAM);
+        assertEquals(TEST_PLAYBACK_STREAM, userRoute.getPlaybackStream());
+
+        userRoute.setIconDrawable(mTestIconDrawable);
+        assertEquals(mTestIconDrawable, userRoute.getIconDrawable());
+
+        userRoute.setIconDrawable(null);
+        assertNull(userRoute.getIconDrawable());
+
+        userRoute.setIconResource(TEST_ICON_RESOURCE_ID);
+        assertTrue(getBitmap(mTestIconDrawable).sameAs(getBitmap(userRoute.getIconDrawable())));
+
+        userRoute.setVolumeMax(TEST_MAX_VOLUME);
+        assertEquals(TEST_MAX_VOLUME, userRoute.getVolumeMax());
+
+        userRoute.setVolume(TEST_VOLUME);
+        assertEquals(TEST_VOLUME, userRoute.getVolume());
+
+        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        PendingIntent mediaButtonIntent = PendingIntent.getBroadcast(
+                getInstrumentation().getContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
+        RemoteControlClient rcc = new RemoteControlClient(mediaButtonIntent);
+        userRoute.setRemoteControlClient(rcc);
+        assertEquals(rcc, userRoute.getRemoteControlClient());
+
+        userRoute.setVolumeHandling(TEST_VOLUME_HANDLING);
+        assertEquals(TEST_VOLUME_HANDLING, userRoute.getVolumeHandling());
+
+        userRoute.setPlaybackType(TEST_PLAYBACK_TYPE);
+        assertEquals(TEST_PLAYBACK_TYPE, userRoute.getPlaybackType());
+    }
+
+    /**
+     * Test {@link MediaRouter.RouteGroup}.
+     */
+    public void testRouteGroup() {
+        // Create a route with a groupable category.
+        // A route does not belong to any group until it is added to a media router or to a group.
+        UserRouteInfo userRoute0 = mMediaRouter.createUserRoute(mTestGroupableCategory);
+        assertNull(userRoute0.getGroup());
+
+        // Call addUserRoute(UserRouteInfo).
+        // For the route whose category is groupable, this method does not directly add the route in
+        // the media router. Instead, it creates a RouteGroup, adds the group in the media router,
+        // and puts the route inside that group.
+        mMediaRouter.addUserRoute(userRoute0);
+        RouteGroup routeGroup = userRoute0.getGroup();
+        assertNotNull(routeGroup);
+        assertEquals(1, routeGroup.getRouteCount());
+        assertEquals(userRoute0, routeGroup.getRouteAt(0));
+
+        // Create another two routes with the same category.
+        UserRouteInfo userRoute1 = mMediaRouter.createUserRoute(mTestGroupableCategory);
+        UserRouteInfo userRoute2 = mMediaRouter.createUserRoute(mTestGroupableCategory);
+
+        // Add userRoute2 at the end of the group.
+        routeGroup.addRoute(userRoute2);
+        assertSame(routeGroup, userRoute2.getGroup());
+        assertEquals(2, routeGroup.getRouteCount());
+        assertEquals(userRoute0, routeGroup.getRouteAt(0));
+        assertEquals(userRoute2, routeGroup.getRouteAt(1));
+
+        // To place routes in order, add userRoute1 to the group between userRoute0 and userRoute2.
+        routeGroup.addRoute(userRoute1, 1);
+        assertSame(routeGroup, userRoute1.getGroup());
+        assertEquals(3, routeGroup.getRouteCount());
+        assertEquals(userRoute0, routeGroup.getRouteAt(0));
+        assertEquals(userRoute1, routeGroup.getRouteAt(1));
+        assertEquals(userRoute2, routeGroup.getRouteAt(2));
+
+        // Remove userRoute0.
+        routeGroup.removeRoute(userRoute0);
+        assertNull(userRoute0.getGroup());
+        assertEquals(2, routeGroup.getRouteCount());
+        assertEquals(userRoute1, routeGroup.getRouteAt(0));
+        assertEquals(userRoute2, routeGroup.getRouteAt(1));
+
+        // Remove userRoute1 which is the first route in the group now.
+        routeGroup.removeRoute(0);
+        assertNull(userRoute1.getGroup());
+        assertEquals(1, routeGroup.getRouteCount());
+        assertEquals(userRoute2, routeGroup.getRouteAt(0));
+
+        // Routes in different categories cannot be added to the same group.
+        UserRouteInfo userRouteInAnotherCategory = mMediaRouter.createUserRoute(mTestCategory);
+        try {
+            // This will throw an IllegalArgumentException.
+            routeGroup.addRoute(userRouteInAnotherCategory);
+            fail();
+        } catch (IllegalArgumentException exception) {
+            // Expected
+        }
+
+        // Set an icon for the group.
+        routeGroup.setIconDrawable(mTestIconDrawable);
+        assertEquals(mTestIconDrawable, routeGroup.getIconDrawable());
+
+        routeGroup.setIconDrawable(null);
+        assertNull(routeGroup.getIconDrawable());
+
+        routeGroup.setIconResource(TEST_ICON_RESOURCE_ID);
+        assertTrue(getBitmap(mTestIconDrawable).sameAs(getBitmap(routeGroup.getIconDrawable())));
+    }
+
+    /**
+     * Test {@link MediaRouter.RouteCategory}.
+     */
+    public void testRouteCategory() {
+        // Test getName() for category whose name is set with resource ID.
+        RouteCategory routeCategory = mMediaRouter.createRouteCategory(
+                TEST_CATEGORY_NAME_RESOURCE_ID, false);
+
+        // The getName() method tries to find the resource in application resources which was stored
+        // when the media router is first initialized. In contrast, getName(Context) method tries to
+        // find the resource in a given context's resources. So if we call getName(Context) with a
+        // context which has the same resources, two methods will return the same value.
+        CharSequence categoryName = getInstrumentation().getContext().getText(
+                TEST_CATEGORY_NAME_RESOURCE_ID);
+        assertEquals(categoryName, routeCategory.getName());
+        assertEquals(categoryName, routeCategory.getName(getInstrumentation().getContext()));
+
+        assertFalse(routeCategory.isGroupable());
+        assertEquals(MediaRouter.ROUTE_TYPE_USER, routeCategory.getSupportedTypes());
+
         final int count = mMediaRouter.getCategoryCount();
         assertTrue("By default, a media router has at least one route category.", count > 0);
 
-        UserRouteInfo newRoute = mMediaRouter.createUserRoute(mTestCategory);
-        mMediaRouter.addUserRoute(newRoute);
+        UserRouteInfo userRoute = mMediaRouter.createUserRoute(routeCategory);
+        mMediaRouter.addUserRoute(userRoute);
         assertEquals(count + 1, mMediaRouter.getCategoryCount());
+        assertEquals(routeCategory, mMediaRouter.getCategoryAt(count));
 
-        for (int i = 0; i < mMediaRouter.getCategoryCount(); i++) {
-            if (mMediaRouter.getCategoryAt(i) == mTestCategory) {
-                List<RouteInfo> routesInCategory = new ArrayList<RouteInfo>();
-                mTestCategory.getRoutes(routesInCategory);
-                assertEquals(1, routesInCategory.size());
+        List<RouteInfo> routesInCategory = new ArrayList<RouteInfo>();
+        routeCategory.getRoutes(routesInCategory);
+        assertEquals(1, routesInCategory.size());
 
-                RouteInfo route = routesInCategory.get(0);
-                assertEquals(newRoute, route);
-                return;
-            }
-        }
-        assertTrue(false);
+        RouteInfo route = routesInCategory.get(0);
+        assertEquals(userRoute, route);
+
+        // Test getName() for category whose name is set with CharSequence object.
+        RouteCategory newRouteCategory = mMediaRouter.createRouteCategory(categoryName, false);
+        assertEquals(categoryName, newRouteCategory.getName());
     }
 
-    public void testRouteInfo_getDeviceType() throws Exception {
-        final RouteInfo defaultRoute = mMediaRouter.getDefaultRoute();
-        assertTrue(defaultRoute != null);
+    public void testCallback() {
+        MediaRouterCallback callback = new MediaRouterCallback();
+        final int allRouteTypes = MediaRouter.ROUTE_TYPE_LIVE_AUDIO
+                | MediaRouter.ROUTE_TYPE_LIVE_VIDEO | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+                | MediaRouter.ROUTE_TYPE_USER;
+        mMediaRouter.addCallback(allRouteTypes, callback);
 
-        final int deviceType = defaultRoute.getDeviceType();
-        assertEquals(RouteInfo.DEVICE_TYPE_UNKNOWN, deviceType);
+        // Test onRouteAdded().
+        callback.reset();
+        UserRouteInfo userRoute = mMediaRouter.createUserRoute(mTestCategory);
+        mMediaRouter.addUserRoute(userRoute);
+        assertTrue(callback.mOnRouteAddedCalled);
+        assertEquals(userRoute, callback.mAddedRoute);
+
+        RouteInfo prevSelectedRoute = mMediaRouter.getSelectedRoute();
+
+        // Test onRouteSelected() and onRouteUnselected().
+        callback.reset();
+        mMediaRouter.selectRoute(MediaRouter.ROUTE_TYPE_USER, userRoute);
+        assertTrue(callback.mOnRouteUnselectedCalled);
+        assertEquals(prevSelectedRoute, callback.mUnselectedRoute);
+        assertTrue(callback.mOnRouteSelectedCalled);
+        assertEquals(userRoute, callback.mSelectedRoute);
+
+        // Test onRouteChanged().
+        // It is called when the route's name, description, status or tag is updated.
+        callback.reset();
+        userRoute.setName(mTestRouteName);
+        assertTrue(callback.mOnRouteChangedCalled);
+        assertEquals(userRoute, callback.mChangedRoute);
+
+        callback.reset();
+        userRoute.setDescription(TEST_ROUTE_DESCRIPTION);
+        assertTrue(callback.mOnRouteChangedCalled);
+        assertEquals(userRoute, callback.mChangedRoute);
+
+        callback.reset();
+        userRoute.setStatus(TEST_STATUS);
+        assertTrue(callback.mOnRouteChangedCalled);
+        assertEquals(userRoute, callback.mChangedRoute);
+
+        callback.reset();
+        Object tag = new Object();
+        userRoute.setTag(tag);
+        assertTrue(callback.mOnRouteChangedCalled);
+        assertEquals(userRoute, callback.mChangedRoute);
+
+        // Test onRouteVolumeChanged().
+        userRoute.setVolumeMax(TEST_MAX_VOLUME);
+        callback.reset();
+        userRoute.setVolume(TEST_VOLUME);
+        assertTrue(callback.mOnRouteVolumeChangedCalled);
+        assertEquals(userRoute, callback.mVolumeChangedRoute);
+
+        // Test onRouteRemoved().
+        callback.reset();
+        mMediaRouter.removeUserRoute(userRoute);
+        assertTrue(callback.mOnRouteRemovedCalled);
+        assertEquals(userRoute, callback.mRemovedRoute);
+
+        // Test onRouteGrouped() and onRouteUngrouped().
+        mMediaRouter.clearUserRoutes();
+        UserRouteInfo groupableRoute0 = mMediaRouter.createUserRoute(mTestGroupableCategory);
+        UserRouteInfo groupableRoute1 = mMediaRouter.createUserRoute(mTestGroupableCategory);
+
+        // Adding a route of groupable category in the media router does not directly add the route.
+        // Instead, it creates a RouteGroup, adds the group as a route in the media router, and puts
+        // the route inside that group. Therefore onRouteAdded() is called for the group, and
+        // onRouteGrouped() is called for the route.
+        callback.reset();
+        mMediaRouter.addUserRoute(groupableRoute0);
+
+        RouteGroup group = groupableRoute0.getGroup();
+        assertTrue(callback.mOnRouteAddedCalled);
+        assertEquals(group, callback.mAddedRoute);
+
+        assertTrue(callback.mOnRouteGroupedCalled);
+        assertEquals(groupableRoute0, callback.mGroupedRoute);
+        assertEquals(group, callback.mGroup);
+        assertEquals(0, callback.mRouteIndexInGroup);
+
+        // Add another route to the group.
+        callback.reset();
+        group.addRoute(groupableRoute1);
+        assertTrue(callback.mOnRouteGroupedCalled);
+        assertEquals(groupableRoute1, callback.mGroupedRoute);
+        assertEquals(1, callback.mRouteIndexInGroup);
+
+        // Since removing a route from the group changes the group's name, onRouteChanged() is
+        // called.
+        callback.reset();
+        group.removeRoute(groupableRoute1);
+        assertTrue(callback.mOnRouteUngroupedCalled);
+        assertEquals(groupableRoute1, callback.mUngroupedRoute);
+        assertTrue(callback.mOnRouteChangedCalled);
+        assertEquals(group, callback.mChangedRoute);
+
+        // When a group has no routes, the group is removed from the media router.
+        callback.reset();
+        group.removeRoute(0);
+        assertTrue(callback.mOnRouteUngroupedCalled);
+        assertEquals(groupableRoute0, callback.mUngroupedRoute);
+        assertTrue(callback.mOnRouteRemovedCalled);
+        assertEquals(group, callback.mRemovedRoute);
+
+        // In this case, onRouteChanged() is not called.
+        assertFalse(callback.mOnRouteChangedCalled);
+
+        // Try removing the callback.
+        mMediaRouter.removeCallback(callback);
+        callback.reset();
+        mMediaRouter.addUserRoute(groupableRoute0);
+        assertFalse(callback.mOnRouteAddedCalled);
+
+        mMediaRouter.selectRoute(prevSelectedRoute.getSupportedTypes(), prevSelectedRoute);
+    }
+
+    /**
+     * Test {@link MediaRouter#addCallback(int, MediaRouter.Callback, int)}.
+     */
+    public void testAddCallbackWithFlags() {
+        MediaRouterCallback callback = new MediaRouterCallback();
+        mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_USER, callback);
+
+        RouteInfo prevSelectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_LIVE_AUDIO | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+                | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+
+        // Currently mCallback is set for the type MediaRouter.ROUTE_TYPE_USER.
+        // Changes on prevSelectedRoute will not invoke mCallback since the types do not match.
+        callback.reset();
+        Object tag0 = new Object();
+        prevSelectedRoute.setTag(tag0);
+        assertFalse(callback.mOnRouteChangedCalled);
+
+        // Remove mCallback and add it again with flag MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS.
+        // This flag will make the callback be invoked even when the types do not match.
+        mMediaRouter.removeCallback(callback);
+        mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_USER, callback,
+                MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
+
+        callback.reset();
+        Object tag1 = new Object();
+        prevSelectedRoute.setTag(tag1);
+        assertTrue(callback.mOnRouteChangedCalled);
+    }
+
+    /**
+     * Test {@link MediaRouter.VolumeCallback)}.
+     */
+    public void testVolumeCallback() {
+        UserRouteInfo userRoute = mMediaRouter.createUserRoute(mTestCategory);
+        userRoute.setVolumeHandling(RouteInfo.PLAYBACK_VOLUME_VARIABLE);
+        MediaRouterVolumeCallback callback = new MediaRouterVolumeCallback();
+        userRoute.setVolumeCallback(callback);
+
+        userRoute.requestSetVolume(TEST_VOLUME);
+        assertTrue(callback.mOnVolumeSetRequestCalled);
+        assertEquals(userRoute, callback.mRouteInfo);
+        assertEquals(TEST_VOLUME, callback.mVolume);
+
+        callback.reset();
+        userRoute.requestUpdateVolume(TEST_VOLUME_DIRECTION);
+        assertTrue(callback.mOnVolumeUpdateRequestCalled);
+        assertEquals(userRoute, callback.mRouteInfo);
+        assertEquals(TEST_VOLUME_DIRECTION, callback.mDirection);
+    }
+
+    private Bitmap getBitmap(Drawable drawable) {
+        int width = drawable.getIntrinsicWidth();
+        int height = drawable.getIntrinsicHeight();
+
+        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(result);
+
+        drawable.setBounds(0, 0, width, height);
+        drawable.draw(canvas);
+
+        return result;
+    }
+
+    private class MediaRouterVolumeCallback extends MediaRouter.VolumeCallback {
+        private boolean mOnVolumeUpdateRequestCalled;
+        private boolean mOnVolumeSetRequestCalled;
+        private RouteInfo mRouteInfo;
+        private int mDirection;
+        private int mVolume;
+
+        public void reset() {
+            mOnVolumeUpdateRequestCalled = false;
+            mOnVolumeSetRequestCalled = false;
+            mRouteInfo = null;
+            mDirection = 0;
+            mVolume = 0;
+        }
+
+        @Override
+        public void onVolumeUpdateRequest(RouteInfo info, int direction) {
+            mOnVolumeUpdateRequestCalled = true;
+            mRouteInfo = info;
+            mDirection = direction;
+        }
+
+        @Override
+        public void onVolumeSetRequest(RouteInfo info, int volume) {
+            mOnVolumeSetRequestCalled = true;
+            mRouteInfo = info;
+            mVolume = volume;
+        }
+    }
+
+    private class MediaRouterCallback extends MediaRouter.Callback {
+        private boolean mOnRouteSelectedCalled;
+        private boolean mOnRouteUnselectedCalled;
+        private boolean mOnRouteAddedCalled;
+        private boolean mOnRouteRemovedCalled;
+        private boolean mOnRouteChangedCalled;
+        private boolean mOnRouteGroupedCalled;
+        private boolean mOnRouteUngroupedCalled;
+        private boolean mOnRouteVolumeChangedCalled;
+
+        private RouteInfo mSelectedRoute;
+        private RouteInfo mUnselectedRoute;
+        private RouteInfo mAddedRoute;
+        private RouteInfo mRemovedRoute;
+        private RouteInfo mChangedRoute;
+        private RouteInfo mGroupedRoute;
+        private RouteInfo mUngroupedRoute;
+        private RouteInfo mVolumeChangedRoute;
+        private RouteGroup mGroup;
+        private int mRouteIndexInGroup = -1;
+
+        public void reset() {
+            mOnRouteSelectedCalled = false;
+            mOnRouteUnselectedCalled = false;
+            mOnRouteAddedCalled = false;
+            mOnRouteRemovedCalled = false;
+            mOnRouteChangedCalled = false;
+            mOnRouteGroupedCalled = false;
+            mOnRouteUngroupedCalled = false;
+            mOnRouteVolumeChangedCalled = false;
+
+            mSelectedRoute = null;
+            mUnselectedRoute = null;
+            mAddedRoute = null;
+            mRemovedRoute = null;
+            mChangedRoute = null;
+            mGroupedRoute = null;
+            mUngroupedRoute = null;
+            mVolumeChangedRoute = null;
+            mGroup = null;
+            mRouteIndexInGroup = -1;
+        }
+
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+            mOnRouteSelectedCalled = true;
+            mSelectedRoute = info;
+        }
+
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+            mOnRouteUnselectedCalled = true;
+            mUnselectedRoute = info;
+        }
+
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo info) {
+            mOnRouteAddedCalled = true;
+            mAddedRoute = info;
+        }
+
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
+            mOnRouteRemovedCalled = true;
+            mRemovedRoute = info;
+        }
+
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo info) {
+            mOnRouteChangedCalled = true;
+            mChangedRoute = info;
+        }
+
+        @Override
+        public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
+                int index) {
+            mOnRouteGroupedCalled = true;
+            mGroupedRoute = info;
+            mGroup = group;
+            mRouteIndexInGroup = index;
+        }
+
+        @Override
+        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
+            mOnRouteUngroupedCalled = true;
+            mUngroupedRoute = info;
+            mGroup = group;
+        }
+
+        @Override
+        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
+            mOnRouteVolumeChangedCalled = true;
+            mVolumeChangedRoute = info;
+        }
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index 952e03f..2bd699f 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -21,14 +21,15 @@
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
-import android.cts.util.PollingCheck;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
 import android.os.IBinder;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index ce93cb1..3a12e3b 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -26,14 +26,14 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.AssetFileDescriptor;
-import android.cts.util.FileCopyHelper;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.media.MediaMetadataRetriever;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.mtp.MtpConstants;
 import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.platform.test.annotations.RequiresDevice;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.IBinder;
@@ -42,9 +42,14 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.File;
 import java.io.IOException;
 
+@SmallTest
+@RequiresDevice
 public class MediaScannerTest extends AndroidTestCase {
 
     private static final String MEDIA_TYPE = "audio/mpeg";
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index 3ebe6e4..de1966c 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;
@@ -208,6 +209,24 @@
             mSession.setSessionActivity(pi);
             assertEquals(pi, controller.getSessionActivity());
 
+            // test setRepeatMode
+            mCallback.resetLocked();
+            final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
+            mSession.setRepeatMode(repeatMode);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnRepeatModeChangedCalled);
+            assertEquals(repeatMode, mCallback.mRepeatMode);
+            assertEquals(repeatMode, controller.getRepeatMode());
+
+            // test setShuffleModeEnabled
+            mCallback.resetLocked();
+            final boolean shuffleModeEnabled = true;
+            mSession.setShuffleModeEnabled(shuffleModeEnabled);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnShuffleModeChangedCalled);
+            assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
+            assertEquals(shuffleModeEnabled, controller.isShuffleModeEnabled());
+
             // test setActivity
             mSession.setActive(true);
             assertTrue(mSession.isActive());
@@ -230,7 +249,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 +310,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 +402,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);
@@ -349,6 +453,8 @@
         private volatile boolean mOnAudioInfoChangedCalled;
         private volatile boolean mOnSessionDestroyedCalled;
         private volatile boolean mOnSessionEventCalled;
+        private volatile boolean mOnRepeatModeChangedCalled;
+        private volatile boolean mOnShuffleModeChangedCalled;
 
         private volatile PlaybackState mPlaybackState;
         private volatile MediaMetadata mMediaMetadata;
@@ -357,6 +463,8 @@
         private volatile String mEvent;
         private volatile Bundle mExtras;
         private volatile MediaController.PlaybackInfo mPlaybackInfo;
+        private volatile int mRepeatMode;
+        private volatile boolean mShuffleModeEnabled;
 
         public void resetLocked() {
             mOnPlaybackStateChangedCalled = false;
@@ -367,6 +475,8 @@
             mOnAudioInfoChangedCalled = false;
             mOnSessionDestroyedCalled = false;
             mOnSessionEventCalled = false;
+            mOnRepeatModeChangedCalled = false;
+            mOnShuffleModeChangedCalled = false;
 
             mPlaybackState = null;
             mMediaMetadata = null;
@@ -374,6 +484,8 @@
             mTitle = null;
             mExtras = null;
             mPlaybackInfo = null;
+            mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
+            mShuffleModeEnabled = false;
         }
 
         @Override
@@ -447,5 +559,99 @@
                 mWaitLock.notify();
             }
         }
+
+        @Override
+        public void onRepeatModeChanged(int repeatMode) {
+            synchronized (mWaitLock) {
+                mOnRepeatModeChangedCalled = true;
+                mRepeatMode = repeatMode;
+                mWaitLock.notify();
+            }
+        }
+
+        @Override
+        public void onShuffleModeChanged(boolean enabled) {
+            synchronized (mWaitLock) {
+                mOnShuffleModeChangedCalled = true;
+                mShuffleModeEnabled = enabled;
+                mWaitLock.notify();
+            }
+        }
+    }
+
+    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/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index 08dc5ea..2adede1 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -21,7 +21,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
@@ -41,6 +40,8 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.IOException;
 import java.lang.Long;
 import java.lang.Math;
diff --git a/tests/tests/media/src/android/media/cts/MidiSoloTest.java b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
index d198ee8..b133ed9 100644
--- a/tests/tests/media/src/android/media/cts/MidiSoloTest.java
+++ b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.media.midi.MidiDevice;
 import android.media.midi.MidiDevice.MidiConnection;
 import android.media.midi.MidiDeviceInfo;
@@ -33,6 +32,8 @@
 import android.os.Handler;
 import android.os.Looper;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
 /**
  * Test MIDI when there may be no MIDI devices available. There is not much we
  * can test without a device.
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index 0806571..32cf661 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -20,7 +20,6 @@
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
 import android.media.MediaCodecInfo;
@@ -35,6 +34,8 @@
 import android.view.Surface;
 import android.webkit.cts.CtsTestServer;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
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/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 0db2e05..1076b8e 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -15,7 +15,6 @@
  */
 package android.media.cts;
 
-import android.cts.util.MediaUtils;
 import android.media.MediaFormat;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.TrackInfo;
@@ -27,6 +26,7 @@
 import android.webkit.cts.CtsTestServer;
 
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import com.android.compatibility.common.util.MediaUtils;
 
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
diff --git a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
index c6e0578..c7101b5 100644
--- a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
@@ -21,8 +21,6 @@
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
-import android.cts.util.MediaPerfUtils;
-import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo.VideoCapabilities;
 import android.media.MediaExtractor;
@@ -32,6 +30,8 @@
 import android.view.Surface;
 
 import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MediaPerfUtils;
+import com.android.compatibility.common.util.MediaUtils;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index c2b665b..acf7dac 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -20,7 +20,6 @@
 
 import android.media.cts.CodecUtils;
 
-import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.media.Image;
@@ -40,6 +39,8 @@
 import android.util.Size;
 import android.view.Surface;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -1014,48 +1015,56 @@
         }
 
         public boolean testIntraRefresh(int width, int height) {
-            final int refreshPeriod = 10;
             if (!mCaps.isFeatureSupported(CodecCapabilities.FEATURE_IntraRefresh)) {
                 return false;
             }
 
-            Function<MediaFormat, Boolean> updateConfigFormatHook =
-                    new Function<MediaFormat, Boolean>() {
-                public Boolean apply(MediaFormat fmt) {
-                    // set i-frame-interval to 10000 so encoded video only has 1 i-frame.
-                    fmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10000);
-                    fmt.setInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD, refreshPeriod);
-                    return true;
-                }
-            };
+            final int refreshPeriod[] = new int[] {10, 13, 17, 22, 29, 38, 50, 60};
 
-            Function<MediaFormat, Boolean> checkOutputFormatHook =
-                    new Function<MediaFormat, Boolean>() {
-                public Boolean apply(MediaFormat fmt) {
-                    int intraPeriod = fmt.getInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD);
-                    // Make sure intra period is correct and carried in the output format.
-                    // intraPeriod must be larger than 0 and not larger than what has been set.
-                    if (intraPeriod > refreshPeriod) {
-                        throw new RuntimeException("Intra period mismatch");
+            // Test the support of refresh periods in the range of 10 - 60 frames
+            for (int period : refreshPeriod) {
+                Function<MediaFormat, Boolean> updateConfigFormatHook =
+                new Function<MediaFormat, Boolean>() {
+                    public Boolean apply(MediaFormat fmt) {
+                        // set i-frame-interval to 10000 so encoded video only has 1 i-frame.
+                        fmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10000);
+                        fmt.setInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD, period);
+                        return true;
                     }
-                    return true;
+                };
+
+                Function<MediaFormat, Boolean> checkOutputFormatHook =
+                new Function<MediaFormat, Boolean>() {
+                    public Boolean apply(MediaFormat fmt) {
+                        int intraPeriod = fmt.getInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD);
+                        // Make sure intra period is correct and carried in the output format.
+                        // intraPeriod must be larger than 0 and operate within 20% of refresh period.
+                        if (intraPeriod > 1.2 * period || intraPeriod < 0.8 * period) {
+                            throw new RuntimeException("Intra period mismatch");
+                        }
+                        return true;
+                    }
+                };
+
+                String testName =
+                mName + '_' + width + "x" + height + '_' + "flexYUV_intraRefresh";
+
+                Consumer<VideoProcessorBase> configureVideoProcessor =
+                new Consumer<VideoProcessorBase>() {
+                    public void accept(VideoProcessorBase processor) {
+                        processor.setProcessorName(testName);
+                        processor.setUpdateConfigHook(updateConfigFormatHook);
+                        processor.setCheckOutputFormatHook(checkOutputFormatHook);
+                    }
+                };
+
+                if (!test(width, height, 0 /* frameRate */, 0 /* bitRate */, true /* optional */,
+                    true /* flex */, configureVideoProcessor)) {
+                    return false;
                 }
-            };
+            }
 
-            String testName =
-                    mName + '_' + width + "x" + height + '_' + "flexYUV_intraRefresh";
-
-            Consumer<VideoProcessorBase> configureVideoProcessor =
-                    new Consumer<VideoProcessorBase>() {
-                public void accept(VideoProcessorBase processor) {
-                    processor.setProcessorName(testName);
-                    processor.setUpdateConfigHook(updateConfigFormatHook);
-                    processor.setCheckOutputFormatHook(checkOutputFormatHook);
-                }
-            };
-
-            return test(width, height, 0 /* frameRate */, 0 /* bitRate */, true /* optional */,
-                    true /* flex */, configureVideoProcessor);
+            return true;
         }
 
         public boolean testDetailed(
diff --git a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
deleted file mode 100644
index 0395ec7..0000000
--- a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
+++ /dev/null
@@ -1,2000 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.content.Context;
-import android.content.res.Resources;
-import android.media.MediaCodec;
-import android.media.MediaCodec.CodecException;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaCodecInfo;
-import android.media.MediaFormat;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Looper;
-import android.os.Handler;
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.media.cts.R;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.Locale;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Verification test for vp8 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
- * calculate PSNR values for various bitrates.
- */
-public class Vp8CodecTestBase extends AndroidTestCase {
-
-    protected static final String TAG = "VP8CodecTestBase";
-    protected static final String VP8_MIME = MediaFormat.MIMETYPE_VIDEO_VP8;
-    private static final String GOOGLE_CODEC_PREFIX = "omx.google.";
-    protected static final String SDCARD_DIR =
-            Environment.getExternalStorageDirectory().getAbsolutePath();
-
-    // Default timeout for MediaCodec buffer dequeue - 200 ms.
-    protected static final long DEFAULT_DEQUEUE_TIMEOUT_US = 200000;
-    // Default timeout for MediaEncoderAsync - 30 sec.
-    protected static final long DEFAULT_ENCODE_TIMEOUT_MS = 30000;
-    // Default sync frame interval in frames (zero means allow the encoder to auto-select
-    // key frame interval).
-    private static final int SYNC_FRAME_INTERVAL = 0;
-    // Video bitrate type - should be set to OMX_Video_ControlRateConstant from OMX_Video.h
-    protected static final int VIDEO_ControlRateVariable = 1;
-    protected static final int VIDEO_ControlRateConstant = 2;
-    // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
-    // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
-    private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
-    // Allowable color formats supported by codec - in order of preference.
-    private static final int[] mSupportedColorList = {
-            CodecCapabilities.COLOR_FormatYUV420Planar,
-            CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
-            CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
-            COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
-    };
-    // Scaled image cache list - contains scale factors, for which up-scaled frames
-    // were calculated and were written to yuv file.
-    ArrayList<Integer> mScaledImages = new ArrayList<Integer>();
-
-    private Resources mResources;
-
-    @Override
-    public void setContext(Context context) {
-        super.setContext(context);
-        mResources = mContext.getResources();
-    }
-
-    /**
-     *  VP8 codec properties generated by getVp8CodecProperties() function.
-     */
-    private class CodecProperties {
-        CodecProperties(String codecName, int colorFormat) {
-            this.codecName = codecName;
-            this.colorFormat = colorFormat;
-        }
-        public boolean  isGoogleCodec() {
-            return codecName.toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
-        }
-
-        public final String codecName; // OpenMax component name for VP8 codec.
-        public final int colorFormat;  // Color format supported by codec.
-    }
-
-    /**
-     * Function to find VP8 codec.
-     *
-     * Iterates through the list of available codecs and tries to find
-     * VPX codec, which can support either YUV420 planar or NV12 color formats.
-     * If forceGoogleCodec parameter set to true the function always returns
-     * Google VPX codec.
-     * If forceGoogleCodec parameter set to false the functions looks for platform
-     * specific VPX codec first. If no platform specific codec exist, falls back to
-     * Google VPX codec.
-     *
-     * @param isEncoder     Flag if encoder is requested.
-     * @param forceGoogleCodec  Forces to use Google codec.
-     */
-    private CodecProperties getVpxCodecProperties(
-            boolean isEncoder,
-            MediaFormat format,
-            boolean forceGoogleCodec) throws Exception {
-        CodecProperties codecProperties = null;
-        String mime = format.getString(MediaFormat.KEY_MIME);
-
-        // Loop through the list of omx components in case platform specific codec
-        // is requested.
-        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
-            if (isEncoder != codecInfo.isEncoder()) {
-                continue;
-            }
-            Log.v(TAG, codecInfo.getName());
-            // TODO: remove dependence of Google from the test
-            // Check if this is Google codec - we should ignore it.
-            boolean isGoogleCodec =
-                codecInfo.getName().toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
-            if (!isGoogleCodec && forceGoogleCodec) {
-                continue;
-            }
-
-            for (String type : codecInfo.getSupportedTypes()) {
-                if (!type.equalsIgnoreCase(mime)) {
-                    continue;
-                }
-                CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(type);
-                if (!capabilities.isFormatSupported(format)) {
-                    continue;
-                }
-
-                // Get candidate codec properties.
-                Log.v(TAG, "Found candidate codec " + codecInfo.getName());
-                for (int colorFormat: capabilities.colorFormats) {
-                    Log.v(TAG, "   Color: 0x" + Integer.toHexString(colorFormat));
-                }
-
-                // Check supported color formats.
-                for (int supportedColorFormat : mSupportedColorList) {
-                    for (int codecColorFormat : capabilities.colorFormats) {
-                        if (codecColorFormat == supportedColorFormat) {
-                            codecProperties = new CodecProperties(codecInfo.getName(),
-                                    codecColorFormat);
-                            Log.v(TAG, "Found target codec " + codecProperties.codecName +
-                                    ". Color: 0x" + Integer.toHexString(codecColorFormat));
-                            // return first HW codec found
-                            if (!isGoogleCodec) {
-                                return codecProperties;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        if (codecProperties == null) {
-            Log.i(TAG, "no suitable " + (forceGoogleCodec ? "google " : "")
-                    + (isEncoder ? "encoder " : "decoder ") + "found for " + format);
-        }
-        return codecProperties;
-    }
-
-    /**
-     * Parameters for encoded video stream.
-     */
-    protected class EncoderOutputStreamParameters {
-        // Name of raw YUV420 input file. When the value of this parameter
-        // is set to null input file descriptor from inputResourceId parameter
-        // is used instead.
-        public String inputYuvFilename;
-        // Name of scaled YUV420 input file.
-        public String scaledYuvFilename;
-        // File descriptor for the raw input file (YUV420). Used only if
-        // inputYuvFilename parameter is null.
-        int inputResourceId;
-        // Name of the IVF file to write encoded bitsream
-        public String outputIvfFilename;
-        // Force to use Google VP8 encoder.
-        boolean forceGoogleEncoder;
-        // Number of frames to encode.
-        int frameCount;
-        // Frame rate of input file in frames per second.
-        int frameRate;
-        // Encoded frame width.
-        public int frameWidth;
-        // Encoded frame height.
-        public int frameHeight;
-        // Encoding bitrate array in bits/second for every frame. If array length
-        // is shorter than the total number of frames, the last value is re-used for
-        // all remaining frames. For constant bitrate encoding single element
-        // array can be used with first element set to target bitrate value.
-        public int[] bitrateSet;
-        // Encoding bitrate type - VBR or CBR
-        public int bitrateType;
-        // Number of temporal layers
-        public int temporalLayers;
-        // Desired key frame interval - codec is asked to generate key frames
-        // at a period defined by this parameter.
-        public int syncFrameInterval;
-        // Optional parameter - forced key frame interval. Used to
-        // explicitly request the codec to generate key frames using
-        // MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME parameter.
-        public int syncForceFrameInterval;
-        // Buffer timeout
-        long timeoutDequeue;
-        // Flag if encoder should run in Looper thread.
-        boolean runInLooperThread;
-    }
-
-    /**
-     * Generates an array of default parameters for encoder output stream based on
-     * upscaling value.
-     */
-    protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
-            String inputYuvName,
-            String outputIvfBaseName,
-            int encodeSeconds,
-            int[] resolutionScales,
-            int frameWidth,
-            int frameHeight,
-            int frameRate,
-            int bitrateMode,
-            int[] bitrates,
-            boolean syncEncoding) {
-        assertTrue(resolutionScales.length == bitrates.length);
-        int numCodecs = resolutionScales.length;
-        ArrayList<EncoderOutputStreamParameters> outputParameters =
-                new ArrayList<EncoderOutputStreamParameters>(numCodecs);
-        for (int i = 0; i < numCodecs; i++) {
-            EncoderOutputStreamParameters params = new EncoderOutputStreamParameters();
-            if (inputYuvName != null) {
-                params.inputYuvFilename = SDCARD_DIR + File.separator + inputYuvName;
-            } else {
-                params.inputYuvFilename = null;
-            }
-            params.scaledYuvFilename = SDCARD_DIR + File.separator +
-                    outputIvfBaseName + resolutionScales[i]+ ".yuv";
-            params.inputResourceId = R.raw.football_qvga;
-            params.outputIvfFilename = SDCARD_DIR + File.separator +
-                    outputIvfBaseName + resolutionScales[i] + ".ivf";
-            params.forceGoogleEncoder = false;
-            params.frameCount = encodeSeconds * frameRate;
-            params.frameRate = frameRate;
-            params.frameWidth = Math.min(frameWidth * resolutionScales[i], 1280);
-            params.frameHeight = Math.min(frameHeight * resolutionScales[i], 720);
-            params.bitrateSet = new int[1];
-            params.bitrateSet[0] = bitrates[i];
-            params.bitrateType = bitrateMode;
-            params.temporalLayers = 0;
-            params.syncFrameInterval = SYNC_FRAME_INTERVAL;
-            params.syncForceFrameInterval = 0;
-            if (syncEncoding) {
-                params.timeoutDequeue = DEFAULT_DEQUEUE_TIMEOUT_US;
-                params.runInLooperThread = false;
-            } else {
-                params.timeoutDequeue = 0;
-                params.runInLooperThread = true;
-            }
-            outputParameters.add(params);
-        }
-        return outputParameters;
-    }
-
-    protected EncoderOutputStreamParameters getDefaultEncodingParameters(
-            String inputYuvName,
-            String outputIvfBaseName,
-            int encodeSeconds,
-            int frameWidth,
-            int frameHeight,
-            int frameRate,
-            int bitrateMode,
-            int bitrate,
-            boolean syncEncoding) {
-        int[] scaleValues = { 1 };
-        int[] bitrates = { bitrate };
-        return getDefaultEncodingParameterList(
-                inputYuvName,
-                outputIvfBaseName,
-                encodeSeconds,
-                scaleValues,
-                frameWidth,
-                frameHeight,
-                frameRate,
-                bitrateMode,
-                bitrates,
-                syncEncoding).get(0);
-    }
-
-    /**
-     * Converts (interleaves) YUV420 planar to NV12.
-     * Assumes packed, macroblock-aligned frame with no cropping
-     * (visible/coded row length == stride).
-     */
-    private static byte[] YUV420ToNV(int width, int height, byte[] yuv) {
-        byte[] nv = new byte[yuv.length];
-        // Y plane we just copy.
-        System.arraycopy(yuv, 0, nv, 0, width * height);
-
-        // U & V plane we interleave.
-        int u_offset = width * height;
-        int v_offset = u_offset + u_offset / 4;
-        int nv_offset = width * height;
-        for (int i = 0; i < width * height / 4; i++) {
-            nv[nv_offset++] = yuv[u_offset++];
-            nv[nv_offset++] = yuv[v_offset++];
-        }
-        return nv;
-    }
-
-    /**
-     * Converts (de-interleaves) NV12 to YUV420 planar.
-     * Stride may be greater than width, slice height may be greater than height.
-     */
-    private static byte[] NV12ToYUV420(int width, int height,
-            int stride, int sliceHeight, byte[] nv12) {
-        byte[] yuv = new byte[width * height * 3 / 2];
-
-        // Y plane we just copy.
-        for (int i = 0; i < height; i++) {
-            System.arraycopy(nv12, i * stride, yuv, i * width, width);
-        }
-
-        // U & V plane - de-interleave.
-        int u_offset = width * height;
-        int v_offset = u_offset + u_offset / 4;
-        int nv_offset;
-        for (int i = 0; i < height / 2; i++) {
-            nv_offset = stride * (sliceHeight + i);
-            for (int j = 0; j < width / 2; j++) {
-                yuv[u_offset++] = nv12[nv_offset++];
-                yuv[v_offset++] = nv12[nv_offset++];
-            }
-        }
-        return yuv;
-    }
-
-    /**
-     * Packs YUV420 frame by moving it to a smaller size buffer with stride and slice
-     * height equal to the original frame width and height.
-     */
-    private static byte[] PackYUV420(int width, int height,
-            int stride, int sliceHeight, byte[] src) {
-        byte[] dst = new byte[width * height * 3 / 2];
-        // Y copy.
-        for (int i = 0; i < height; i++) {
-            System.arraycopy(src, i * stride, dst, i * width, width);
-        }
-        // U and V copy.
-        int u_src_offset = stride * sliceHeight;
-        int v_src_offset = u_src_offset + u_src_offset / 4;
-        int u_dst_offset = width * height;
-        int v_dst_offset = u_dst_offset + u_dst_offset / 4;
-        for (int i = 0; i < height / 2; i++) {
-            System.arraycopy(src, u_src_offset + i * (stride / 2),
-                    dst, u_dst_offset + i * (width / 2), width / 2);
-            System.arraycopy(src, v_src_offset + i * (stride / 2),
-                    dst, v_dst_offset + i * (width / 2), width / 2);
-        }
-        return dst;
-    }
-
-
-    private static void imageUpscale1To2(byte[] src, int srcByteOffset, int srcStride,
-            byte[] dst, int dstByteOffset, int dstWidth, int dstHeight) {
-        for (int i = 0; i < dstHeight/2 - 1; i++) {
-            int dstOffset0 = 2 * i * dstWidth + dstByteOffset;
-            int dstOffset1 = dstOffset0 + dstWidth;
-            int srcOffset0 = i * srcStride + srcByteOffset;
-            int srcOffset1 = srcOffset0 + srcStride;
-            int pixel00 = (int)src[srcOffset0++] & 0xff;
-            int pixel10 = (int)src[srcOffset1++] & 0xff;
-            for (int j = 0; j < dstWidth/2 - 1; j++) {
-                int pixel01 = (int)src[srcOffset0++] & 0xff;
-                int pixel11 = (int)src[srcOffset1++] & 0xff;
-                dst[dstOffset0++] = (byte)pixel00;
-                dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
-                dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
-                dst[dstOffset1++] = (byte)((pixel00 + pixel01 + pixel10 + pixel11 + 2) / 4);
-                pixel00 = pixel01;
-                pixel10 = pixel11;
-            }
-            // last column
-            dst[dstOffset0++] = (byte)pixel00;
-            dst[dstOffset0++] = (byte)pixel00;
-            dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
-            dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
-        }
-
-        // last row
-        int dstOffset0 = (dstHeight - 2) * dstWidth + dstByteOffset;
-        int dstOffset1 = dstOffset0 + dstWidth;
-        int srcOffset0 = (dstHeight/2 - 1) * srcStride + srcByteOffset;
-        int pixel00 = (int)src[srcOffset0++] & 0xff;
-        for (int j = 0; j < dstWidth/2 - 1; j++) {
-            int pixel01 = (int)src[srcOffset0++] & 0xff;
-            dst[dstOffset0++] = (byte)pixel00;
-            dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
-            dst[dstOffset1++] = (byte)pixel00;
-            dst[dstOffset1++] = (byte)((pixel00 + pixel01 + 1) / 2);
-            pixel00 = pixel01;
-        }
-        // the very last pixel - bottom right
-        dst[dstOffset0++] = (byte)pixel00;
-        dst[dstOffset0++] = (byte)pixel00;
-        dst[dstOffset1++] = (byte)pixel00;
-        dst[dstOffset1++] = (byte)pixel00;
-    }
-
-    /**
-    * Up-scale image.
-    * Scale factor is defined by source and destination width ratio.
-    * Only 1:2 and 1:4 up-scaling is supported for now.
-    * For 640x480 -> 1280x720 conversion only top 640x360 part of the original
-    * image is scaled.
-    */
-    private static byte[] imageScale(byte[] src, int srcWidth, int srcHeight,
-            int dstWidth, int dstHeight) throws Exception {
-        int srcYSize = srcWidth * srcHeight;
-        int dstYSize = dstWidth * dstHeight;
-        byte[] dst = null;
-        if (dstWidth == 2 * srcWidth && dstHeight <= 2 * srcHeight) {
-            // 1:2 upscale
-            dst = new byte[dstWidth * dstHeight * 3 / 2];
-            imageUpscale1To2(src, 0, srcWidth,
-                    dst, 0, dstWidth, dstHeight);                                 // Y
-            imageUpscale1To2(src, srcYSize, srcWidth / 2,
-                    dst, dstYSize, dstWidth / 2, dstHeight / 2);                  // U
-            imageUpscale1To2(src, srcYSize * 5 / 4, srcWidth / 2,
-                    dst, dstYSize * 5 / 4, dstWidth / 2, dstHeight / 2);          // V
-        } else if (dstWidth == 4 * srcWidth && dstHeight <= 4 * srcHeight) {
-            // 1:4 upscale - in two steps
-            int midWidth = 2 * srcWidth;
-            int midHeight = 2 * srcHeight;
-            byte[] midBuffer = imageScale(src, srcWidth, srcHeight, midWidth, midHeight);
-            dst = imageScale(midBuffer, midWidth, midHeight, dstWidth, dstHeight);
-
-        } else {
-            throw new RuntimeException("Can not find proper scaling function");
-        }
-
-        return dst;
-    }
-
-    private void cacheScaledImage(
-            String srcYuvFilename, int srcResourceId, int srcFrameWidth, int srcFrameHeight,
-            String dstYuvFilename, int dstFrameWidth, int dstFrameHeight) throws Exception {
-        InputStream srcStream = OpenFileOrResourceId(srcYuvFilename, srcResourceId);
-        FileOutputStream dstFile = new FileOutputStream(dstYuvFilename, false);
-        int srcFrameSize = srcFrameWidth * srcFrameHeight * 3 / 2;
-        byte[] srcFrame = new byte[srcFrameSize];
-        byte[] dstFrame = null;
-        Log.d(TAG, "Scale to " + dstFrameWidth + " x " + dstFrameHeight + ". -> " + dstYuvFilename);
-        while (true) {
-            int bytesRead = srcStream.read(srcFrame);
-            if (bytesRead != srcFrame.length) {
-                break;
-            }
-            if (dstFrameWidth == srcFrameWidth && dstFrameHeight == srcFrameHeight) {
-                dstFrame = srcFrame;
-            } else {
-                dstFrame = imageScale(srcFrame, srcFrameWidth, srcFrameHeight,
-                        dstFrameWidth, dstFrameHeight);
-            }
-            dstFile.write(dstFrame);
-        }
-        srcStream.close();
-        dstFile.close();
-    }
-
-
-    /**
-     * A basic check if an encoded stream is decodable.
-     *
-     * The most basic confirmation we can get about a frame
-     * being properly encoded is trying to decode it.
-     * (Especially in realtime mode encode output is non-
-     * deterministic, therefore a more thorough check like
-     * md5 sum comparison wouldn't work.)
-     *
-     * Indeed, MediaCodec will raise an IllegalStateException
-     * whenever vp8 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.
-     */
-    protected ArrayList<MediaCodec.BufferInfo> decode(
-            String inputIvfFilename,
-            String outputYuvFilename,
-            int frameRate,
-            boolean forceGoogleDecoder) throws Exception {
-        ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
-
-        // Open input/output.
-        IvfReader ivf = new IvfReader(inputIvfFilename);
-        int frameWidth = ivf.getWidth();
-        int frameHeight = ivf.getHeight();
-        int frameCount = ivf.getFrameCount();
-        int frameStride = frameWidth;
-        int frameSliceHeight = frameHeight;
-        assertTrue(frameWidth > 0);
-        assertTrue(frameHeight > 0);
-        assertTrue(frameCount > 0);
-
-        // Create decoder.
-        MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, ivf.getWidth(), ivf.getHeight());
-        CodecProperties properties = getVpxCodecProperties(
-                false /* encoder */, format, forceGoogleDecoder);
-        if (properties == null) {
-            ivf.close();
-            return null;
-        }
-        int frameColorFormat = properties.colorFormat;
-        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
-
-        FileOutputStream yuv = null;
-        if (outputYuvFilename != null) {
-            yuv = new FileOutputStream(outputYuvFilename, false);
-        }
-
-        Log.d(TAG, "Creating decoder " + properties.codecName +
-                ". Color format: 0x" + Integer.toHexString(frameColorFormat) +
-                ". " + frameWidth + " x " + frameHeight);
-        Log.d(TAG, "  Format: " + format);
-        Log.d(TAG, "  In: " + inputIvfFilename + ". Out:" + outputYuvFilename);
-        MediaCodec decoder = MediaCodec.createByCodecName(properties.codecName);
-        decoder.configure(format,
-                          null,  // surface
-                          null,  // crypto
-                          0);    // flags
-        decoder.start();
-
-        ByteBuffer[] inputBuffers = decoder.getInputBuffers();
-        ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
-        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
-
-        // decode loop
-        int inputFrameIndex = 0;
-        int outputFrameIndex = 0;
-        long inPresentationTimeUs = 0;
-        long outPresentationTimeUs = 0;
-        boolean sawOutputEOS = false;
-        boolean sawInputEOS = false;
-
-        while (!sawOutputEOS) {
-            if (!sawInputEOS) {
-                int inputBufIndex = decoder.dequeueInputBuffer(DEFAULT_DEQUEUE_TIMEOUT_US);
-                if (inputBufIndex >= 0) {
-                    byte[] frame = ivf.readFrame(inputFrameIndex);
-
-                    if (inputFrameIndex == frameCount - 1) {
-                        Log.d(TAG, "  Input EOS for frame # " + inputFrameIndex);
-                        sawInputEOS = true;
-                    }
-
-                    inputBuffers[inputBufIndex].clear();
-                    inputBuffers[inputBufIndex].put(frame);
-                    inputBuffers[inputBufIndex].rewind();
-                    inPresentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
-
-                    decoder.queueInputBuffer(
-                            inputBufIndex,
-                            0,  // offset
-                            frame.length,
-                            inPresentationTimeUs,
-                            sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
-                    inputFrameIndex++;
-                }
-            }
-
-            int result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
-            while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
-                    result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
-                    outputBuffers = decoder.getOutputBuffers();
-                } else  if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                    // Process format change
-                    format = decoder.getOutputFormat();
-                    frameWidth = format.getInteger(MediaFormat.KEY_WIDTH);
-                    frameHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
-                    frameColorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
-                    Log.d(TAG, "Decoder output format change. Color: 0x" +
-                            Integer.toHexString(frameColorFormat));
-                    Log.d(TAG, "Format: " + format.toString());
-
-                    // Parse frame and slice height from undocumented values
-                    if (format.containsKey("stride")) {
-                        frameStride = format.getInteger("stride");
-                    } else {
-                        frameStride = frameWidth;
-                    }
-                    if (format.containsKey("slice-height")) {
-                        frameSliceHeight = format.getInteger("slice-height");
-                    } else {
-                        frameSliceHeight = frameHeight;
-                    }
-                    Log.d(TAG, "Frame stride and slice height: " + frameStride +
-                            " x " + frameSliceHeight);
-                    frameStride = Math.max(frameWidth, frameStride);
-                    frameSliceHeight = Math.max(frameHeight, frameSliceHeight);
-                }
-                result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
-            }
-            if (result >= 0) {
-                int outputBufIndex = result;
-                outPresentationTimeUs = bufferInfo.presentationTimeUs;
-                Log.v(TAG, "Writing buffer # " + outputFrameIndex +
-                        ". Size: " + bufferInfo.size +
-                        ". InTime: " + (inPresentationTimeUs + 500)/1000 +
-                        ". OutTime: " + (outPresentationTimeUs + 500)/1000);
-                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    sawOutputEOS = true;
-                    Log.d(TAG, "   Output EOS for frame # " + outputFrameIndex);
-                }
-
-                if (bufferInfo.size > 0) {
-                    // Save decoder output to yuv file.
-                    if (yuv != null) {
-                        byte[] frame = new byte[bufferInfo.size];
-                        outputBuffers[outputBufIndex].position(bufferInfo.offset);
-                        outputBuffers[outputBufIndex].get(frame, 0, bufferInfo.size);
-                        // Convert NV12 to YUV420 if necessary.
-                        if (frameColorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
-                            frame = NV12ToYUV420(frameWidth, frameHeight,
-                                    frameStride, frameSliceHeight, frame);
-                        }
-                        int writeLength = Math.min(frameWidth * frameHeight * 3 / 2, frame.length);
-                        // Pack frame if necessary.
-                        if (writeLength < frame.length &&
-                                (frameStride > frameWidth || frameSliceHeight > frameHeight)) {
-                            frame = PackYUV420(frameWidth, frameHeight,
-                                    frameStride, frameSliceHeight, frame);
-                        }
-                        yuv.write(frame, 0, writeLength);
-                    }
-                    outputFrameIndex++;
-
-                    // Update statistics - store presentation time delay in offset
-                    long presentationTimeUsDelta = inPresentationTimeUs - outPresentationTimeUs;
-                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
-                    bufferInfoCopy.set((int)presentationTimeUsDelta, bufferInfo.size,
-                            outPresentationTimeUs, bufferInfo.flags);
-                    bufferInfos.add(bufferInfoCopy);
-                }
-                decoder.releaseOutputBuffer(outputBufIndex, false);
-            }
-        }
-        decoder.stop();
-        decoder.release();
-        ivf.close();
-        if (yuv != null) {
-            yuv.close();
-        }
-
-        return bufferInfos;
-    }
-
-
-    /**
-     * Helper function to return InputStream from either filename (if set)
-     * or resource id (if filename is not set).
-     */
-    private InputStream OpenFileOrResourceId(String filename, int resourceId) throws Exception {
-        if (filename != null) {
-            return new FileInputStream(filename);
-        }
-        return mResources.openRawResource(resourceId);
-    }
-
-    /**
-     * Results of frame encoding.
-     */
-    protected class MediaEncoderOutput {
-        public long inPresentationTimeUs;
-        public long outPresentationTimeUs;
-        public boolean outputGenerated;
-        public int flags;
-        public byte[] buffer;
-    }
-
-    protected class MediaEncoderAsyncHelper {
-        private final EncoderOutputStreamParameters mStreamParams;
-        private final CodecProperties mProperties;
-        private final ArrayList<MediaCodec.BufferInfo> mBufferInfos;
-        private final IvfWriter mIvf;
-        private final byte[] mSrcFrame;
-
-        private InputStream mYuvStream;
-        private int mInputFrameIndex;
-
-        MediaEncoderAsyncHelper(
-                EncoderOutputStreamParameters streamParams,
-                CodecProperties properties,
-                ArrayList<MediaCodec.BufferInfo> bufferInfos,
-                IvfWriter ivf)
-                throws Exception {
-            mStreamParams = streamParams;
-            mProperties = properties;
-            mBufferInfos = bufferInfos;
-            mIvf = ivf;
-
-            int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
-            mSrcFrame = new byte[srcFrameSize];
-
-            mYuvStream = OpenFileOrResourceId(
-                    streamParams.inputYuvFilename, streamParams.inputResourceId);
-        }
-
-        public byte[] getInputFrame() {
-            // Check EOS
-            if (mStreamParams.frameCount == 0
-                    || (mStreamParams.frameCount > 0
-                            && mInputFrameIndex >= mStreamParams.frameCount)) {
-                Log.d(TAG, "---Sending EOS empty frame for frame # " + mInputFrameIndex);
-                return null;
-            }
-
-            try {
-                int bytesRead = mYuvStream.read(mSrcFrame);
-
-                if (bytesRead == -1) {
-                    // rewind to beginning of file
-                    mYuvStream.close();
-                    mYuvStream = OpenFileOrResourceId(
-                            mStreamParams.inputYuvFilename, mStreamParams.inputResourceId);
-                    bytesRead = mYuvStream.read(mSrcFrame);
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to read YUV file.");
-                return null;
-            }
-            mInputFrameIndex++;
-
-            // Convert YUV420 to NV12 if necessary
-            if (mProperties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
-                return YUV420ToNV(mStreamParams.frameWidth, mStreamParams.frameHeight,
-                        mSrcFrame);
-            } else {
-                return mSrcFrame;
-            }
-        }
-
-        public boolean saveOutputFrame(MediaEncoderOutput out) {
-            if (out.outputGenerated) {
-                if (out.buffer.length > 0) {
-                    // Save frame
-                    try {
-                        mIvf.writeFrame(out.buffer, out.outPresentationTimeUs);
-                    } catch (Exception e) {
-                        Log.d(TAG, "Failed to write frame");
-                        return true;
-                    }
-
-                    // Update statistics - store presentation time delay in offset
-                    long presentationTimeUsDelta = out.inPresentationTimeUs -
-                            out.outPresentationTimeUs;
-                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
-                    bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
-                            out.outPresentationTimeUs, out.flags);
-                    mBufferInfos.add(bufferInfoCopy);
-                }
-                // Detect output EOS
-                if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    Log.d(TAG, "----Output EOS ");
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Video encoder wrapper class.
-     * Allows to run the encoder either in a callee's thread or in a looper thread
-     * using buffer dequeue ready notification callbacks.
-     *
-     * Function feedInput() is used to send raw video frame to the encoder input. When encoder
-     * is configured to run in async mode the function will run in a looper thread.
-     * Encoded frame can be retrieved by calling getOutput() function.
-     */
-    protected class MediaEncoderAsync extends Thread {
-        private int mId;
-        private MediaCodec mCodec;
-        private MediaFormat mFormat;
-        private ByteBuffer[] mInputBuffers;
-        private ByteBuffer[] mOutputBuffers;
-        private int mInputFrameIndex;
-        private int mOutputFrameIndex;
-        private int mInputBufIndex;
-        private int mFrameRate;
-        private long mTimeout;
-        private MediaCodec.BufferInfo mBufferInfo;
-        private long mInPresentationTimeUs;
-        private long mOutPresentationTimeUs;
-        private boolean mAsync;
-        // Flag indicating if input frame was consumed by the encoder in feedInput() call.
-        private boolean mConsumedInput;
-        // Result of frame encoding returned by getOutput() call.
-        private MediaEncoderOutput mOutput;
-        // Object used to signal that looper thread has started and Handler instance associated
-        // with looper thread has been allocated.
-        private final Object mThreadEvent = new Object();
-        // Object used to signal that MediaCodec buffer dequeue notification callback
-        // was received.
-        private final Object mCallbackEvent = new Object();
-        private Handler mHandler;
-        private boolean mCallbackReceived;
-        private MediaEncoderAsyncHelper mHelper;
-        private final Object mCompletionEvent = new Object();
-        private boolean mCompleted;
-
-        private MediaCodec.Callback mCallback = new MediaCodec.Callback() {
-            @Override
-            public void onInputBufferAvailable(MediaCodec codec, int index) {
-                if (mHelper == null) {
-                    Log.e(TAG, "async helper not available");
-                    return;
-                }
-
-                byte[] encFrame = mHelper.getInputFrame();
-                boolean inputEOS = (encFrame == null);
-
-                int encFrameLength = 0;
-                int flags = 0;
-                if (inputEOS) {
-                    flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                } else {
-                    encFrameLength = encFrame.length;
-
-                    ByteBuffer byteBuffer = mCodec.getInputBuffer(index);
-                    byteBuffer.put(encFrame);
-                    byteBuffer.rewind();
-
-                    mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
-
-                    Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
-                            ". InTime: " + (mInPresentationTimeUs + 500)/1000);
-
-                    mInputFrameIndex++;
-                }
-
-                mCodec.queueInputBuffer(
-                        index,
-                        0,  // offset
-                        encFrameLength,  // size
-                        mInPresentationTimeUs,
-                        flags);
-            }
-
-            @Override
-            public void onOutputBufferAvailable(MediaCodec codec,
-                    int index, MediaCodec.BufferInfo info) {
-                if (mHelper == null) {
-                    Log.e(TAG, "async helper not available");
-                    return;
-                }
-
-                MediaEncoderOutput out = new MediaEncoderOutput();
-
-                out.buffer = new byte[info.size];
-                ByteBuffer outputBuffer = mCodec.getOutputBuffer(index);
-                outputBuffer.get(out.buffer, 0, info.size);
-                mOutPresentationTimeUs = info.presentationTimeUs;
-
-                String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
-                if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
-                    logStr += " CONFIG. ";
-                }
-                if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
-                    logStr += " KEY. ";
-                }
-                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    logStr += " EOS. ";
-                }
-                logStr += " Size: " + info.size;
-                logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
-                        ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
-                Log.v(TAG, logStr);
-
-                if (mOutputFrameIndex == 0 &&
-                        ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
-                    throw new RuntimeException("First frame is not a sync frame.");
-                }
-
-                if (info.size > 0) {
-                    mOutputFrameIndex++;
-                    out.inPresentationTimeUs = mInPresentationTimeUs;
-                    out.outPresentationTimeUs = mOutPresentationTimeUs;
-                }
-                mCodec.releaseOutputBuffer(index, false);
-
-                out.flags = info.flags;
-                out.outputGenerated = true;
-
-                if (mHelper.saveOutputFrame(out)) {
-                    // output EOS
-                    signalCompletion();
-                }
-            }
-
-            @Override
-            public void onError(MediaCodec codec, CodecException e) {
-                Log.e(TAG, "onError: " + e
-                        + ", transient " + e.isTransient()
-                        + ", recoverable " + e.isRecoverable()
-                        + ", error " + e.getErrorCode());
-            }
-
-            @Override
-            public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
-                Log.i(TAG, "onOutputFormatChanged: " + format.toString());
-            }
-        };
-
-        private synchronized void requestStart() throws Exception {
-            mHandler = null;
-            start();
-            // Wait for Hander allocation
-            synchronized (mThreadEvent) {
-                while (mHandler == null) {
-                    mThreadEvent.wait();
-                }
-            }
-        }
-
-        public void setAsyncHelper(MediaEncoderAsyncHelper helper) {
-            mHelper = helper;
-        }
-
-        @Override
-        public void run() {
-            Looper.prepare();
-            synchronized (mThreadEvent) {
-                mHandler = new Handler();
-                mThreadEvent.notify();
-            }
-            Looper.loop();
-        }
-
-        private void runCallable(final Callable<?> callable) throws Exception {
-            if (mAsync) {
-                final Exception[] exception = new Exception[1];
-                final CountDownLatch countDownLatch = new CountDownLatch(1);
-                mHandler.post( new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            callable.call();
-                        } catch (Exception e) {
-                            exception[0] = e;
-                        } finally {
-                            countDownLatch.countDown();
-                        }
-                    }
-                } );
-
-                // Wait for task completion
-                countDownLatch.await();
-                if (exception[0] != null) {
-                    throw exception[0];
-                }
-            } else {
-                callable.call();
-            }
-        }
-
-        private synchronized void requestStop() throws Exception {
-            mHandler.post( new Runnable() {
-                @Override
-                public void run() {
-                    // This will run on the Looper thread
-                    Log.v(TAG, "MediaEncoder looper quitting");
-                    Looper.myLooper().quitSafely();
-                }
-            } );
-            // Wait for completion
-            join();
-            mHandler = null;
-        }
-
-        private void createCodecInternal(final String name,
-                final MediaFormat format, final long timeout) throws Exception {
-            mBufferInfo = new MediaCodec.BufferInfo();
-            mFormat = format;
-            mFrameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
-            mTimeout = timeout;
-            mInputFrameIndex = 0;
-            mOutputFrameIndex = 0;
-            mInPresentationTimeUs = 0;
-            mOutPresentationTimeUs = 0;
-
-            mCodec = MediaCodec.createByCodecName(name);
-            if (mAsync) {
-                mCodec.setCallback(mCallback);
-            }
-            mCodec.configure(mFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
-            mCodec.start();
-
-            // get the cached input/output only in sync mode
-            if (!mAsync) {
-                mInputBuffers = mCodec.getInputBuffers();
-                mOutputBuffers = mCodec.getOutputBuffers();
-            }
-        }
-
-        public void createCodec(int id, final String name, final MediaFormat format,
-                final long timeout, boolean async)  throws Exception {
-            mId = id;
-            mAsync = async;
-            if (mAsync) {
-                requestStart(); // start looper thread
-            }
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    createCodecInternal(name, format, timeout);
-                    return null;
-                }
-            } );
-        }
-
-        private void feedInputInternal(final byte[] encFrame, final boolean inputEOS) {
-            mConsumedInput = false;
-            // Feed input
-            mInputBufIndex = mCodec.dequeueInputBuffer(mTimeout);
-
-            if (mInputBufIndex >= 0) {
-                mInputBuffers[mInputBufIndex].clear();
-                mInputBuffers[mInputBufIndex].put(encFrame);
-                mInputBuffers[mInputBufIndex].rewind();
-                int encFrameLength = encFrame.length;
-                int flags = 0;
-                if (inputEOS) {
-                    encFrameLength = 0;
-                    flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                }
-                if (!inputEOS) {
-                    Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
-                            ". InTime: " + (mInPresentationTimeUs + 500)/1000);
-                    mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
-                    mInputFrameIndex++;
-                }
-
-                mCodec.queueInputBuffer(
-                        mInputBufIndex,
-                        0,  // offset
-                        encFrameLength,  // size
-                        mInPresentationTimeUs,
-                        flags);
-
-                mConsumedInput = true;
-            } else {
-                Log.v(TAG, "In " + mId + " - TRY_AGAIN_LATER");
-            }
-            mCallbackReceived = false;
-        }
-
-        public boolean feedInput(final byte[] encFrame, final boolean inputEOS) throws Exception {
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    feedInputInternal(encFrame, inputEOS);
-                    return null;
-                }
-            } );
-            return mConsumedInput;
-        }
-
-        private void getOutputInternal() {
-            mOutput = new MediaEncoderOutput();
-            mOutput.inPresentationTimeUs = mInPresentationTimeUs;
-            mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
-            mOutput.outputGenerated = false;
-
-            // Get output from the encoder
-            int result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
-            while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
-                    result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
-                    mOutputBuffers = mCodec.getOutputBuffers();
-                } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                    mFormat = mCodec.getOutputFormat();
-                    Log.d(TAG, "Format changed: " + mFormat.toString());
-                }
-                result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
-            }
-            if (result == MediaCodec.INFO_TRY_AGAIN_LATER) {
-                Log.v(TAG, "Out " + mId + " - TRY_AGAIN_LATER");
-            }
-
-            if (result >= 0) {
-                int outputBufIndex = result;
-                mOutput.buffer = new byte[mBufferInfo.size];
-                mOutputBuffers[outputBufIndex].position(mBufferInfo.offset);
-                mOutputBuffers[outputBufIndex].get(mOutput.buffer, 0, mBufferInfo.size);
-                mOutPresentationTimeUs = mBufferInfo.presentationTimeUs;
-
-                String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
-                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
-                    logStr += " CONFIG. ";
-                }
-                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
-                    logStr += " KEY. ";
-                }
-                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    logStr += " EOS. ";
-                }
-                logStr += " Size: " + mBufferInfo.size;
-                logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
-                        ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
-                Log.v(TAG, logStr);
-                if (mOutputFrameIndex == 0 &&
-                        ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
-                    throw new RuntimeException("First frame is not a sync frame.");
-                }
-
-                if (mBufferInfo.size > 0) {
-                    mOutputFrameIndex++;
-                    mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
-                }
-                mCodec.releaseOutputBuffer(outputBufIndex, false);
-
-                mOutput.flags = mBufferInfo.flags;
-                mOutput.outputGenerated = true;
-            }
-            mCallbackReceived = false;
-        }
-
-        public MediaEncoderOutput getOutput() throws Exception {
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    getOutputInternal();
-                    return null;
-                }
-            } );
-            return mOutput;
-        }
-
-        public void forceSyncFrame() throws Exception {
-            final Bundle syncFrame = new Bundle();
-            syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    mCodec.setParameters(syncFrame);
-                    return null;
-                }
-            } );
-        }
-
-        public void updateBitrate(int bitrate) throws Exception {
-            final Bundle bitrateUpdate = new Bundle();
-            bitrateUpdate.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bitrate);
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    mCodec.setParameters(bitrateUpdate);
-                    return null;
-                }
-            } );
-        }
-
-
-        public void waitForBufferEvent() throws Exception {
-            Log.v(TAG, "----Enc" + mId + " waiting for bufferEvent");
-            if (mAsync) {
-                synchronized (mCallbackEvent) {
-                    if (!mCallbackReceived) {
-                        mCallbackEvent.wait(1000); // wait 1 sec for a callback
-                        // throw an exception if callback was not received
-                        if (!mCallbackReceived) {
-                            throw new RuntimeException("MediaCodec callback was not received");
-                        }
-                    }
-                }
-            } else {
-                Thread.sleep(5);
-            }
-            Log.v(TAG, "----Waiting for bufferEvent done");
-        }
-
-
-        public void waitForCompletion(long timeoutMs) throws Exception {
-            synchronized (mCompletionEvent) {
-                long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
-
-                while (!mCompleted) {
-                    mCompletionEvent.wait(timeoutExpiredMs - System.currentTimeMillis());
-                    if (System.currentTimeMillis() >= timeoutExpiredMs) {
-                        throw new RuntimeException("encoding has timed out!");
-                    }
-                }
-            }
-        }
-
-        public void signalCompletion() {
-            synchronized (mCompletionEvent) {
-                mCompleted = true;
-                mCompletionEvent.notify();
-            }
-        }
-
-        public void deleteCodec() throws Exception {
-            runCallable( new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    mCodec.stop();
-                    mCodec.release();
-                    return null;
-                }
-            } );
-            if (mAsync) {
-                requestStop(); // Stop looper thread
-            }
-        }
-    }
-
-    /**
-     * Vp8 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.
-     *
-     * Color format of input file should be YUV420, and frameWidth,
-     * frameHeight should be supplied correctly as raw input file doesn't
-     * include any header data.
-     *
-     * @param streamParams  Structure with encoder parameters
-     * @return              Returns array of encoded frames information for each frame.
-     */
-    protected ArrayList<MediaCodec.BufferInfo> encode(
-            EncoderOutputStreamParameters streamParams) throws Exception {
-
-        ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
-        Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
-                streamParams.frameHeight);
-        int bitrate = streamParams.bitrateSet[0];
-
-        // Create minimal media format signifying desired output.
-        MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
-        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-        CodecProperties properties = getVpxCodecProperties(
-                true, format, streamParams.forceGoogleEncoder);
-        if (properties == null) {
-            return null;
-        }
-
-        // Open input/output
-        InputStream yuvStream = OpenFileOrResourceId(
-                streamParams.inputYuvFilename, streamParams.inputResourceId);
-        IvfWriter ivf = new IvfWriter(
-                streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
-
-        // Create a media format signifying desired output.
-        if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
-            format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
-        }
-        if (streamParams.temporalLayers > 0) {
-            format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
-        }
-        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
-        format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
-        int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
-                streamParams.frameRate;
-        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-
-        // Create encoder
-        Log.d(TAG, "Creating encoder " + properties.codecName +
-                ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
-                streamParams.frameWidth + " x " + streamParams.frameHeight +
-                ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
-                ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
-                ". Key frame:" + syncFrameInterval * streamParams.frameRate +
-                ". Force keyFrame: " + streamParams.syncForceFrameInterval);
-        Log.d(TAG, "  Format: " + format);
-        Log.d(TAG, "  Output ivf:" + streamParams.outputIvfFilename);
-        MediaEncoderAsync codec = new MediaEncoderAsync();
-        codec.createCodec(0, properties.codecName, format,
-                streamParams.timeoutDequeue, streamParams.runInLooperThread);
-
-        // encode loop
-        boolean sawInputEOS = false;  // no more data
-        boolean consumedInputEOS = false; // EOS flag is consumed dy encoder
-        boolean sawOutputEOS = false;
-        boolean inputConsumed = true;
-        int inputFrameIndex = 0;
-        int lastBitrate = bitrate;
-        int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
-        byte[] srcFrame = new byte[srcFrameSize];
-
-        while (!sawOutputEOS) {
-
-            // Read and feed input frame
-            if (!consumedInputEOS) {
-
-                // Read new input buffers - if previous input was consumed and no EOS
-                if (inputConsumed && !sawInputEOS) {
-                    int bytesRead = yuvStream.read(srcFrame);
-
-                    // Check EOS
-                    if (streamParams.frameCount > 0 && inputFrameIndex >= streamParams.frameCount) {
-                        sawInputEOS = true;
-                        Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
-                    }
-
-                    if (!sawInputEOS && bytesRead == -1) {
-                        if (streamParams.frameCount == 0) {
-                            sawInputEOS = true;
-                            Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
-                        } else {
-                            yuvStream.close();
-                            yuvStream = OpenFileOrResourceId(
-                                    streamParams.inputYuvFilename, streamParams.inputResourceId);
-                            bytesRead = yuvStream.read(srcFrame);
-                        }
-                    }
-
-                    // Force sync frame if syncForceFrameinterval is set.
-                    if (!sawInputEOS && inputFrameIndex > 0 &&
-                            streamParams.syncForceFrameInterval > 0 &&
-                            (inputFrameIndex % streamParams.syncForceFrameInterval) == 0) {
-                        Log.d(TAG, "---Requesting sync frame # " + inputFrameIndex);
-                        codec.forceSyncFrame();
-                    }
-
-                    // Dynamic bitrate change.
-                    if (!sawInputEOS && streamParams.bitrateSet.length > inputFrameIndex) {
-                        int newBitrate = streamParams.bitrateSet[inputFrameIndex];
-                        if (newBitrate != lastBitrate) {
-                            Log.d(TAG, "--- Requesting new bitrate " + newBitrate +
-                                    " for frame " + inputFrameIndex);
-                            codec.updateBitrate(newBitrate);
-                            lastBitrate = newBitrate;
-                        }
-                    }
-
-                    // Convert YUV420 to NV12 if necessary
-                    if (properties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
-                        srcFrame = YUV420ToNV(streamParams.frameWidth, streamParams.frameHeight,
-                                srcFrame);
-                    }
-                }
-
-                inputConsumed = codec.feedInput(srcFrame, sawInputEOS);
-                if (inputConsumed) {
-                    inputFrameIndex++;
-                    consumedInputEOS = sawInputEOS;
-                }
-            }
-
-            // Get output from the encoder
-            MediaEncoderOutput out = codec.getOutput();
-            if (out.outputGenerated) {
-                // Detect output EOS
-                if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                    Log.d(TAG, "----Output EOS ");
-                    sawOutputEOS = true;
-                }
-
-                if (out.buffer.length > 0) {
-                    // Save frame
-                    ivf.writeFrame(out.buffer, out.outPresentationTimeUs);
-
-                    // Update statistics - store presentation time delay in offset
-                    long presentationTimeUsDelta = out.inPresentationTimeUs -
-                            out.outPresentationTimeUs;
-                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
-                    bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
-                            out.outPresentationTimeUs, out.flags);
-                    bufferInfos.add(bufferInfoCopy);
-                }
-            }
-
-            // If codec is not ready to accept input/poutput - wait for buffer ready callback
-            if ((!inputConsumed || consumedInputEOS) && !out.outputGenerated) {
-                codec.waitForBufferEvent();
-            }
-        }
-
-        codec.deleteCodec();
-        ivf.close();
-        yuvStream.close();
-
-        return bufferInfos;
-    }
-
-    /**
-     * Vp8 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.
-     *
-     * Color format of input file should be YUV420, and frameWidth,
-     * frameHeight should be supplied correctly as raw input file doesn't
-     * include any header data.
-     *
-     * @param streamParams  Structure with encoder parameters
-     * @return              Returns array of encoded frames information for each frame.
-     */
-    protected ArrayList<MediaCodec.BufferInfo> encodeAsync(
-            EncoderOutputStreamParameters streamParams) throws Exception {
-        if (!streamParams.runInLooperThread) {
-            throw new RuntimeException("encodeAsync should run with a looper thread!");
-        }
-
-        ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
-        Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
-                streamParams.frameHeight);
-        int bitrate = streamParams.bitrateSet[0];
-
-        // Create minimal media format signifying desired output.
-        MediaFormat format = MediaFormat.createVideoFormat(
-                VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
-        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-        CodecProperties properties = getVpxCodecProperties(
-                true, format, streamParams.forceGoogleEncoder);
-        if (properties == null) {
-            return null;
-        }
-
-        // Open input/output
-        IvfWriter ivf = new IvfWriter(
-                streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
-
-        // Create a media format signifying desired output.
-        if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
-            format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
-        }
-        if (streamParams.temporalLayers > 0) {
-            format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
-        }
-        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
-        format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
-        int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
-                streamParams.frameRate;
-        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-
-        // Create encoder
-        Log.d(TAG, "Creating encoder " + properties.codecName +
-                ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
-                streamParams.frameWidth + " x " + streamParams.frameHeight +
-                ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
-                ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
-                ". Key frame:" + syncFrameInterval * streamParams.frameRate +
-                ". Force keyFrame: " + streamParams.syncForceFrameInterval);
-        Log.d(TAG, "  Format: " + format);
-        Log.d(TAG, "  Output ivf:" + streamParams.outputIvfFilename);
-
-        MediaEncoderAsync codec = new MediaEncoderAsync();
-        MediaEncoderAsyncHelper helper = new MediaEncoderAsyncHelper(
-                streamParams, properties, bufferInfos, ivf);
-
-        codec.setAsyncHelper(helper);
-        codec.createCodec(0, properties.codecName, format,
-                streamParams.timeoutDequeue, streamParams.runInLooperThread);
-        codec.waitForCompletion(DEFAULT_ENCODE_TIMEOUT_MS);
-
-        codec.deleteCodec();
-        ivf.close();
-
-        return bufferInfos;
-    }
-
-    /**
-     * Vp8 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.
-     *
-     * Color format of input file should be YUV420, and frameWidth,
-     * frameHeight should be supplied correctly as raw input file doesn't
-     * include any header data.
-     *
-     * @param srcFrameWidth     Frame width of input yuv file
-     * @param srcFrameHeight    Frame height of input yuv file
-     * @param encodingParams    Encoder parameters
-     * @return                  Returns 2D array of encoded frames information for each stream and
-     *                          for each frame.
-     */
-    protected ArrayList<ArrayList<MediaCodec.BufferInfo>> encodeSimulcast(
-            int srcFrameWidth,
-            int srcFrameHeight,
-            ArrayList<EncoderOutputStreamParameters> encodingParams)  throws Exception {
-        int numEncoders = encodingParams.size();
-
-        // Create arrays of input/output, formats, bitrates etc
-        ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos =
-                new ArrayList<ArrayList<MediaCodec.BufferInfo>>(numEncoders);
-        InputStream yuvStream[] = new InputStream[numEncoders];
-        IvfWriter[] ivf = new IvfWriter[numEncoders];
-        FileOutputStream[] yuvScaled = new FileOutputStream[numEncoders];
-        MediaFormat[] format = new MediaFormat[numEncoders];
-        MediaEncoderAsync[] codec = new MediaEncoderAsync[numEncoders];
-        int[] inputFrameIndex = new int[numEncoders];
-        boolean[] sawInputEOS = new boolean[numEncoders];
-        boolean[] consumedInputEOS = new boolean[numEncoders];
-        boolean[] inputConsumed = new boolean[numEncoders];
-        boolean[] bufferConsumed = new boolean[numEncoders];
-        boolean[] sawOutputEOS = new boolean[numEncoders];
-        byte[][] srcFrame = new byte[numEncoders][];
-        boolean sawOutputEOSTotal = false;
-        boolean bufferConsumedTotal = false;
-        CodecProperties[] codecProperties = new CodecProperties[numEncoders];
-
-        numEncoders = 0;
-        for (EncoderOutputStreamParameters params : encodingParams) {
-            int i = numEncoders;
-            Log.d(TAG, "Source resolution: " + params.frameWidth + " x " +
-                    params.frameHeight);
-            int bitrate = params.bitrateSet[0];
-
-            // Create minimal media format signifying desired output.
-            format[i] = MediaFormat.createVideoFormat(VP8_MIME,
-                    params.frameWidth, params.frameHeight);
-            format[i].setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-            CodecProperties properties = getVpxCodecProperties(
-                    true, format[i], params.forceGoogleEncoder);
-            if (properties == null) {
-                continue;
-            }
-
-            // Check if scaled image was created
-            int scale = params.frameWidth / srcFrameWidth;
-            if (!mScaledImages.contains(scale)) {
-                // resize image
-                cacheScaledImage(params.inputYuvFilename, params.inputResourceId,
-                        srcFrameWidth, srcFrameHeight,
-                        params.scaledYuvFilename, params.frameWidth, params.frameHeight);
-                mScaledImages.add(scale);
-            }
-
-            // Create buffer info storage
-            bufferInfos.add(new ArrayList<MediaCodec.BufferInfo>());
-
-            // Create YUV reader
-            yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
-
-            // Create IVF writer
-            ivf[i] = new IvfWriter(params.outputIvfFilename, params.frameWidth, params.frameHeight);
-
-            // Frame buffer
-            int frameSize = params.frameWidth * params.frameHeight * 3 / 2;
-            srcFrame[i] = new byte[frameSize];
-
-            // Create a media format signifying desired output.
-            if (params.bitrateType == VIDEO_ControlRateConstant) {
-                format[i].setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
-            }
-            if (params.temporalLayers > 0) {
-                format[i].setInteger("ts-layers", params.temporalLayers); // 1 temporal layer
-            }
-            format[i].setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
-            format[i].setInteger(MediaFormat.KEY_FRAME_RATE, params.frameRate);
-            int syncFrameInterval = (params.syncFrameInterval + params.frameRate/2) /
-                    params.frameRate; // in sec
-            format[i].setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-            // Create encoder
-            Log.d(TAG, "Creating encoder #" + i +" : " + properties.codecName +
-                    ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
-                    params.frameWidth + " x " + params.frameHeight +
-                    ". Bitrate: " + bitrate + " Bitrate type: " + params.bitrateType +
-                    ". Fps:" + params.frameRate + ". TS Layers: " + params.temporalLayers +
-                    ". Key frame:" + syncFrameInterval * params.frameRate +
-                    ". Force keyFrame: " + params.syncForceFrameInterval);
-            Log.d(TAG, "  Format: " + format[i]);
-            Log.d(TAG, "  Output ivf:" + params.outputIvfFilename);
-
-            // Create encoder
-            codec[i] = new MediaEncoderAsync();
-            codec[i].createCodec(i, properties.codecName, format[i],
-                    params.timeoutDequeue, params.runInLooperThread);
-            codecProperties[i] = new CodecProperties(properties.codecName, properties.colorFormat);
-
-            inputConsumed[i] = true;
-            ++numEncoders;
-        }
-        if (numEncoders == 0) {
-            Log.i(TAG, "no suitable encoders found for any of the streams");
-            return null;
-        }
-
-        while (!sawOutputEOSTotal) {
-            // Feed input buffer to all encoders
-            for (int i = 0; i < numEncoders; i++) {
-                bufferConsumed[i] = false;
-                if (consumedInputEOS[i]) {
-                    continue;
-                }
-
-                EncoderOutputStreamParameters params = encodingParams.get(i);
-                // Read new input buffers - if previous input was consumed and no EOS
-                if (inputConsumed[i] && !sawInputEOS[i]) {
-                    int bytesRead = yuvStream[i].read(srcFrame[i]);
-
-                    // Check EOS
-                    if (params.frameCount > 0 && inputFrameIndex[i] >= params.frameCount) {
-                        sawInputEOS[i] = true;
-                        Log.d(TAG, "---Enc" + i +
-                                ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
-                    }
-
-                    if (!sawInputEOS[i] && bytesRead == -1) {
-                        if (params.frameCount == 0) {
-                            sawInputEOS[i] = true;
-                            Log.d(TAG, "---Enc" + i +
-                                    ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
-                        } else {
-                            yuvStream[i].close();
-                            yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
-                            bytesRead = yuvStream[i].read(srcFrame[i]);
-                        }
-                    }
-
-                    // Convert YUV420 to NV12 if necessary
-                    if (codecProperties[i].colorFormat !=
-                            CodecCapabilities.COLOR_FormatYUV420Planar) {
-                        srcFrame[i] =
-                            YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i]);
-                    }
-                }
-
-                inputConsumed[i] = codec[i].feedInput(srcFrame[i], sawInputEOS[i]);
-                if (inputConsumed[i]) {
-                    inputFrameIndex[i]++;
-                    consumedInputEOS[i] = sawInputEOS[i];
-                    bufferConsumed[i] = true;
-                }
-
-            }
-
-            // Get output from all encoders
-            for (int i = 0; i < numEncoders; i++) {
-                if (sawOutputEOS[i]) {
-                    continue;
-                }
-
-                MediaEncoderOutput out = codec[i].getOutput();
-                if (out.outputGenerated) {
-                    bufferConsumed[i] = true;
-                    // Detect output EOS
-                    if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                        Log.d(TAG, "----Enc" + i + ". Output EOS ");
-                        sawOutputEOS[i] = true;
-                    }
-
-                    if (out.buffer.length > 0) {
-                        // Save frame
-                        ivf[i].writeFrame(out.buffer, out.outPresentationTimeUs);
-
-                        // Update statistics - store presentation time delay in offset
-                        long presentationTimeUsDelta = out.inPresentationTimeUs -
-                                out.outPresentationTimeUs;
-                        MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
-                        bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
-                                out.outPresentationTimeUs, out.flags);
-                        bufferInfos.get(i).add(bufferInfoCopy);
-                    }
-                }
-            }
-
-            // If codec is not ready to accept input/output - wait for buffer ready callback
-            bufferConsumedTotal = false;
-            for (boolean bufferConsumedCurrent : bufferConsumed) {
-                bufferConsumedTotal |= bufferConsumedCurrent;
-            }
-            if (!bufferConsumedTotal) {
-                // Pick the encoder to wait for
-                for (int i = 0; i < numEncoders; i++) {
-                    if (!bufferConsumed[i] && !sawOutputEOS[i]) {
-                        codec[i].waitForBufferEvent();
-                        break;
-                    }
-                }
-            }
-
-            // Check if EOS happened for all encoders
-            sawOutputEOSTotal = true;
-            for (boolean sawOutputEOSStream : sawOutputEOS) {
-                sawOutputEOSTotal &= sawOutputEOSStream;
-            }
-        }
-
-        for (int i = 0; i < numEncoders; i++) {
-            codec[i].deleteCodec();
-            ivf[i].close();
-            yuvStream[i].close();
-            if (yuvScaled[i] != null) {
-                yuvScaled[i].close();
-            }
-        }
-
-        return bufferInfos;
-    }
-
-    /**
-     * Some encoding statistics.
-     */
-    protected class Vp8EncodingStatistics {
-        Vp8EncodingStatistics() {
-            mBitrates = new ArrayList<Integer>();
-            mFrames = new ArrayList<Integer>();
-            mKeyFrames = new ArrayList<Integer>();
-            mMinimumKeyFrameInterval = Integer.MAX_VALUE;
-        }
-
-        public ArrayList<Integer> mBitrates;// Bitrate values for each second of the encoded stream.
-        public ArrayList<Integer> mFrames; // Number of frames in each second of the encoded stream.
-        public int mAverageBitrate;         // Average stream bitrate.
-        public ArrayList<Integer> mKeyFrames;// Stores the position of key frames in a stream.
-        public int mAverageKeyFrameInterval; // Average key frame interval.
-        public int mMaximumKeyFrameInterval; // Maximum key frame interval.
-        public int mMinimumKeyFrameInterval; // Minimum key frame interval.
-    }
-
-    /**
-     * Calculates average bitrate and key frame interval for the encoded streams.
-     * Output mBitrates field will contain bitrate values for every second
-     * of the encoded stream.
-     * Average stream bitrate will be stored in mAverageBitrate field.
-     * mKeyFrames array will contain the position of key frames in the encoded stream and
-     * mKeyFrameInterval - average key frame interval.
-     */
-    protected Vp8EncodingStatistics computeEncodingStatistics(int encoderId,
-            ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
-        Vp8EncodingStatistics statistics = new Vp8EncodingStatistics();
-
-        int totalSize = 0;
-        int frames = 0;
-        int framesPerSecond = 0;
-        int totalFrameSizePerSecond = 0;
-        int maxFrameSize = 0;
-        int currentSecond;
-        int nextSecond = 0;
-        String keyFrameList = "  IFrame List: ";
-        String bitrateList = "  Bitrate list: ";
-        String framesList = "  FPS list: ";
-
-
-        for (int j = 0; j < bufferInfos.size(); j++) {
-            MediaCodec.BufferInfo info = bufferInfos.get(j);
-            currentSecond = (int)(info.presentationTimeUs / 1000000);
-            boolean lastFrame = (j == bufferInfos.size() - 1);
-            if (!lastFrame) {
-                nextSecond = (int)(bufferInfos.get(j+1).presentationTimeUs / 1000000);
-            }
-
-            totalSize += info.size;
-            totalFrameSizePerSecond += info.size;
-            maxFrameSize = Math.max(maxFrameSize, info.size);
-            framesPerSecond++;
-            frames++;
-
-            // Update the bitrate statistics if the next frame will
-            // be for the next second
-            if (lastFrame || nextSecond > currentSecond) {
-                int currentBitrate = totalFrameSizePerSecond * 8;
-                bitrateList += (currentBitrate + " ");
-                framesList += (framesPerSecond + " ");
-                statistics.mBitrates.add(currentBitrate);
-                statistics.mFrames.add(framesPerSecond);
-                totalFrameSizePerSecond = 0;
-                framesPerSecond = 0;
-            }
-
-            // Update key frame statistics.
-            if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
-                statistics.mKeyFrames.add(j);
-                keyFrameList += (j + "  ");
-            }
-        }
-        int duration = (int)(bufferInfos.get(bufferInfos.size() - 1).presentationTimeUs / 1000);
-        duration = (duration + 500) / 1000;
-        statistics.mAverageBitrate = (int)(((long)totalSize * 8) / duration);
-        Log.d(TAG, "Statistics for encoder # " + encoderId);
-        // Calculate average key frame interval in frames.
-        int keyFrames = statistics.mKeyFrames.size();
-        if (keyFrames > 1) {
-            statistics.mAverageKeyFrameInterval =
-                    statistics.mKeyFrames.get(keyFrames - 1) - statistics.mKeyFrames.get(0);
-            statistics.mAverageKeyFrameInterval =
-                    Math.round((float)statistics.mAverageKeyFrameInterval / (keyFrames - 1));
-            for (int j = 1; j < keyFrames; j++) {
-                int keyFrameInterval =
-                        statistics.mKeyFrames.get(j) - statistics.mKeyFrames.get(j - 1);
-                statistics.mMaximumKeyFrameInterval =
-                        Math.max(statistics.mMaximumKeyFrameInterval, keyFrameInterval);
-                statistics.mMinimumKeyFrameInterval =
-                        Math.min(statistics.mMinimumKeyFrameInterval, keyFrameInterval);
-            }
-            Log.d(TAG, "  Key frame intervals: Max: " + statistics.mMaximumKeyFrameInterval +
-                    ". Min: " + statistics.mMinimumKeyFrameInterval +
-                    ". Avg: " + statistics.mAverageKeyFrameInterval);
-        }
-        Log.d(TAG, "  Frames: " + frames + ". Duration: " + duration +
-                ". Total size: " + totalSize + ". Key frames: " + keyFrames);
-        Log.d(TAG, keyFrameList);
-        Log.d(TAG, bitrateList);
-        Log.d(TAG, framesList);
-        Log.d(TAG, "  Bitrate average: " + statistics.mAverageBitrate);
-        Log.d(TAG, "  Maximum frame size: " + maxFrameSize);
-
-        return statistics;
-    }
-
-    protected Vp8EncodingStatistics computeEncodingStatistics(
-            ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
-        return computeEncodingStatistics(0, bufferInfos);
-    }
-
-    protected ArrayList<Vp8EncodingStatistics> computeSimulcastEncodingStatistics(
-            ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos) {
-        int numCodecs = bufferInfos.size();
-        ArrayList<Vp8EncodingStatistics> statistics = new ArrayList<Vp8EncodingStatistics>();
-
-        for (int i = 0; i < numCodecs; i++) {
-            Vp8EncodingStatistics currentStatistics =
-                    computeEncodingStatistics(i, bufferInfos.get(i));
-            statistics.add(currentStatistics);
-        }
-        return statistics;
-    }
-
-    /**
-     * Calculates maximum latency for encoder/decoder based on buffer info array
-     * generated either by encoder or decoder.
-     */
-    protected int maxPresentationTimeDifference(ArrayList<MediaCodec.BufferInfo> bufferInfos) {
-        int maxValue = 0;
-        for (MediaCodec.BufferInfo bufferInfo : bufferInfos) {
-            maxValue = Math.max(maxValue,  bufferInfo.offset);
-        }
-        maxValue = (maxValue + 500) / 1000; // mcs -> ms
-        return maxValue;
-    }
-
-    /**
-     * Decoding PSNR statistics.
-     */
-    protected class Vp8DecodingStatistics {
-        Vp8DecodingStatistics() {
-            mMinimumPSNR = Integer.MAX_VALUE;
-        }
-        public double mAveragePSNR;
-        public double mMinimumPSNR;
-    }
-
-    /**
-     * Calculates PSNR value between two video frames.
-     */
-    private double computePSNR(byte[] data0, byte[] data1) {
-        long squareError = 0;
-        assertTrue(data0.length == data1.length);
-        int length = data0.length;
-        for (int i = 0 ; i < length; i++) {
-            int diff = ((int)data0[i] & 0xff) - ((int)data1[i] & 0xff);
-            squareError += diff * diff;
-        }
-        double meanSquareError = (double)squareError / length;
-        double psnr = 10 * Math.log10((double)255 * 255 / meanSquareError);
-        return psnr;
-    }
-
-    /**
-     * Calculates average and minimum PSNR values between
-     * set of reference and decoded video frames.
-     * Runs PSNR calculation for the full duration of the decoded data.
-     */
-    protected Vp8DecodingStatistics computeDecodingStatistics(
-            String referenceYuvFilename,
-            int referenceYuvRawId,
-            String decodedYuvFilename,
-            int width,
-            int height) throws Exception {
-        Vp8DecodingStatistics statistics = new Vp8DecodingStatistics();
-        InputStream referenceStream =
-                OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
-        InputStream decodedStream = new FileInputStream(decodedYuvFilename);
-
-        int ySize = width * height;
-        int uvSize = width * height / 4;
-        byte[] yRef = new byte[ySize];
-        byte[] yDec = new byte[ySize];
-        byte[] uvRef = new byte[uvSize];
-        byte[] uvDec = new byte[uvSize];
-
-        int frames = 0;
-        double averageYPSNR = 0;
-        double averageUPSNR = 0;
-        double averageVPSNR = 0;
-        double minimumYPSNR = Integer.MAX_VALUE;
-        double minimumUPSNR = Integer.MAX_VALUE;
-        double minimumVPSNR = Integer.MAX_VALUE;
-        int minimumPSNRFrameIndex = 0;
-
-        while (true) {
-            // Calculate Y PSNR.
-            int bytesReadRef = referenceStream.read(yRef);
-            int bytesReadDec = decodedStream.read(yDec);
-            if (bytesReadDec == -1) {
-                break;
-            }
-            if (bytesReadRef == -1) {
-                // Reference file wrapping up
-                referenceStream.close();
-                referenceStream =
-                        OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
-                bytesReadRef = referenceStream.read(yRef);
-            }
-            double curYPSNR = computePSNR(yRef, yDec);
-            averageYPSNR += curYPSNR;
-            minimumYPSNR = Math.min(minimumYPSNR, curYPSNR);
-            double curMinimumPSNR = curYPSNR;
-
-            // Calculate U PSNR.
-            bytesReadRef = referenceStream.read(uvRef);
-            bytesReadDec = decodedStream.read(uvDec);
-            double curUPSNR = computePSNR(uvRef, uvDec);
-            averageUPSNR += curUPSNR;
-            minimumUPSNR = Math.min(minimumUPSNR, curUPSNR);
-            curMinimumPSNR = Math.min(curMinimumPSNR, curUPSNR);
-
-            // Calculate V PSNR.
-            bytesReadRef = referenceStream.read(uvRef);
-            bytesReadDec = decodedStream.read(uvDec);
-            double curVPSNR = computePSNR(uvRef, uvDec);
-            averageVPSNR += curVPSNR;
-            minimumVPSNR = Math.min(minimumVPSNR, curVPSNR);
-            curMinimumPSNR = Math.min(curMinimumPSNR, curVPSNR);
-
-            // Frame index for minimum PSNR value - help to detect possible distortions
-            if (curMinimumPSNR < statistics.mMinimumPSNR) {
-                statistics.mMinimumPSNR = curMinimumPSNR;
-                minimumPSNRFrameIndex = frames;
-            }
-
-            String logStr = String.format(Locale.US, "PSNR #%d: Y: %.2f. U: %.2f. V: %.2f",
-                    frames, curYPSNR, curUPSNR, curVPSNR);
-            Log.v(TAG, logStr);
-
-            frames++;
-        }
-
-        averageYPSNR /= frames;
-        averageUPSNR /= frames;
-        averageVPSNR /= frames;
-        statistics.mAveragePSNR = (4 * averageYPSNR + averageUPSNR + averageVPSNR) / 6;
-
-        Log.d(TAG, "PSNR statistics for " + frames + " frames.");
-        String logStr = String.format(Locale.US,
-                "Average PSNR: Y: %.1f. U: %.1f. V: %.1f. Average: %.1f",
-                averageYPSNR, averageUPSNR, averageVPSNR, statistics.mAveragePSNR);
-        Log.d(TAG, logStr);
-        logStr = String.format(Locale.US,
-                "Minimum PSNR: Y: %.1f. U: %.1f. V: %.1f. Overall: %.1f at frame %d",
-                minimumYPSNR, minimumUPSNR, minimumVPSNR,
-                statistics.mMinimumPSNR, minimumPSNRFrameIndex);
-        Log.d(TAG, logStr);
-
-        referenceStream.close();
-        decodedStream.close();
-        return statistics;
-    }
-}
-
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
deleted file mode 100644
index 5552f6c..0000000
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.util.Log;
-import android.media.cts.R;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Verification test for vp8 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
- * calculate PSNR values for various bitrates.
- */
-public class Vp8EncoderTest extends Vp8CodecTestBase {
-
-    private static final String ENCODED_IVF_BASE = "football";
-    private static final String INPUT_YUV = null;
-    private static final String OUTPUT_YUV = SDCARD_DIR + File.separator +
-            ENCODED_IVF_BASE + "_out.yuv";
-
-    // YUV stream properties.
-    private static final int WIDTH = 320;
-    private static final int HEIGHT = 240;
-    private static final int FPS = 30;
-    // Default encoding bitrate.
-    private static final int BITRATE = 400000;
-    // Default encoding bitrate mode
-    private static final int BITRATE_MODE = VIDEO_ControlRateVariable;
-    // List of bitrates used in quality and basic bitrate tests.
-    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.
-    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.
-    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;
-    // Maximum allowed minimum PSNR difference of encoder comparing to reference Google encoder.
-    private static final double MAX_MINIMUM_PSNR_DIFFERENCE = 4;
-    // Maximum allowed average PSNR difference of the encoder running in a looper thread with 0 ms
-    // buffer dequeue timeout comparing to the encoder running in a callee's thread with 100 ms
-    // buffer dequeue timeout.
-    private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 0.5;
-    // Maximum allowed minimum PSNR difference of the encoder running in a looper thread
-    // comparing to the encoder running in a callee's thread.
-    private static final double MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE = 2;
-    // Maximum allowed average key frame interval variation from the target value.
-    private static final int MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION = 1;
-    // Maximum allowed key frame interval variation from the target value.
-    private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
-
-    /**
-     * A basic test for VP8 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 {
-        int encodeSeconds = 9;
-        boolean skipped = true;
-
-        for (int targetBitrate : TEST_BITRATES_SET) {
-            EncoderOutputStreamParameters params = getDefaultEncodingParameters(
-                    INPUT_YUV,
-                    ENCODED_IVF_BASE,
-                    encodeSeconds,
-                    WIDTH,
-                    HEIGHT,
-                    FPS,
-                    BITRATE_MODE,
-                    targetBitrate,
-                    true);
-            ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
-            if (bufInfo == null) {
-                continue;
-            }
-            skipped = false;
-
-            Vp8EncodingStatistics 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);
-        }
-
-        if (skipped) {
-            Log.i(TAG, "SKIPPING testBasic(): codec is not supported");
-        }
-    }
-
-    /**
-     * Asynchronous encoding test for VP8 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 {
-        int encodeSeconds = 9;
-
-        // First test the encoder running in a looper thread with buffer callbacks enabled.
-        boolean syncEncoding = false;
-        EncoderOutputStreamParameters params = getDefaultEncodingParameters(
-                INPUT_YUV,
-                ENCODED_IVF_BASE,
-                encodeSeconds,
-                WIDTH,
-                HEIGHT,
-                FPS,
-                BITRATE_MODE,
-                BITRATE,
-                syncEncoding);
-        ArrayList<MediaCodec.BufferInfo> bufInfos = encodeAsync(params);
-        if (bufInfos == null) {
-            Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
-            return;
-        }
-        computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-        Vp8DecodingStatistics statisticsAsync = computeDecodingStatistics(
-                params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
-                params.frameWidth, params.frameHeight);
-
-
-        // Test the encoder running in a callee's thread.
-        syncEncoding = true;
-        params = getDefaultEncodingParameters(
-                INPUT_YUV,
-                ENCODED_IVF_BASE,
-                encodeSeconds,
-                WIDTH,
-                HEIGHT,
-                FPS,
-                BITRATE_MODE,
-                BITRATE,
-                syncEncoding);
-        bufInfos = encode(params);
-        if (bufInfos == null) {
-            Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
-            return;
-        }
-        computeEncodingStatistics(bufInfos);
-        decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-        Vp8DecodingStatistics statisticsSync = computeDecodingStatistics(
-                params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
-                params.frameWidth, params.frameHeight);
-
-        // Check PSNR difference.
-        Log.d(TAG, "PSNR Average: Async: " + statisticsAsync.mAveragePSNR +
-                ". Sync: " + statisticsSync.mAveragePSNR);
-        Log.d(TAG, "PSNR Minimum: Async: " + statisticsAsync.mMinimumPSNR +
-                ". Sync: " + statisticsSync.mMinimumPSNR);
-        if ((Math.abs(statisticsAsync.mAveragePSNR - statisticsSync.mAveragePSNR) >
-            MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE) ||
-            (Math.abs(statisticsAsync.mMinimumPSNR - statisticsSync.mMinimumPSNR) >
-            MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE)) {
-            throw new RuntimeException("Difference between PSNRs for async and sync encoders");
-        }
-    }
-
-    /**
-     * Check if MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME is honored.
-     *
-     * 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 {
-        int encodeSeconds = 9;
-
-        EncoderOutputStreamParameters params = getDefaultEncodingParameters(
-                INPUT_YUV,
-                ENCODED_IVF_BASE,
-                encodeSeconds,
-                WIDTH,
-                HEIGHT,
-                FPS,
-                BITRATE_MODE,
-                BITRATE,
-                true);
-        params.syncFrameInterval = encodeSeconds * FPS;
-        params.syncForceFrameInterval = FPS;
-        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
-        if (bufInfo == null) {
-            Log.i(TAG, "SKIPPING testSyncFrame(): no suitable encoder found");
-            return;
-        }
-
-        Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-
-        // First check if we got expected number of key frames.
-        int actualKeyFrames = statistics.mKeyFrames.size();
-        if (actualKeyFrames != encodeSeconds) {
-            throw new RuntimeException("Number of key frames " + actualKeyFrames +
-                    " is different from the expected " + encodeSeconds);
-        }
-
-        // Check key frame intervals:
-        // Average value should be within +/- 1 frame of the target value,
-        // maximum value should not be greater than target value + 3,
-        // and minimum value should not be less that target value - 3.
-        if (Math.abs(statistics.mAverageKeyFrameInterval - FPS) >
-            MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION ||
-            (statistics.mMaximumKeyFrameInterval - FPS > MAX_KEYFRAME_INTERVAL_VARIATION) ||
-            (FPS - statistics.mMinimumKeyFrameInterval > MAX_KEYFRAME_INTERVAL_VARIATION)) {
-            throw new RuntimeException(
-                    "Key frame intervals are different from the expected " + FPS);
-        }
-    }
-
-    /**
-     * Check if MediaCodec.PARAMETER_KEY_VIDEO_BITRATE is honored.
-     *
-     * 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 {
-        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,
-                encodeSeconds,
-                WIDTH,
-                HEIGHT,
-                FPS,
-                BITRATE_MODE,
-                bitrateTargetValues[0],
-                true);
-
-        // Number of seconds for each bitrate
-        int stepSeconds = encodeSeconds / bitrateTargetValues.length;
-        // Fill the bitrates values.
-        params.bitrateSet = new int[encodeSeconds * FPS];
-        for (int i = 0; i < bitrateTargetValues.length ; i++) {
-            Arrays.fill(params.bitrateSet,
-                    i * encodeSeconds * FPS / bitrateTargetValues.length,
-                    (i + 1) * encodeSeconds * FPS / bitrateTargetValues.length,
-                    bitrateTargetValues[i]);
-        }
-
-        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
-        if (bufInfo == null) {
-            Log.i(TAG, "SKIPPING testDynamicBitrateChange(): no suitable encoder found");
-            return;
-        }
-
-        Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-
-        // Calculate actual average bitrates  for every [stepSeconds] second.
-        int[] bitrateActualValues = new int[bitrateTargetValues.length];
-        for (int i = 0; i < bitrateTargetValues.length ; i++) {
-            bitrateActualValues[i] = 0;
-            for (int j = i * stepSeconds; j < (i + 1) * stepSeconds; j++) {
-                bitrateActualValues[i] += statistics.mBitrates.get(j);
-            }
-            bitrateActualValues[i] /= stepSeconds;
-            Log.d(TAG, "Actual bitrate for interval #" + i + " : " + bitrateActualValues[i] +
-                    ". Target: " + bitrateTargetValues[i]);
-
-            // Compare actual bitrate values to make sure at least same increasing/decreasing
-            // order as the target bitrate values.
-            for (int j = 0; j < i; j++) {
-                long differenceTarget = bitrateTargetValues[i] - bitrateTargetValues[j];
-                long differenceActual = bitrateActualValues[i] - bitrateActualValues[j];
-                if (differenceTarget * differenceActual < 0) {
-                    throw new RuntimeException("Target bitrates: " +
-                            bitrateTargetValues[j] + " , " + bitrateTargetValues[i] +
-                            ". Actual bitrates: "
-                            + bitrateActualValues[j] + " , " + bitrateActualValues[i]);
-                }
-            }
-        }
-    }
-
-     /**
-      * Check if encoder and decoder can run simultaneously on different threads.
-      *
-      * Encodes and decodes 9 seconds of raw stream sequentially in CBR mode,
-      * 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 {
-         // 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);
-         if (mcl.findEncoderForFormat(format) == null) {
-             Log.i(TAG, "SKIPPING testParallelEncodingAndDecoding(): no suitable encoder found");
-             return;
-         }
-
-         int encodeSeconds = 9;
-         final int[] bitrate = new int[1];
-         final double[] psnr = new double[1];
-         final Exception[] exceptionEncoder = new Exception[1];
-         final Exception[] exceptionDecoder = new Exception[1];
-         final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
-                 INPUT_YUV,
-                 ENCODED_IVF_BASE,
-                 encodeSeconds,
-                 WIDTH,
-                 HEIGHT,
-                 FPS,
-                 VIDEO_ControlRateConstant,
-                 BITRATE,
-                 true);
-         final String inputIvfFilename = params.outputIvfFilename;
-
-         Runnable runEncoder = new Runnable() {
-             public void run() {
-                 try {
-                     ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
-                     Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-                     bitrate[0] = statistics.mAverageBitrate;
-                 } catch (Exception e) {
-                     Log.e(TAG, "Encoder error: " + e.toString());
-                     exceptionEncoder[0] = e;
-                 }
-             }
-         };
-         Runnable runDecoder = new Runnable() {
-             public void run() {
-                 try {
-                     decode(inputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-                     Vp8DecodingStatistics statistics = computeDecodingStatistics(
-                            params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
-                            params.frameWidth, params.frameHeight);
-                     psnr[0] = statistics.mAveragePSNR;
-                 } catch (Exception e) {
-                     Log.e(TAG, "Decoder error: " + e.toString());
-                     exceptionDecoder[0] = e;
-                 }
-             }
-         };
-
-         // Sequential encoding and decoding.
-         runEncoder.run();
-         if (exceptionEncoder[0] != null) {
-             throw exceptionEncoder[0];
-         }
-         int referenceBitrate = bitrate[0];
-         runDecoder.run();
-         if (exceptionDecoder[0] != null) {
-             throw exceptionDecoder[0];
-         }
-         double referencePsnr = psnr[0];
-
-         // Parallel encoding and decoding.
-         params.outputIvfFilename = SDCARD_DIR + File.separator + ENCODED_IVF_BASE + "_copy.ivf";
-         Thread threadEncoder = new Thread(runEncoder);
-         Thread threadDecoder = new Thread(runDecoder);
-         threadEncoder.start();
-         threadDecoder.start();
-         threadEncoder.join();
-         threadDecoder.join();
-         if (exceptionEncoder[0] != null) {
-             throw exceptionEncoder[0];
-         }
-         if (exceptionDecoder[0] != null) {
-             throw exceptionDecoder[0];
-         }
-
-         // Compare bitrates and PSNRs for sequential and parallel cases.
-         Log.d(TAG, "Sequential bitrate: " + referenceBitrate + ". PSNR: " + referencePsnr);
-         Log.d(TAG, "Parallel bitrate: " + bitrate[0] + ". PSNR: " + psnr[0]);
-         assertEquals("Bitrate for sequenatial encoding" + referenceBitrate +
-                 " is different from parallel encoding " + bitrate[0],
-                 referenceBitrate, bitrate[0], MAX_BITRATE_VARIATION * referenceBitrate);
-         assertEquals("PSNR for sequenatial encoding" + referencePsnr +
-                 " is different from parallel encoding " + psnr[0],
-                 referencePsnr, psnr[0], MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE);
-     }
-
-
-    /**
-     * Check the encoder quality for various bitrates by calculating PSNR
-     *
-     * Run the the encoder for 9 seconds for each bitrate and calculate PSNR
-     * for each encoded stream.
-     * 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 {
-        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];
-        boolean[] completed = new boolean[TEST_BITRATES_SET.length];
-        boolean skipped = true;
-
-        // Run platform specific encoder for different bitrates
-        // and compare PSNR of codec with PSNR of reference Google codec.
-        for (int i = 0; i < TEST_BITRATES_SET.length; i++) {
-            EncoderOutputStreamParameters params = getDefaultEncodingParameters(
-                    INPUT_YUV,
-                    ENCODED_IVF_BASE,
-                    encodeSeconds,
-                    WIDTH,
-                    HEIGHT,
-                    FPS,
-                    BITRATE_MODE,
-                    TEST_BITRATES_SET[i],
-                    true);
-            if (encode(params) == null) {
-                // parameters not supported, try other bitrates
-                completed[i] = false;
-                continue;
-            }
-            completed[i] = true;
-            skipped = false;
-
-            decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
-            Vp8DecodingStatistics statistics = computeDecodingStatistics(
-                    params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
-                    params.frameWidth, params.frameHeight);
-            psnrPlatformCodecAverage[i] = statistics.mAveragePSNR;
-            psnrPlatformCodecMin[i] = statistics.mMinimumPSNR;
-        }
-
-        if (skipped) {
-            Log.i(TAG, "SKIPPING testEncoderQuality(): no bitrates supported");
-            return;
-        }
-
-        // First do a sanity check - higher bitrates should results in higher PSNR.
-        for (int i = 1; i < TEST_BITRATES_SET.length ; i++) {
-            if (!completed[i]) {
-                continue;
-            }
-            for (int j = 0; j < i; j++) {
-                if (!completed[j]) {
-                    continue;
-                }
-                double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
-                double differencePSNR = psnrPlatformCodecAverage[i] - psnrPlatformCodecAverage[j];
-                if (differenceBitrate * differencePSNR < 0) {
-                    throw new RuntimeException("Target bitrates: " +
-                            TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
-                            ". Actual PSNRs: "
-                            + psnrPlatformCodecAverage[j] + ", " + psnrPlatformCodecAverage[i]);
-                }
-            }
-        }
-
-        // Then compare average and minimum PSNR of platform codec with reference Google codec -
-        // average PSNR for platform codec should be no more than 2 dB less than reference PSNR
-        // and minumum PSNR - no more than 4 dB less than reference minimum PSNR.
-        // These PSNR difference numbers are arbitrary for now, will need further estimation
-        // when more devices with HW VP8 codec will appear.
-        for (int i = 0; i < TEST_BITRATES_SET.length ; i++) {
-            if (!completed[i]) {
-                continue;
-            }
-
-            Log.d(TAG, "Bitrate " + TEST_BITRATES_SET[i]);
-            Log.d(TAG, "Reference: Average: " + REFERENCE_AVERAGE_PSNR[i] + ". Minimum: " +
-                    REFERENCE_MINIMUM_PSNR[i]);
-            Log.d(TAG, "Platform:  Average: " + psnrPlatformCodecAverage[i] + ". Minimum: " +
-                    psnrPlatformCodecMin[i]);
-            if (psnrPlatformCodecAverage[i] < REFERENCE_AVERAGE_PSNR[i] -
-                    MAX_AVERAGE_PSNR_DIFFERENCE) {
-                throw new RuntimeException("Low average PSNR " + psnrPlatformCodecAverage[i] +
-                        " comparing to reference PSNR " + REFERENCE_AVERAGE_PSNR[i] +
-                        " for bitrate " + TEST_BITRATES_SET[i]);
-            }
-            if (psnrPlatformCodecMin[i] < REFERENCE_MINIMUM_PSNR[i] -
-                    MAX_MINIMUM_PSNR_DIFFERENCE) {
-                throw new RuntimeException("Low minimum PSNR " + psnrPlatformCodecMin[i] +
-                        " comparing to reference PSNR " + REFERENCE_MINIMUM_PSNR[i] +
-                        " for bitrate " + TEST_BITRATES_SET[i]);
-            }
-        }
-    }
-}
-
diff --git a/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
new file mode 100644
index 0000000..ea72225
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
@@ -0,0 +1,2016 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.Context;
+import android.content.res.Resources;
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.media.cts.R;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 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 the decoder to verify frames are decodable and to
+ * calculate PSNR values for various bitrates.
+ */
+public class VpxCodecTestBase extends AndroidTestCase {
+
+    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();
+
+    // Default timeout for MediaCodec buffer dequeue - 200 ms.
+    protected static final long DEFAULT_DEQUEUE_TIMEOUT_US = 200000;
+    // Default timeout for MediaEncoderAsync - 30 sec.
+    protected static final long DEFAULT_ENCODE_TIMEOUT_MS = 30000;
+    // Default sync frame interval in frames (zero means allow the encoder to auto-select
+    // key frame interval).
+    private static final int SYNC_FRAME_INTERVAL = 0;
+    // Video bitrate type - should be set to OMX_Video_ControlRateConstant from OMX_Video.h
+    protected static final int VIDEO_ControlRateVariable = 1;
+    protected static final int VIDEO_ControlRateConstant = 2;
+    // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
+    // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
+    private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
+    // Allowable color formats supported by codec - in order of preference.
+    private static final int[] mSupportedColorList = {
+            CodecCapabilities.COLOR_FormatYUV420Planar,
+            CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
+            CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
+            COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
+    };
+    // Scaled image cache list - contains scale factors, for which up-scaled frames
+    // were calculated and were written to yuv file.
+    ArrayList<Integer> mScaledImages = new ArrayList<Integer>();
+
+    private Resources mResources;
+
+    @Override
+    public void setContext(Context context) {
+        super.setContext(context);
+        mResources = mContext.getResources();
+    }
+
+    /**
+     *  VPx codec properties generated by getVpxCodecProperties() function.
+     */
+    private class CodecProperties {
+        CodecProperties(String codecName, int colorFormat) {
+            this.codecName = codecName;
+            this.colorFormat = colorFormat;
+        }
+        public boolean  isGoogleCodec() {
+            return codecName.toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
+        }
+
+        public final String codecName; // OpenMax component name for VPx codec.
+        public final int colorFormat;  // Color format supported by 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.
+     * If forceGoogleCodec parameter set to true the function always returns
+     * Google VPX codec.
+     * If forceGoogleCodec parameter set to false the functions looks for platform
+     * specific VPX codec first. If no platform specific codec exist, falls back to
+     * Google VPX codec.
+     *
+     * @param isEncoder     Flag if encoder is requested.
+     * @param forceGoogleCodec  Forces to use Google codec.
+     */
+    private CodecProperties getVpxCodecProperties(
+            boolean isEncoder,
+            MediaFormat format,
+            boolean forceGoogleCodec) throws Exception {
+        CodecProperties codecProperties = null;
+        String mime = format.getString(MediaFormat.KEY_MIME);
+
+        // Loop through the list of omx components in case platform specific codec
+        // is requested.
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+            if (isEncoder != codecInfo.isEncoder()) {
+                continue;
+            }
+            Log.v(TAG, codecInfo.getName());
+            // TODO: remove dependence of Google from the test
+            // Check if this is Google codec - we should ignore it.
+            boolean isGoogleCodec =
+                codecInfo.getName().toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
+            if (!isGoogleCodec && forceGoogleCodec) {
+                continue;
+            }
+
+            for (String type : codecInfo.getSupportedTypes()) {
+                if (!type.equalsIgnoreCase(mime)) {
+                    continue;
+                }
+                CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(type);
+                if (!capabilities.isFormatSupported(format)) {
+                    continue;
+                }
+
+                // Get candidate codec properties.
+                Log.v(TAG, "Found candidate codec " + codecInfo.getName());
+                for (int colorFormat: capabilities.colorFormats) {
+                    Log.v(TAG, "   Color: 0x" + Integer.toHexString(colorFormat));
+                }
+
+                // Check supported color formats.
+                for (int supportedColorFormat : mSupportedColorList) {
+                    for (int codecColorFormat : capabilities.colorFormats) {
+                        if (codecColorFormat == supportedColorFormat) {
+                            codecProperties = new CodecProperties(codecInfo.getName(),
+                                    codecColorFormat);
+                            Log.v(TAG, "Found target codec " + codecProperties.codecName +
+                                    ". Color: 0x" + Integer.toHexString(codecColorFormat));
+                            // return first HW codec found
+                            if (!isGoogleCodec) {
+                                return codecProperties;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (codecProperties == null) {
+            Log.i(TAG, "no suitable " + (forceGoogleCodec ? "google " : "")
+                    + (isEncoder ? "encoder " : "decoder ") + "found for " + format);
+        }
+        return codecProperties;
+    }
+
+    /**
+     * Parameters for encoded video stream.
+     */
+    protected class EncoderOutputStreamParameters {
+        // Name of raw YUV420 input file. When the value of this parameter
+        // is set to null input file descriptor from inputResourceId parameter
+        // is used instead.
+        public String inputYuvFilename;
+        // Name of scaled YUV420 input file.
+        public String scaledYuvFilename;
+        // File descriptor for the raw input file (YUV420). Used only if
+        // inputYuvFilename parameter is null.
+        int inputResourceId;
+        // Name of the IVF file to write encoded bitsream
+        public String outputIvfFilename;
+        // Mime Type of the Encoded content.
+        public String codecMimeType;
+        // Force to use Google VPx encoder.
+        boolean forceGoogleEncoder;
+        // Number of frames to encode.
+        int frameCount;
+        // Frame rate of input file in frames per second.
+        int frameRate;
+        // Encoded frame width.
+        public int frameWidth;
+        // Encoded frame height.
+        public int frameHeight;
+        // Encoding bitrate array in bits/second for every frame. If array length
+        // is shorter than the total number of frames, the last value is re-used for
+        // all remaining frames. For constant bitrate encoding single element
+        // array can be used with first element set to target bitrate value.
+        public int[] bitrateSet;
+        // Encoding bitrate type - VBR or CBR
+        public int bitrateType;
+        // Number of temporal layers
+        public int temporalLayers;
+        // Desired key frame interval - codec is asked to generate key frames
+        // at a period defined by this parameter.
+        public int syncFrameInterval;
+        // Optional parameter - forced key frame interval. Used to
+        // explicitly request the codec to generate key frames using
+        // MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME parameter.
+        public int syncForceFrameInterval;
+        // Buffer timeout
+        long timeoutDequeue;
+        // Flag if encoder should run in Looper thread.
+        boolean runInLooperThread;
+    }
+
+    /**
+     * Generates an array of default parameters for encoder output stream based on
+     * upscaling value.
+     */
+    protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
+            String inputYuvName,
+            String outputIvfBaseName,
+            String codecMimeType,
+            int encodeSeconds,
+            int[] resolutionScales,
+            int frameWidth,
+            int frameHeight,
+            int frameRate,
+            int bitrateMode,
+            int[] bitrates,
+            boolean syncEncoding) {
+        assertTrue(resolutionScales.length == bitrates.length);
+        int numCodecs = resolutionScales.length;
+        ArrayList<EncoderOutputStreamParameters> outputParameters =
+                new ArrayList<EncoderOutputStreamParameters>(numCodecs);
+        for (int i = 0; i < numCodecs; i++) {
+            EncoderOutputStreamParameters params = new EncoderOutputStreamParameters();
+            if (inputYuvName != null) {
+                params.inputYuvFilename = SDCARD_DIR + File.separator + inputYuvName;
+            } else {
+                params.inputYuvFilename = null;
+            }
+            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] + "_" + codecSuffix + ".ivf";
+            params.forceGoogleEncoder = false;
+            params.frameCount = encodeSeconds * frameRate;
+            params.frameRate = frameRate;
+            params.frameWidth = Math.min(frameWidth * resolutionScales[i], 1280);
+            params.frameHeight = Math.min(frameHeight * resolutionScales[i], 720);
+            params.bitrateSet = new int[1];
+            params.bitrateSet[0] = bitrates[i];
+            params.bitrateType = bitrateMode;
+            params.temporalLayers = 0;
+            params.syncFrameInterval = SYNC_FRAME_INTERVAL;
+            params.syncForceFrameInterval = 0;
+            if (syncEncoding) {
+                params.timeoutDequeue = DEFAULT_DEQUEUE_TIMEOUT_US;
+                params.runInLooperThread = false;
+            } else {
+                params.timeoutDequeue = 0;
+                params.runInLooperThread = true;
+            }
+            outputParameters.add(params);
+        }
+        return outputParameters;
+    }
+
+    protected EncoderOutputStreamParameters getDefaultEncodingParameters(
+            String inputYuvName,
+            String outputIvfBaseName,
+            String codecMimeType,
+            int encodeSeconds,
+            int frameWidth,
+            int frameHeight,
+            int frameRate,
+            int bitrateMode,
+            int bitrate,
+            boolean syncEncoding) {
+        int[] scaleValues = { 1 };
+        int[] bitrates = { bitrate };
+        return getDefaultEncodingParameterList(
+                inputYuvName,
+                outputIvfBaseName,
+                codecMimeType,
+                encodeSeconds,
+                scaleValues,
+                frameWidth,
+                frameHeight,
+                frameRate,
+                bitrateMode,
+                bitrates,
+                syncEncoding).get(0);
+    }
+
+    /**
+     * Converts (interleaves) YUV420 planar to NV12.
+     * Assumes packed, macroblock-aligned frame with no cropping
+     * (visible/coded row length == stride).
+     */
+    private static byte[] YUV420ToNV(int width, int height, byte[] yuv) {
+        byte[] nv = new byte[yuv.length];
+        // Y plane we just copy.
+        System.arraycopy(yuv, 0, nv, 0, width * height);
+
+        // U & V plane we interleave.
+        int u_offset = width * height;
+        int v_offset = u_offset + u_offset / 4;
+        int nv_offset = width * height;
+        for (int i = 0; i < width * height / 4; i++) {
+            nv[nv_offset++] = yuv[u_offset++];
+            nv[nv_offset++] = yuv[v_offset++];
+        }
+        return nv;
+    }
+
+    /**
+     * Converts (de-interleaves) NV12 to YUV420 planar.
+     * Stride may be greater than width, slice height may be greater than height.
+     */
+    private static byte[] NV12ToYUV420(int width, int height,
+            int stride, int sliceHeight, byte[] nv12) {
+        byte[] yuv = new byte[width * height * 3 / 2];
+
+        // Y plane we just copy.
+        for (int i = 0; i < height; i++) {
+            System.arraycopy(nv12, i * stride, yuv, i * width, width);
+        }
+
+        // U & V plane - de-interleave.
+        int u_offset = width * height;
+        int v_offset = u_offset + u_offset / 4;
+        int nv_offset;
+        for (int i = 0; i < height / 2; i++) {
+            nv_offset = stride * (sliceHeight + i);
+            for (int j = 0; j < width / 2; j++) {
+                yuv[u_offset++] = nv12[nv_offset++];
+                yuv[v_offset++] = nv12[nv_offset++];
+            }
+        }
+        return yuv;
+    }
+
+    /**
+     * Packs YUV420 frame by moving it to a smaller size buffer with stride and slice
+     * height equal to the original frame width and height.
+     */
+    private static byte[] PackYUV420(int width, int height,
+            int stride, int sliceHeight, byte[] src) {
+        byte[] dst = new byte[width * height * 3 / 2];
+        // Y copy.
+        for (int i = 0; i < height; i++) {
+            System.arraycopy(src, i * stride, dst, i * width, width);
+        }
+        // U and V copy.
+        int u_src_offset = stride * sliceHeight;
+        int v_src_offset = u_src_offset + u_src_offset / 4;
+        int u_dst_offset = width * height;
+        int v_dst_offset = u_dst_offset + u_dst_offset / 4;
+        for (int i = 0; i < height / 2; i++) {
+            System.arraycopy(src, u_src_offset + i * (stride / 2),
+                    dst, u_dst_offset + i * (width / 2), width / 2);
+            System.arraycopy(src, v_src_offset + i * (stride / 2),
+                    dst, v_dst_offset + i * (width / 2), width / 2);
+        }
+        return dst;
+    }
+
+
+    private static void imageUpscale1To2(byte[] src, int srcByteOffset, int srcStride,
+            byte[] dst, int dstByteOffset, int dstWidth, int dstHeight) {
+        for (int i = 0; i < dstHeight/2 - 1; i++) {
+            int dstOffset0 = 2 * i * dstWidth + dstByteOffset;
+            int dstOffset1 = dstOffset0 + dstWidth;
+            int srcOffset0 = i * srcStride + srcByteOffset;
+            int srcOffset1 = srcOffset0 + srcStride;
+            int pixel00 = (int)src[srcOffset0++] & 0xff;
+            int pixel10 = (int)src[srcOffset1++] & 0xff;
+            for (int j = 0; j < dstWidth/2 - 1; j++) {
+                int pixel01 = (int)src[srcOffset0++] & 0xff;
+                int pixel11 = (int)src[srcOffset1++] & 0xff;
+                dst[dstOffset0++] = (byte)pixel00;
+                dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
+                dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+                dst[dstOffset1++] = (byte)((pixel00 + pixel01 + pixel10 + pixel11 + 2) / 4);
+                pixel00 = pixel01;
+                pixel10 = pixel11;
+            }
+            // last column
+            dst[dstOffset0++] = (byte)pixel00;
+            dst[dstOffset0++] = (byte)pixel00;
+            dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+            dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+        }
+
+        // last row
+        int dstOffset0 = (dstHeight - 2) * dstWidth + dstByteOffset;
+        int dstOffset1 = dstOffset0 + dstWidth;
+        int srcOffset0 = (dstHeight/2 - 1) * srcStride + srcByteOffset;
+        int pixel00 = (int)src[srcOffset0++] & 0xff;
+        for (int j = 0; j < dstWidth/2 - 1; j++) {
+            int pixel01 = (int)src[srcOffset0++] & 0xff;
+            dst[dstOffset0++] = (byte)pixel00;
+            dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
+            dst[dstOffset1++] = (byte)pixel00;
+            dst[dstOffset1++] = (byte)((pixel00 + pixel01 + 1) / 2);
+            pixel00 = pixel01;
+        }
+        // the very last pixel - bottom right
+        dst[dstOffset0++] = (byte)pixel00;
+        dst[dstOffset0++] = (byte)pixel00;
+        dst[dstOffset1++] = (byte)pixel00;
+        dst[dstOffset1++] = (byte)pixel00;
+    }
+
+    /**
+    * Up-scale image.
+    * Scale factor is defined by source and destination width ratio.
+    * Only 1:2 and 1:4 up-scaling is supported for now.
+    * For 640x480 -> 1280x720 conversion only top 640x360 part of the original
+    * image is scaled.
+    */
+    private static byte[] imageScale(byte[] src, int srcWidth, int srcHeight,
+            int dstWidth, int dstHeight) throws Exception {
+        int srcYSize = srcWidth * srcHeight;
+        int dstYSize = dstWidth * dstHeight;
+        byte[] dst = null;
+        if (dstWidth == 2 * srcWidth && dstHeight <= 2 * srcHeight) {
+            // 1:2 upscale
+            dst = new byte[dstWidth * dstHeight * 3 / 2];
+            imageUpscale1To2(src, 0, srcWidth,
+                    dst, 0, dstWidth, dstHeight);                                 // Y
+            imageUpscale1To2(src, srcYSize, srcWidth / 2,
+                    dst, dstYSize, dstWidth / 2, dstHeight / 2);                  // U
+            imageUpscale1To2(src, srcYSize * 5 / 4, srcWidth / 2,
+                    dst, dstYSize * 5 / 4, dstWidth / 2, dstHeight / 2);          // V
+        } else if (dstWidth == 4 * srcWidth && dstHeight <= 4 * srcHeight) {
+            // 1:4 upscale - in two steps
+            int midWidth = 2 * srcWidth;
+            int midHeight = 2 * srcHeight;
+            byte[] midBuffer = imageScale(src, srcWidth, srcHeight, midWidth, midHeight);
+            dst = imageScale(midBuffer, midWidth, midHeight, dstWidth, dstHeight);
+
+        } else {
+            throw new RuntimeException("Can not find proper scaling function");
+        }
+
+        return dst;
+    }
+
+    private void cacheScaledImage(
+            String srcYuvFilename, int srcResourceId, int srcFrameWidth, int srcFrameHeight,
+            String dstYuvFilename, int dstFrameWidth, int dstFrameHeight) throws Exception {
+        InputStream srcStream = OpenFileOrResourceId(srcYuvFilename, srcResourceId);
+        FileOutputStream dstFile = new FileOutputStream(dstYuvFilename, false);
+        int srcFrameSize = srcFrameWidth * srcFrameHeight * 3 / 2;
+        byte[] srcFrame = new byte[srcFrameSize];
+        byte[] dstFrame = null;
+        Log.d(TAG, "Scale to " + dstFrameWidth + " x " + dstFrameHeight + ". -> " + dstYuvFilename);
+        while (true) {
+            int bytesRead = srcStream.read(srcFrame);
+            if (bytesRead != srcFrame.length) {
+                break;
+            }
+            if (dstFrameWidth == srcFrameWidth && dstFrameHeight == srcFrameHeight) {
+                dstFrame = srcFrame;
+            } else {
+                dstFrame = imageScale(srcFrame, srcFrameWidth, srcFrameHeight,
+                        dstFrameWidth, dstFrameHeight);
+            }
+            dstFile.write(dstFrame);
+        }
+        srcStream.close();
+        dstFile.close();
+    }
+
+
+    /**
+     * A basic check if an encoded stream is decodable.
+     *
+     * The most basic confirmation we can get about a frame
+     * being properly encoded is trying to decode it.
+     * (Especially in realtime mode encode output is non-
+     * deterministic, therefore a more thorough check like
+     * md5 sum comparison wouldn't work.)
+     *
+     * Indeed, MediaCodec will raise an IllegalStateException
+     * 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 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>();
+
+        // Open input/output.
+        IvfReader ivf = new IvfReader(inputIvfFilename);
+        int frameWidth = ivf.getWidth();
+        int frameHeight = ivf.getHeight();
+        int frameCount = ivf.getFrameCount();
+        int frameStride = frameWidth;
+        int frameSliceHeight = frameHeight;
+        assertTrue(frameWidth > 0);
+        assertTrue(frameHeight > 0);
+        assertTrue(frameCount > 0);
+
+        // Create decoder.
+        MediaFormat format = MediaFormat.createVideoFormat(
+                codecMimeType, ivf.getWidth(), ivf.getHeight());
+        CodecProperties properties = getVpxCodecProperties(
+                false /* encoder */, format, forceGoogleDecoder);
+        if (properties == null) {
+            ivf.close();
+            return null;
+        }
+        int frameColorFormat = properties.colorFormat;
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+
+        FileOutputStream yuv = null;
+        if (outputYuvFilename != null) {
+            yuv = new FileOutputStream(outputYuvFilename, false);
+        }
+
+        Log.d(TAG, "Creating decoder " + properties.codecName +
+                ". Color format: 0x" + Integer.toHexString(frameColorFormat) +
+                ". " + frameWidth + " x " + frameHeight);
+        Log.d(TAG, "  Format: " + format);
+        Log.d(TAG, "  In: " + inputIvfFilename + ". Out:" + outputYuvFilename);
+        MediaCodec decoder = MediaCodec.createByCodecName(properties.codecName);
+        decoder.configure(format,
+                          null,  // surface
+                          null,  // crypto
+                          0);    // flags
+        decoder.start();
+
+        ByteBuffer[] inputBuffers = decoder.getInputBuffers();
+        ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
+        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+
+        // decode loop
+        int inputFrameIndex = 0;
+        int outputFrameIndex = 0;
+        long inPresentationTimeUs = 0;
+        long outPresentationTimeUs = 0;
+        boolean sawOutputEOS = false;
+        boolean sawInputEOS = false;
+
+        while (!sawOutputEOS) {
+            if (!sawInputEOS) {
+                int inputBufIndex = decoder.dequeueInputBuffer(DEFAULT_DEQUEUE_TIMEOUT_US);
+                if (inputBufIndex >= 0) {
+                    byte[] frame = ivf.readFrame(inputFrameIndex);
+
+                    if (inputFrameIndex == frameCount - 1) {
+                        Log.d(TAG, "  Input EOS for frame # " + inputFrameIndex);
+                        sawInputEOS = true;
+                    }
+
+                    inputBuffers[inputBufIndex].clear();
+                    inputBuffers[inputBufIndex].put(frame);
+                    inputBuffers[inputBufIndex].rewind();
+                    inPresentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
+
+                    decoder.queueInputBuffer(
+                            inputBufIndex,
+                            0,  // offset
+                            frame.length,
+                            inPresentationTimeUs,
+                            sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+                    inputFrameIndex++;
+                }
+            }
+
+            int result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
+            while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
+                    result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                    outputBuffers = decoder.getOutputBuffers();
+                } else  if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                    // Process format change
+                    format = decoder.getOutputFormat();
+                    frameWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+                    frameHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+                    frameColorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+                    Log.d(TAG, "Decoder output format change. Color: 0x" +
+                            Integer.toHexString(frameColorFormat));
+                    Log.d(TAG, "Format: " + format.toString());
+
+                    // Parse frame and slice height from undocumented values
+                    if (format.containsKey("stride")) {
+                        frameStride = format.getInteger("stride");
+                    } else {
+                        frameStride = frameWidth;
+                    }
+                    if (format.containsKey("slice-height")) {
+                        frameSliceHeight = format.getInteger("slice-height");
+                    } else {
+                        frameSliceHeight = frameHeight;
+                    }
+                    Log.d(TAG, "Frame stride and slice height: " + frameStride +
+                            " x " + frameSliceHeight);
+                    frameStride = Math.max(frameWidth, frameStride);
+                    frameSliceHeight = Math.max(frameHeight, frameSliceHeight);
+                }
+                result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
+            }
+            if (result >= 0) {
+                int outputBufIndex = result;
+                outPresentationTimeUs = bufferInfo.presentationTimeUs;
+                Log.v(TAG, "Writing buffer # " + outputFrameIndex +
+                        ". Size: " + bufferInfo.size +
+                        ". InTime: " + (inPresentationTimeUs + 500)/1000 +
+                        ". OutTime: " + (outPresentationTimeUs + 500)/1000);
+                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    sawOutputEOS = true;
+                    Log.d(TAG, "   Output EOS for frame # " + outputFrameIndex);
+                }
+
+                if (bufferInfo.size > 0) {
+                    // Save decoder output to yuv file.
+                    if (yuv != null) {
+                        byte[] frame = new byte[bufferInfo.size];
+                        outputBuffers[outputBufIndex].position(bufferInfo.offset);
+                        outputBuffers[outputBufIndex].get(frame, 0, bufferInfo.size);
+                        // Convert NV12 to YUV420 if necessary.
+                        if (frameColorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+                            frame = NV12ToYUV420(frameWidth, frameHeight,
+                                    frameStride, frameSliceHeight, frame);
+                        }
+                        int writeLength = Math.min(frameWidth * frameHeight * 3 / 2, frame.length);
+                        // Pack frame if necessary.
+                        if (writeLength < frame.length &&
+                                (frameStride > frameWidth || frameSliceHeight > frameHeight)) {
+                            frame = PackYUV420(frameWidth, frameHeight,
+                                    frameStride, frameSliceHeight, frame);
+                        }
+                        yuv.write(frame, 0, writeLength);
+                    }
+                    outputFrameIndex++;
+
+                    // Update statistics - store presentation time delay in offset
+                    long presentationTimeUsDelta = inPresentationTimeUs - outPresentationTimeUs;
+                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+                    bufferInfoCopy.set((int)presentationTimeUsDelta, bufferInfo.size,
+                            outPresentationTimeUs, bufferInfo.flags);
+                    bufferInfos.add(bufferInfoCopy);
+                }
+                decoder.releaseOutputBuffer(outputBufIndex, false);
+            }
+        }
+        decoder.stop();
+        decoder.release();
+        ivf.close();
+        if (yuv != null) {
+            yuv.close();
+        }
+
+        return bufferInfos;
+    }
+
+
+    /**
+     * Helper function to return InputStream from either filename (if set)
+     * or resource id (if filename is not set).
+     */
+    private InputStream OpenFileOrResourceId(String filename, int resourceId) throws Exception {
+        if (filename != null) {
+            return new FileInputStream(filename);
+        }
+        return mResources.openRawResource(resourceId);
+    }
+
+    /**
+     * Results of frame encoding.
+     */
+    protected class MediaEncoderOutput {
+        public long inPresentationTimeUs;
+        public long outPresentationTimeUs;
+        public boolean outputGenerated;
+        public int flags;
+        public byte[] buffer;
+    }
+
+    protected class MediaEncoderAsyncHelper {
+        private final EncoderOutputStreamParameters mStreamParams;
+        private final CodecProperties mProperties;
+        private final ArrayList<MediaCodec.BufferInfo> mBufferInfos;
+        private final IvfWriter mIvf;
+        private final byte[] mSrcFrame;
+
+        private InputStream mYuvStream;
+        private int mInputFrameIndex;
+
+        MediaEncoderAsyncHelper(
+                EncoderOutputStreamParameters streamParams,
+                CodecProperties properties,
+                ArrayList<MediaCodec.BufferInfo> bufferInfos,
+                IvfWriter ivf)
+                throws Exception {
+            mStreamParams = streamParams;
+            mProperties = properties;
+            mBufferInfos = bufferInfos;
+            mIvf = ivf;
+
+            int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
+            mSrcFrame = new byte[srcFrameSize];
+
+            mYuvStream = OpenFileOrResourceId(
+                    streamParams.inputYuvFilename, streamParams.inputResourceId);
+        }
+
+        public byte[] getInputFrame() {
+            // Check EOS
+            if (mStreamParams.frameCount == 0
+                    || (mStreamParams.frameCount > 0
+                            && mInputFrameIndex >= mStreamParams.frameCount)) {
+                Log.d(TAG, "---Sending EOS empty frame for frame # " + mInputFrameIndex);
+                return null;
+            }
+
+            try {
+                int bytesRead = mYuvStream.read(mSrcFrame);
+
+                if (bytesRead == -1) {
+                    // rewind to beginning of file
+                    mYuvStream.close();
+                    mYuvStream = OpenFileOrResourceId(
+                            mStreamParams.inputYuvFilename, mStreamParams.inputResourceId);
+                    bytesRead = mYuvStream.read(mSrcFrame);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to read YUV file.");
+                return null;
+            }
+            mInputFrameIndex++;
+
+            // Convert YUV420 to NV12 if necessary
+            if (mProperties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+                return YUV420ToNV(mStreamParams.frameWidth, mStreamParams.frameHeight,
+                        mSrcFrame);
+            } else {
+                return mSrcFrame;
+            }
+        }
+
+        public boolean saveOutputFrame(MediaEncoderOutput out) {
+            if (out.outputGenerated) {
+                if (out.buffer.length > 0) {
+                    // Save frame
+                    try {
+                        mIvf.writeFrame(out.buffer, out.outPresentationTimeUs);
+                    } catch (Exception e) {
+                        Log.d(TAG, "Failed to write frame");
+                        return true;
+                    }
+
+                    // Update statistics - store presentation time delay in offset
+                    long presentationTimeUsDelta = out.inPresentationTimeUs -
+                            out.outPresentationTimeUs;
+                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+                    bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+                            out.outPresentationTimeUs, out.flags);
+                    mBufferInfos.add(bufferInfoCopy);
+                }
+                // Detect output EOS
+                if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    Log.d(TAG, "----Output EOS ");
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Video encoder wrapper class.
+     * Allows to run the encoder either in a callee's thread or in a looper thread
+     * using buffer dequeue ready notification callbacks.
+     *
+     * Function feedInput() is used to send raw video frame to the encoder input. When encoder
+     * is configured to run in async mode the function will run in a looper thread.
+     * Encoded frame can be retrieved by calling getOutput() function.
+     */
+    protected class MediaEncoderAsync extends Thread {
+        private int mId;
+        private MediaCodec mCodec;
+        private MediaFormat mFormat;
+        private ByteBuffer[] mInputBuffers;
+        private ByteBuffer[] mOutputBuffers;
+        private int mInputFrameIndex;
+        private int mOutputFrameIndex;
+        private int mInputBufIndex;
+        private int mFrameRate;
+        private long mTimeout;
+        private MediaCodec.BufferInfo mBufferInfo;
+        private long mInPresentationTimeUs;
+        private long mOutPresentationTimeUs;
+        private boolean mAsync;
+        // Flag indicating if input frame was consumed by the encoder in feedInput() call.
+        private boolean mConsumedInput;
+        // Result of frame encoding returned by getOutput() call.
+        private MediaEncoderOutput mOutput;
+        // Object used to signal that looper thread has started and Handler instance associated
+        // with looper thread has been allocated.
+        private final Object mThreadEvent = new Object();
+        // Object used to signal that MediaCodec buffer dequeue notification callback
+        // was received.
+        private final Object mCallbackEvent = new Object();
+        private Handler mHandler;
+        private boolean mCallbackReceived;
+        private MediaEncoderAsyncHelper mHelper;
+        private final Object mCompletionEvent = new Object();
+        private boolean mCompleted;
+
+        private MediaCodec.Callback mCallback = new MediaCodec.Callback() {
+            @Override
+            public void onInputBufferAvailable(MediaCodec codec, int index) {
+                if (mHelper == null) {
+                    Log.e(TAG, "async helper not available");
+                    return;
+                }
+
+                byte[] encFrame = mHelper.getInputFrame();
+                boolean inputEOS = (encFrame == null);
+
+                int encFrameLength = 0;
+                int flags = 0;
+                if (inputEOS) {
+                    flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                } else {
+                    encFrameLength = encFrame.length;
+
+                    ByteBuffer byteBuffer = mCodec.getInputBuffer(index);
+                    byteBuffer.put(encFrame);
+                    byteBuffer.rewind();
+
+                    mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
+
+                    Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
+                            ". InTime: " + (mInPresentationTimeUs + 500)/1000);
+
+                    mInputFrameIndex++;
+                }
+
+                mCodec.queueInputBuffer(
+                        index,
+                        0,  // offset
+                        encFrameLength,  // size
+                        mInPresentationTimeUs,
+                        flags);
+            }
+
+            @Override
+            public void onOutputBufferAvailable(MediaCodec codec,
+                    int index, MediaCodec.BufferInfo info) {
+                if (mHelper == null) {
+                    Log.e(TAG, "async helper not available");
+                    return;
+                }
+
+                MediaEncoderOutput out = new MediaEncoderOutput();
+
+                out.buffer = new byte[info.size];
+                ByteBuffer outputBuffer = mCodec.getOutputBuffer(index);
+                outputBuffer.get(out.buffer, 0, info.size);
+                mOutPresentationTimeUs = info.presentationTimeUs;
+
+                String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
+                if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
+                    logStr += " CONFIG. ";
+                }
+                if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+                    logStr += " KEY. ";
+                }
+                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    logStr += " EOS. ";
+                }
+                logStr += " Size: " + info.size;
+                logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
+                        ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
+                Log.v(TAG, logStr);
+
+                if (mOutputFrameIndex == 0 &&
+                        ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
+                    throw new RuntimeException("First frame is not a sync frame.");
+                }
+
+                if (info.size > 0) {
+                    mOutputFrameIndex++;
+                    out.inPresentationTimeUs = mInPresentationTimeUs;
+                    out.outPresentationTimeUs = mOutPresentationTimeUs;
+                }
+                mCodec.releaseOutputBuffer(index, false);
+
+                out.flags = info.flags;
+                out.outputGenerated = true;
+
+                if (mHelper.saveOutputFrame(out)) {
+                    // output EOS
+                    signalCompletion();
+                }
+            }
+
+            @Override
+            public void onError(MediaCodec codec, CodecException e) {
+                Log.e(TAG, "onError: " + e
+                        + ", transient " + e.isTransient()
+                        + ", recoverable " + e.isRecoverable()
+                        + ", error " + e.getErrorCode());
+            }
+
+            @Override
+            public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+                Log.i(TAG, "onOutputFormatChanged: " + format.toString());
+            }
+        };
+
+        private synchronized void requestStart() throws Exception {
+            mHandler = null;
+            start();
+            // Wait for Hander allocation
+            synchronized (mThreadEvent) {
+                while (mHandler == null) {
+                    mThreadEvent.wait();
+                }
+            }
+        }
+
+        public void setAsyncHelper(MediaEncoderAsyncHelper helper) {
+            mHelper = helper;
+        }
+
+        @Override
+        public void run() {
+            Looper.prepare();
+            synchronized (mThreadEvent) {
+                mHandler = new Handler();
+                mThreadEvent.notify();
+            }
+            Looper.loop();
+        }
+
+        private void runCallable(final Callable<?> callable) throws Exception {
+            if (mAsync) {
+                final Exception[] exception = new Exception[1];
+                final CountDownLatch countDownLatch = new CountDownLatch(1);
+                mHandler.post( new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            callable.call();
+                        } catch (Exception e) {
+                            exception[0] = e;
+                        } finally {
+                            countDownLatch.countDown();
+                        }
+                    }
+                } );
+
+                // Wait for task completion
+                countDownLatch.await();
+                if (exception[0] != null) {
+                    throw exception[0];
+                }
+            } else {
+                callable.call();
+            }
+        }
+
+        private synchronized void requestStop() throws Exception {
+            mHandler.post( new Runnable() {
+                @Override
+                public void run() {
+                    // This will run on the Looper thread
+                    Log.v(TAG, "MediaEncoder looper quitting");
+                    Looper.myLooper().quitSafely();
+                }
+            } );
+            // Wait for completion
+            join();
+            mHandler = null;
+        }
+
+        private void createCodecInternal(final String name,
+                final MediaFormat format, final long timeout) throws Exception {
+            mBufferInfo = new MediaCodec.BufferInfo();
+            mFormat = format;
+            mFrameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+            mTimeout = timeout;
+            mInputFrameIndex = 0;
+            mOutputFrameIndex = 0;
+            mInPresentationTimeUs = 0;
+            mOutPresentationTimeUs = 0;
+
+            mCodec = MediaCodec.createByCodecName(name);
+            if (mAsync) {
+                mCodec.setCallback(mCallback);
+            }
+            mCodec.configure(mFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+            mCodec.start();
+
+            // get the cached input/output only in sync mode
+            if (!mAsync) {
+                mInputBuffers = mCodec.getInputBuffers();
+                mOutputBuffers = mCodec.getOutputBuffers();
+            }
+        }
+
+        public void createCodec(int id, final String name, final MediaFormat format,
+                final long timeout, boolean async)  throws Exception {
+            mId = id;
+            mAsync = async;
+            if (mAsync) {
+                requestStart(); // start looper thread
+            }
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    createCodecInternal(name, format, timeout);
+                    return null;
+                }
+            } );
+        }
+
+        private void feedInputInternal(final byte[] encFrame, final boolean inputEOS) {
+            mConsumedInput = false;
+            // Feed input
+            mInputBufIndex = mCodec.dequeueInputBuffer(mTimeout);
+
+            if (mInputBufIndex >= 0) {
+                mInputBuffers[mInputBufIndex].clear();
+                mInputBuffers[mInputBufIndex].put(encFrame);
+                mInputBuffers[mInputBufIndex].rewind();
+                int encFrameLength = encFrame.length;
+                int flags = 0;
+                if (inputEOS) {
+                    encFrameLength = 0;
+                    flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                }
+                if (!inputEOS) {
+                    Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
+                            ". InTime: " + (mInPresentationTimeUs + 500)/1000);
+                    mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
+                    mInputFrameIndex++;
+                }
+
+                mCodec.queueInputBuffer(
+                        mInputBufIndex,
+                        0,  // offset
+                        encFrameLength,  // size
+                        mInPresentationTimeUs,
+                        flags);
+
+                mConsumedInput = true;
+            } else {
+                Log.v(TAG, "In " + mId + " - TRY_AGAIN_LATER");
+            }
+            mCallbackReceived = false;
+        }
+
+        public boolean feedInput(final byte[] encFrame, final boolean inputEOS) throws Exception {
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    feedInputInternal(encFrame, inputEOS);
+                    return null;
+                }
+            } );
+            return mConsumedInput;
+        }
+
+        private void getOutputInternal() {
+            mOutput = new MediaEncoderOutput();
+            mOutput.inPresentationTimeUs = mInPresentationTimeUs;
+            mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
+            mOutput.outputGenerated = false;
+
+            // Get output from the encoder
+            int result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
+            while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
+                    result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                    mOutputBuffers = mCodec.getOutputBuffers();
+                } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                    mFormat = mCodec.getOutputFormat();
+                    Log.d(TAG, "Format changed: " + mFormat.toString());
+                }
+                result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
+            }
+            if (result == MediaCodec.INFO_TRY_AGAIN_LATER) {
+                Log.v(TAG, "Out " + mId + " - TRY_AGAIN_LATER");
+            }
+
+            if (result >= 0) {
+                int outputBufIndex = result;
+                mOutput.buffer = new byte[mBufferInfo.size];
+                mOutputBuffers[outputBufIndex].position(mBufferInfo.offset);
+                mOutputBuffers[outputBufIndex].get(mOutput.buffer, 0, mBufferInfo.size);
+                mOutPresentationTimeUs = mBufferInfo.presentationTimeUs;
+
+                String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
+                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
+                    logStr += " CONFIG. ";
+                }
+                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+                    logStr += " KEY. ";
+                }
+                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    logStr += " EOS. ";
+                }
+                logStr += " Size: " + mBufferInfo.size;
+                logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
+                        ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
+                Log.v(TAG, logStr);
+                if (mOutputFrameIndex == 0 &&
+                        ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
+                    throw new RuntimeException("First frame is not a sync frame.");
+                }
+
+                if (mBufferInfo.size > 0) {
+                    mOutputFrameIndex++;
+                    mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
+                }
+                mCodec.releaseOutputBuffer(outputBufIndex, false);
+
+                mOutput.flags = mBufferInfo.flags;
+                mOutput.outputGenerated = true;
+            }
+            mCallbackReceived = false;
+        }
+
+        public MediaEncoderOutput getOutput() throws Exception {
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    getOutputInternal();
+                    return null;
+                }
+            } );
+            return mOutput;
+        }
+
+        public void forceSyncFrame() throws Exception {
+            final Bundle syncFrame = new Bundle();
+            syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    mCodec.setParameters(syncFrame);
+                    return null;
+                }
+            } );
+        }
+
+        public void updateBitrate(int bitrate) throws Exception {
+            final Bundle bitrateUpdate = new Bundle();
+            bitrateUpdate.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bitrate);
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    mCodec.setParameters(bitrateUpdate);
+                    return null;
+                }
+            } );
+        }
+
+
+        public void waitForBufferEvent() throws Exception {
+            Log.v(TAG, "----Enc" + mId + " waiting for bufferEvent");
+            if (mAsync) {
+                synchronized (mCallbackEvent) {
+                    if (!mCallbackReceived) {
+                        mCallbackEvent.wait(1000); // wait 1 sec for a callback
+                        // throw an exception if callback was not received
+                        if (!mCallbackReceived) {
+                            throw new RuntimeException("MediaCodec callback was not received");
+                        }
+                    }
+                }
+            } else {
+                Thread.sleep(5);
+            }
+            Log.v(TAG, "----Waiting for bufferEvent done");
+        }
+
+
+        public void waitForCompletion(long timeoutMs) throws Exception {
+            synchronized (mCompletionEvent) {
+                long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
+
+                while (!mCompleted) {
+                    mCompletionEvent.wait(timeoutExpiredMs - System.currentTimeMillis());
+                    if (System.currentTimeMillis() >= timeoutExpiredMs) {
+                        throw new RuntimeException("encoding has timed out!");
+                    }
+                }
+            }
+        }
+
+        public void signalCompletion() {
+            synchronized (mCompletionEvent) {
+                mCompleted = true;
+                mCompletionEvent.notify();
+            }
+        }
+
+        public void deleteCodec() throws Exception {
+            runCallable( new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    mCodec.stop();
+                    mCodec.release();
+                    return null;
+                }
+            } );
+            if (mAsync) {
+                requestStop(); // Stop looper thread
+            }
+        }
+    }
+
+    /**
+     * 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 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
+     * include any header data.
+     *
+     * @param streamParams  Structure with encoder parameters
+     * @return              Returns array of encoded frames information for each frame.
+     */
+    protected ArrayList<MediaCodec.BufferInfo> encode(
+            EncoderOutputStreamParameters streamParams) throws Exception {
+
+        ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+        Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
+                streamParams.frameHeight);
+        int bitrate = streamParams.bitrateSet[0];
+
+        // Create minimal media format signifying desired output.
+        MediaFormat format = MediaFormat.createVideoFormat(
+                streamParams.codecMimeType, streamParams.frameWidth,
+                streamParams.frameHeight);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+        CodecProperties properties = getVpxCodecProperties(
+                true, format, streamParams.forceGoogleEncoder);
+        if (properties == null) {
+            return null;
+        }
+
+        // Open input/output
+        InputStream yuvStream = OpenFileOrResourceId(
+                streamParams.inputYuvFilename, streamParams.inputResourceId);
+        IvfWriter ivf = new IvfWriter(
+                streamParams.outputIvfFilename, streamParams.codecMimeType,
+                streamParams.frameWidth, streamParams.frameHeight);
+
+        // Create a media format signifying desired output.
+        if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
+            format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+        }
+        if (streamParams.temporalLayers > 0) {
+            format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
+        }
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
+        int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
+                streamParams.frameRate;
+        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+
+        // Create encoder
+        Log.d(TAG, "Creating encoder " + properties.codecName +
+                ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+                streamParams.frameWidth + " x " + streamParams.frameHeight +
+                ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
+                ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
+                ". Key frame:" + syncFrameInterval * streamParams.frameRate +
+                ". Force keyFrame: " + streamParams.syncForceFrameInterval);
+        Log.d(TAG, "  Format: " + format);
+        Log.d(TAG, "  Output ivf:" + streamParams.outputIvfFilename);
+        MediaEncoderAsync codec = new MediaEncoderAsync();
+        codec.createCodec(0, properties.codecName, format,
+                streamParams.timeoutDequeue, streamParams.runInLooperThread);
+
+        // encode loop
+        boolean sawInputEOS = false;  // no more data
+        boolean consumedInputEOS = false; // EOS flag is consumed dy encoder
+        boolean sawOutputEOS = false;
+        boolean inputConsumed = true;
+        int inputFrameIndex = 0;
+        int lastBitrate = bitrate;
+        int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
+        byte[] srcFrame = new byte[srcFrameSize];
+
+        while (!sawOutputEOS) {
+
+            // Read and feed input frame
+            if (!consumedInputEOS) {
+
+                // Read new input buffers - if previous input was consumed and no EOS
+                if (inputConsumed && !sawInputEOS) {
+                    int bytesRead = yuvStream.read(srcFrame);
+
+                    // Check EOS
+                    if (streamParams.frameCount > 0 && inputFrameIndex >= streamParams.frameCount) {
+                        sawInputEOS = true;
+                        Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
+                    }
+
+                    if (!sawInputEOS && bytesRead == -1) {
+                        if (streamParams.frameCount == 0) {
+                            sawInputEOS = true;
+                            Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
+                        } else {
+                            yuvStream.close();
+                            yuvStream = OpenFileOrResourceId(
+                                    streamParams.inputYuvFilename, streamParams.inputResourceId);
+                            bytesRead = yuvStream.read(srcFrame);
+                        }
+                    }
+
+                    // Force sync frame if syncForceFrameinterval is set.
+                    if (!sawInputEOS && inputFrameIndex > 0 &&
+                            streamParams.syncForceFrameInterval > 0 &&
+                            (inputFrameIndex % streamParams.syncForceFrameInterval) == 0) {
+                        Log.d(TAG, "---Requesting sync frame # " + inputFrameIndex);
+                        codec.forceSyncFrame();
+                    }
+
+                    // Dynamic bitrate change.
+                    if (!sawInputEOS && streamParams.bitrateSet.length > inputFrameIndex) {
+                        int newBitrate = streamParams.bitrateSet[inputFrameIndex];
+                        if (newBitrate != lastBitrate) {
+                            Log.d(TAG, "--- Requesting new bitrate " + newBitrate +
+                                    " for frame " + inputFrameIndex);
+                            codec.updateBitrate(newBitrate);
+                            lastBitrate = newBitrate;
+                        }
+                    }
+
+                    // Convert YUV420 to NV12 if necessary
+                    if (properties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+                        srcFrame = YUV420ToNV(streamParams.frameWidth, streamParams.frameHeight,
+                                srcFrame);
+                    }
+                }
+
+                inputConsumed = codec.feedInput(srcFrame, sawInputEOS);
+                if (inputConsumed) {
+                    inputFrameIndex++;
+                    consumedInputEOS = sawInputEOS;
+                }
+            }
+
+            // Get output from the encoder
+            MediaEncoderOutput out = codec.getOutput();
+            if (out.outputGenerated) {
+                // Detect output EOS
+                if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    Log.d(TAG, "----Output EOS ");
+                    sawOutputEOS = true;
+                }
+
+                if (out.buffer.length > 0) {
+                    // Save frame
+                    ivf.writeFrame(out.buffer, out.outPresentationTimeUs);
+
+                    // Update statistics - store presentation time delay in offset
+                    long presentationTimeUsDelta = out.inPresentationTimeUs -
+                            out.outPresentationTimeUs;
+                    MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+                    bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+                            out.outPresentationTimeUs, out.flags);
+                    bufferInfos.add(bufferInfoCopy);
+                }
+            }
+
+            // If codec is not ready to accept input/poutput - wait for buffer ready callback
+            if ((!inputConsumed || consumedInputEOS) && !out.outputGenerated) {
+                codec.waitForBufferEvent();
+            }
+        }
+
+        codec.deleteCodec();
+        ivf.close();
+        yuvStream.close();
+
+        return bufferInfos;
+    }
+
+    /**
+     * 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 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
+     * include any header data.
+     *
+     * @param streamParams  Structure with encoder parameters
+     * @return              Returns array of encoded frames information for each frame.
+     */
+    protected ArrayList<MediaCodec.BufferInfo> encodeAsync(
+            EncoderOutputStreamParameters streamParams) throws Exception {
+        if (!streamParams.runInLooperThread) {
+            throw new RuntimeException("encodeAsync should run with a looper thread!");
+        }
+
+        ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+        Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
+                streamParams.frameHeight);
+        int bitrate = streamParams.bitrateSet[0];
+
+        // Create minimal media format signifying desired output.
+        MediaFormat format = MediaFormat.createVideoFormat(
+                streamParams.codecMimeType, streamParams.frameWidth,
+                streamParams.frameHeight);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+        CodecProperties properties = getVpxCodecProperties(
+                true, format, streamParams.forceGoogleEncoder);
+        if (properties == null) {
+            return null;
+        }
+
+        // Open input/output
+        IvfWriter ivf = new IvfWriter(
+                streamParams.outputIvfFilename, streamParams.codecMimeType,
+                streamParams.frameWidth, streamParams.frameHeight);
+
+        // Create a media format signifying desired output.
+        if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
+            format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+        }
+        if (streamParams.temporalLayers > 0) {
+            format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
+        }
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
+        int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
+                streamParams.frameRate;
+        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+
+        // Create encoder
+        Log.d(TAG, "Creating encoder " + properties.codecName +
+                ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+                streamParams.frameWidth + " x " + streamParams.frameHeight +
+                ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
+                ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
+                ". Key frame:" + syncFrameInterval * streamParams.frameRate +
+                ". Force keyFrame: " + streamParams.syncForceFrameInterval);
+        Log.d(TAG, "  Format: " + format);
+        Log.d(TAG, "  Output ivf:" + streamParams.outputIvfFilename);
+
+        MediaEncoderAsync codec = new MediaEncoderAsync();
+        MediaEncoderAsyncHelper helper = new MediaEncoderAsyncHelper(
+                streamParams, properties, bufferInfos, ivf);
+
+        codec.setAsyncHelper(helper);
+        codec.createCodec(0, properties.codecName, format,
+                streamParams.timeoutDequeue, streamParams.runInLooperThread);
+        codec.waitForCompletion(DEFAULT_ENCODE_TIMEOUT_MS);
+
+        codec.deleteCodec();
+        ivf.close();
+
+        return bufferInfos;
+    }
+
+    /**
+     * 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 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
+     * include any header data.
+     *
+     * @param srcFrameWidth     Frame width of input yuv file
+     * @param srcFrameHeight    Frame height of input yuv file
+     * @param encodingParams    Encoder parameters
+     * @return                  Returns 2D array of encoded frames information for each stream and
+     *                          for each frame.
+     */
+    protected ArrayList<ArrayList<MediaCodec.BufferInfo>> encodeSimulcast(
+            int srcFrameWidth,
+            int srcFrameHeight,
+            ArrayList<EncoderOutputStreamParameters> encodingParams)  throws Exception {
+        int numEncoders = encodingParams.size();
+
+        // Create arrays of input/output, formats, bitrates etc
+        ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos =
+                new ArrayList<ArrayList<MediaCodec.BufferInfo>>(numEncoders);
+        InputStream yuvStream[] = new InputStream[numEncoders];
+        IvfWriter[] ivf = new IvfWriter[numEncoders];
+        FileOutputStream[] yuvScaled = new FileOutputStream[numEncoders];
+        MediaFormat[] format = new MediaFormat[numEncoders];
+        MediaEncoderAsync[] codec = new MediaEncoderAsync[numEncoders];
+        int[] inputFrameIndex = new int[numEncoders];
+        boolean[] sawInputEOS = new boolean[numEncoders];
+        boolean[] consumedInputEOS = new boolean[numEncoders];
+        boolean[] inputConsumed = new boolean[numEncoders];
+        boolean[] bufferConsumed = new boolean[numEncoders];
+        boolean[] sawOutputEOS = new boolean[numEncoders];
+        byte[][] srcFrame = new byte[numEncoders][];
+        boolean sawOutputEOSTotal = false;
+        boolean bufferConsumedTotal = false;
+        CodecProperties[] codecProperties = new CodecProperties[numEncoders];
+
+        numEncoders = 0;
+        for (EncoderOutputStreamParameters params : encodingParams) {
+            int i = numEncoders;
+            Log.d(TAG, "Source resolution: " + params.frameWidth + " x " +
+                    params.frameHeight);
+            int bitrate = params.bitrateSet[0];
+
+            // Create minimal media format signifying desired output.
+            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);
+            if (properties == null) {
+                continue;
+            }
+
+            // Check if scaled image was created
+            int scale = params.frameWidth / srcFrameWidth;
+            if (!mScaledImages.contains(scale)) {
+                // resize image
+                cacheScaledImage(params.inputYuvFilename, params.inputResourceId,
+                        srcFrameWidth, srcFrameHeight,
+                        params.scaledYuvFilename, params.frameWidth, params.frameHeight);
+                mScaledImages.add(scale);
+            }
+
+            // Create buffer info storage
+            bufferInfos.add(new ArrayList<MediaCodec.BufferInfo>());
+
+            // Create YUV reader
+            yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
+
+            // Create IVF writer
+            ivf[i] = new IvfWriter(
+                    params.outputIvfFilename, params.codecMimeType,
+                    params.frameWidth, params.frameHeight);
+
+            // Frame buffer
+            int frameSize = params.frameWidth * params.frameHeight * 3 / 2;
+            srcFrame[i] = new byte[frameSize];
+
+            // Create a media format signifying desired output.
+            if (params.bitrateType == VIDEO_ControlRateConstant) {
+                format[i].setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+            }
+            if (params.temporalLayers > 0) {
+                format[i].setInteger("ts-layers", params.temporalLayers); // 1 temporal layer
+            }
+            format[i].setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+            format[i].setInteger(MediaFormat.KEY_FRAME_RATE, params.frameRate);
+            int syncFrameInterval = (params.syncFrameInterval + params.frameRate/2) /
+                    params.frameRate; // in sec
+            format[i].setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+            // Create encoder
+            Log.d(TAG, "Creating encoder #" + i +" : " + properties.codecName +
+                    ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+                    params.frameWidth + " x " + params.frameHeight +
+                    ". Bitrate: " + bitrate + " Bitrate type: " + params.bitrateType +
+                    ". Fps:" + params.frameRate + ". TS Layers: " + params.temporalLayers +
+                    ". Key frame:" + syncFrameInterval * params.frameRate +
+                    ". Force keyFrame: " + params.syncForceFrameInterval);
+            Log.d(TAG, "  Format: " + format[i]);
+            Log.d(TAG, "  Output ivf:" + params.outputIvfFilename);
+
+            // Create encoder
+            codec[i] = new MediaEncoderAsync();
+            codec[i].createCodec(i, properties.codecName, format[i],
+                    params.timeoutDequeue, params.runInLooperThread);
+            codecProperties[i] = new CodecProperties(properties.codecName, properties.colorFormat);
+
+            inputConsumed[i] = true;
+            ++numEncoders;
+        }
+        if (numEncoders == 0) {
+            Log.i(TAG, "no suitable encoders found for any of the streams");
+            return null;
+        }
+
+        while (!sawOutputEOSTotal) {
+            // Feed input buffer to all encoders
+            for (int i = 0; i < numEncoders; i++) {
+                bufferConsumed[i] = false;
+                if (consumedInputEOS[i]) {
+                    continue;
+                }
+
+                EncoderOutputStreamParameters params = encodingParams.get(i);
+                // Read new input buffers - if previous input was consumed and no EOS
+                if (inputConsumed[i] && !sawInputEOS[i]) {
+                    int bytesRead = yuvStream[i].read(srcFrame[i]);
+
+                    // Check EOS
+                    if (params.frameCount > 0 && inputFrameIndex[i] >= params.frameCount) {
+                        sawInputEOS[i] = true;
+                        Log.d(TAG, "---Enc" + i +
+                                ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
+                    }
+
+                    if (!sawInputEOS[i] && bytesRead == -1) {
+                        if (params.frameCount == 0) {
+                            sawInputEOS[i] = true;
+                            Log.d(TAG, "---Enc" + i +
+                                    ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
+                        } else {
+                            yuvStream[i].close();
+                            yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
+                            bytesRead = yuvStream[i].read(srcFrame[i]);
+                        }
+                    }
+
+                    // Convert YUV420 to NV12 if necessary
+                    if (codecProperties[i].colorFormat !=
+                            CodecCapabilities.COLOR_FormatYUV420Planar) {
+                        srcFrame[i] =
+                            YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i]);
+                    }
+                }
+
+                inputConsumed[i] = codec[i].feedInput(srcFrame[i], sawInputEOS[i]);
+                if (inputConsumed[i]) {
+                    inputFrameIndex[i]++;
+                    consumedInputEOS[i] = sawInputEOS[i];
+                    bufferConsumed[i] = true;
+                }
+
+            }
+
+            // Get output from all encoders
+            for (int i = 0; i < numEncoders; i++) {
+                if (sawOutputEOS[i]) {
+                    continue;
+                }
+
+                MediaEncoderOutput out = codec[i].getOutput();
+                if (out.outputGenerated) {
+                    bufferConsumed[i] = true;
+                    // Detect output EOS
+                    if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                        Log.d(TAG, "----Enc" + i + ". Output EOS ");
+                        sawOutputEOS[i] = true;
+                    }
+
+                    if (out.buffer.length > 0) {
+                        // Save frame
+                        ivf[i].writeFrame(out.buffer, out.outPresentationTimeUs);
+
+                        // Update statistics - store presentation time delay in offset
+                        long presentationTimeUsDelta = out.inPresentationTimeUs -
+                                out.outPresentationTimeUs;
+                        MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+                        bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+                                out.outPresentationTimeUs, out.flags);
+                        bufferInfos.get(i).add(bufferInfoCopy);
+                    }
+                }
+            }
+
+            // If codec is not ready to accept input/output - wait for buffer ready callback
+            bufferConsumedTotal = false;
+            for (boolean bufferConsumedCurrent : bufferConsumed) {
+                bufferConsumedTotal |= bufferConsumedCurrent;
+            }
+            if (!bufferConsumedTotal) {
+                // Pick the encoder to wait for
+                for (int i = 0; i < numEncoders; i++) {
+                    if (!bufferConsumed[i] && !sawOutputEOS[i]) {
+                        codec[i].waitForBufferEvent();
+                        break;
+                    }
+                }
+            }
+
+            // Check if EOS happened for all encoders
+            sawOutputEOSTotal = true;
+            for (boolean sawOutputEOSStream : sawOutputEOS) {
+                sawOutputEOSTotal &= sawOutputEOSStream;
+            }
+        }
+
+        for (int i = 0; i < numEncoders; i++) {
+            codec[i].deleteCodec();
+            ivf[i].close();
+            yuvStream[i].close();
+            if (yuvScaled[i] != null) {
+                yuvScaled[i].close();
+            }
+        }
+
+        return bufferInfos;
+    }
+
+    /**
+     * Some encoding statistics.
+     */
+    protected class VpxEncodingStatistics {
+        VpxEncodingStatistics() {
+            mBitrates = new ArrayList<Integer>();
+            mFrames = new ArrayList<Integer>();
+            mKeyFrames = new ArrayList<Integer>();
+            mMinimumKeyFrameInterval = Integer.MAX_VALUE;
+        }
+
+        public ArrayList<Integer> mBitrates;// Bitrate values for each second of the encoded stream.
+        public ArrayList<Integer> mFrames; // Number of frames in each second of the encoded stream.
+        public int mAverageBitrate;         // Average stream bitrate.
+        public ArrayList<Integer> mKeyFrames;// Stores the position of key frames in a stream.
+        public int mAverageKeyFrameInterval; // Average key frame interval.
+        public int mMaximumKeyFrameInterval; // Maximum key frame interval.
+        public int mMinimumKeyFrameInterval; // Minimum key frame interval.
+    }
+
+    /**
+     * Calculates average bitrate and key frame interval for the encoded streams.
+     * Output mBitrates field will contain bitrate values for every second
+     * of the encoded stream.
+     * Average stream bitrate will be stored in mAverageBitrate field.
+     * mKeyFrames array will contain the position of key frames in the encoded stream and
+     * mKeyFrameInterval - average key frame interval.
+     */
+    protected VpxEncodingStatistics computeEncodingStatistics(int encoderId,
+            ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
+        VpxEncodingStatistics statistics = new VpxEncodingStatistics();
+
+        int totalSize = 0;
+        int frames = 0;
+        int framesPerSecond = 0;
+        int totalFrameSizePerSecond = 0;
+        int maxFrameSize = 0;
+        int currentSecond;
+        int nextSecond = 0;
+        String keyFrameList = "  IFrame List: ";
+        String bitrateList = "  Bitrate list: ";
+        String framesList = "  FPS list: ";
+
+
+        for (int j = 0; j < bufferInfos.size(); j++) {
+            MediaCodec.BufferInfo info = bufferInfos.get(j);
+            currentSecond = (int)(info.presentationTimeUs / 1000000);
+            boolean lastFrame = (j == bufferInfos.size() - 1);
+            if (!lastFrame) {
+                nextSecond = (int)(bufferInfos.get(j+1).presentationTimeUs / 1000000);
+            }
+
+            totalSize += info.size;
+            totalFrameSizePerSecond += info.size;
+            maxFrameSize = Math.max(maxFrameSize, info.size);
+            framesPerSecond++;
+            frames++;
+
+            // Update the bitrate statistics if the next frame will
+            // be for the next second
+            if (lastFrame || nextSecond > currentSecond) {
+                int currentBitrate = totalFrameSizePerSecond * 8;
+                bitrateList += (currentBitrate + " ");
+                framesList += (framesPerSecond + " ");
+                statistics.mBitrates.add(currentBitrate);
+                statistics.mFrames.add(framesPerSecond);
+                totalFrameSizePerSecond = 0;
+                framesPerSecond = 0;
+            }
+
+            // Update key frame statistics.
+            if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+                statistics.mKeyFrames.add(j);
+                keyFrameList += (j + "  ");
+            }
+        }
+        int duration = (int)(bufferInfos.get(bufferInfos.size() - 1).presentationTimeUs / 1000);
+        duration = (duration + 500) / 1000;
+        statistics.mAverageBitrate = (int)(((long)totalSize * 8) / duration);
+        Log.d(TAG, "Statistics for encoder # " + encoderId);
+        // Calculate average key frame interval in frames.
+        int keyFrames = statistics.mKeyFrames.size();
+        if (keyFrames > 1) {
+            statistics.mAverageKeyFrameInterval =
+                    statistics.mKeyFrames.get(keyFrames - 1) - statistics.mKeyFrames.get(0);
+            statistics.mAverageKeyFrameInterval =
+                    Math.round((float)statistics.mAverageKeyFrameInterval / (keyFrames - 1));
+            for (int j = 1; j < keyFrames; j++) {
+                int keyFrameInterval =
+                        statistics.mKeyFrames.get(j) - statistics.mKeyFrames.get(j - 1);
+                statistics.mMaximumKeyFrameInterval =
+                        Math.max(statistics.mMaximumKeyFrameInterval, keyFrameInterval);
+                statistics.mMinimumKeyFrameInterval =
+                        Math.min(statistics.mMinimumKeyFrameInterval, keyFrameInterval);
+            }
+            Log.d(TAG, "  Key frame intervals: Max: " + statistics.mMaximumKeyFrameInterval +
+                    ". Min: " + statistics.mMinimumKeyFrameInterval +
+                    ". Avg: " + statistics.mAverageKeyFrameInterval);
+        }
+        Log.d(TAG, "  Frames: " + frames + ". Duration: " + duration +
+                ". Total size: " + totalSize + ". Key frames: " + keyFrames);
+        Log.d(TAG, keyFrameList);
+        Log.d(TAG, bitrateList);
+        Log.d(TAG, framesList);
+        Log.d(TAG, "  Bitrate average: " + statistics.mAverageBitrate);
+        Log.d(TAG, "  Maximum frame size: " + maxFrameSize);
+
+        return statistics;
+    }
+
+    protected VpxEncodingStatistics computeEncodingStatistics(
+            ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
+        return computeEncodingStatistics(0, bufferInfos);
+    }
+
+    protected ArrayList<VpxEncodingStatistics> computeSimulcastEncodingStatistics(
+            ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos) {
+        int numCodecs = bufferInfos.size();
+        ArrayList<VpxEncodingStatistics> statistics = new ArrayList<VpxEncodingStatistics>();
+
+        for (int i = 0; i < numCodecs; i++) {
+            VpxEncodingStatistics currentStatistics =
+                    computeEncodingStatistics(i, bufferInfos.get(i));
+            statistics.add(currentStatistics);
+        }
+        return statistics;
+    }
+
+    /**
+     * Calculates maximum latency for encoder/decoder based on buffer info array
+     * generated either by encoder or decoder.
+     */
+    protected int maxPresentationTimeDifference(ArrayList<MediaCodec.BufferInfo> bufferInfos) {
+        int maxValue = 0;
+        for (MediaCodec.BufferInfo bufferInfo : bufferInfos) {
+            maxValue = Math.max(maxValue,  bufferInfo.offset);
+        }
+        maxValue = (maxValue + 500) / 1000; // mcs -> ms
+        return maxValue;
+    }
+
+    /**
+     * Decoding PSNR statistics.
+     */
+    protected class VpxDecodingStatistics {
+        VpxDecodingStatistics() {
+            mMinimumPSNR = Integer.MAX_VALUE;
+        }
+        public double mAveragePSNR;
+        public double mMinimumPSNR;
+    }
+
+    /**
+     * Calculates PSNR value between two video frames.
+     */
+    private double computePSNR(byte[] data0, byte[] data1) {
+        long squareError = 0;
+        assertTrue(data0.length == data1.length);
+        int length = data0.length;
+        for (int i = 0 ; i < length; i++) {
+            int diff = ((int)data0[i] & 0xff) - ((int)data1[i] & 0xff);
+            squareError += diff * diff;
+        }
+        double meanSquareError = (double)squareError / length;
+        double psnr = 10 * Math.log10((double)255 * 255 / meanSquareError);
+        return psnr;
+    }
+
+    /**
+     * Calculates average and minimum PSNR values between
+     * set of reference and decoded video frames.
+     * Runs PSNR calculation for the full duration of the decoded data.
+     */
+    protected VpxDecodingStatistics computeDecodingStatistics(
+            String referenceYuvFilename,
+            int referenceYuvRawId,
+            String decodedYuvFilename,
+            int width,
+            int height) throws Exception {
+        VpxDecodingStatistics statistics = new VpxDecodingStatistics();
+        InputStream referenceStream =
+                OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
+        InputStream decodedStream = new FileInputStream(decodedYuvFilename);
+
+        int ySize = width * height;
+        int uvSize = width * height / 4;
+        byte[] yRef = new byte[ySize];
+        byte[] yDec = new byte[ySize];
+        byte[] uvRef = new byte[uvSize];
+        byte[] uvDec = new byte[uvSize];
+
+        int frames = 0;
+        double averageYPSNR = 0;
+        double averageUPSNR = 0;
+        double averageVPSNR = 0;
+        double minimumYPSNR = Integer.MAX_VALUE;
+        double minimumUPSNR = Integer.MAX_VALUE;
+        double minimumVPSNR = Integer.MAX_VALUE;
+        int minimumPSNRFrameIndex = 0;
+
+        while (true) {
+            // Calculate Y PSNR.
+            int bytesReadRef = referenceStream.read(yRef);
+            int bytesReadDec = decodedStream.read(yDec);
+            if (bytesReadDec == -1) {
+                break;
+            }
+            if (bytesReadRef == -1) {
+                // Reference file wrapping up
+                referenceStream.close();
+                referenceStream =
+                        OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
+                bytesReadRef = referenceStream.read(yRef);
+            }
+            double curYPSNR = computePSNR(yRef, yDec);
+            averageYPSNR += curYPSNR;
+            minimumYPSNR = Math.min(minimumYPSNR, curYPSNR);
+            double curMinimumPSNR = curYPSNR;
+
+            // Calculate U PSNR.
+            bytesReadRef = referenceStream.read(uvRef);
+            bytesReadDec = decodedStream.read(uvDec);
+            double curUPSNR = computePSNR(uvRef, uvDec);
+            averageUPSNR += curUPSNR;
+            minimumUPSNR = Math.min(minimumUPSNR, curUPSNR);
+            curMinimumPSNR = Math.min(curMinimumPSNR, curUPSNR);
+
+            // Calculate V PSNR.
+            bytesReadRef = referenceStream.read(uvRef);
+            bytesReadDec = decodedStream.read(uvDec);
+            double curVPSNR = computePSNR(uvRef, uvDec);
+            averageVPSNR += curVPSNR;
+            minimumVPSNR = Math.min(minimumVPSNR, curVPSNR);
+            curMinimumPSNR = Math.min(curMinimumPSNR, curVPSNR);
+
+            // Frame index for minimum PSNR value - help to detect possible distortions
+            if (curMinimumPSNR < statistics.mMinimumPSNR) {
+                statistics.mMinimumPSNR = curMinimumPSNR;
+                minimumPSNRFrameIndex = frames;
+            }
+
+            String logStr = String.format(Locale.US, "PSNR #%d: Y: %.2f. U: %.2f. V: %.2f",
+                    frames, curYPSNR, curUPSNR, curVPSNR);
+            Log.v(TAG, logStr);
+
+            frames++;
+        }
+
+        averageYPSNR /= frames;
+        averageUPSNR /= frames;
+        averageVPSNR /= frames;
+        statistics.mAveragePSNR = (4 * averageYPSNR + averageUPSNR + averageVPSNR) / 6;
+
+        Log.d(TAG, "PSNR statistics for " + frames + " frames.");
+        String logStr = String.format(Locale.US,
+                "Average PSNR: Y: %.1f. U: %.1f. V: %.1f. Average: %.1f",
+                averageYPSNR, averageUPSNR, averageVPSNR, statistics.mAveragePSNR);
+        Log.d(TAG, logStr);
+        logStr = String.format(Locale.US,
+                "Minimum PSNR: Y: %.1f. U: %.1f. V: %.1f. Overall: %.1f at frame %d",
+                minimumYPSNR, minimumUPSNR, minimumVPSNR,
+                statistics.mMinimumPSNR, minimumPSNRFrameIndex);
+        Log.d(TAG, logStr);
+
+        referenceStream.close();
+        decodedStream.close();
+        return statistics;
+    }
+}
+
diff --git a/tests/tests/media/src/android/media/cts/VpxEncoderTest.java b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
new file mode 100644
index 0000000..0e9c940
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.media.cts.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * 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/vp9 decoder to verify frames are decodable and to
+ * calculate PSNR values for various bitrates.
+ */
+public class VpxEncoderTest extends VpxCodecTestBase {
+
+    private static final String ENCODED_IVF_BASE = "football";
+    private static final String INPUT_YUV = null;
+    private static final String OUTPUT_YUV = SDCARD_DIR + File.separator +
+            ENCODED_IVF_BASE + "_out.yuv";
+
+    // YUV stream properties.
+    private static final int WIDTH = 320;
+    private static final int HEIGHT = 240;
+    private static final int FPS = 30;
+    // Default encoding bitrate.
+    private static final int BITRATE = 400000;
+    // Default encoding bitrate mode
+    private static final int BITRATE_MODE = VIDEO_ControlRateVariable;
+    // List of bitrates used in quality and basic bitrate tests.
+    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 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 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;
+    // Maximum allowed minimum PSNR difference of encoder comparing to reference Google encoder.
+    private static final double MAX_MINIMUM_PSNR_DIFFERENCE = 4;
+    // Maximum allowed average PSNR difference of the encoder running in a looper thread with 0 ms
+    // buffer dequeue timeout comparing to the encoder running in a callee's thread with 100 ms
+    // buffer dequeue timeout.
+    private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 0.5;
+    // Maximum allowed minimum PSNR difference of the encoder running in a looper thread
+    // comparing to the encoder running in a callee's thread.
+    private static final double MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE = 2;
+    // Maximum allowed average key frame interval variation from the target value.
+    private static final int MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION = 1;
+    // Maximum allowed key frame interval variation from the target value.
+    private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
+
+    /**
+     * 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.
+     */
+    private void internalTestBasic(String codecMimeType) throws Exception {
+        int encodeSeconds = 9;
+        boolean skipped = true;
+
+        for (int targetBitrate : TEST_BITRATES_SET) {
+            EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                    INPUT_YUV,
+                    ENCODED_IVF_BASE,
+                    codecMimeType,
+                    encodeSeconds,
+                    WIDTH,
+                    HEIGHT,
+                    FPS,
+                    BITRATE_MODE,
+                    targetBitrate,
+                    true);
+            ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+            if (bufInfo == null) {
+                continue;
+            }
+            skipped = false;
+
+            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, codecMimeType, FPS, params.forceGoogleEncoder);
+        }
+
+        if (skipped) {
+            Log.i(TAG, "SKIPPING testBasic(): codec is not supported");
+        }
+    }
+
+    /**
+     * 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.
+     */
+    private void internalTestAsyncEncoding(String codecMimeType) throws Exception {
+        int encodeSeconds = 9;
+
+        // First test the encoder running in a looper thread with buffer callbacks enabled.
+        boolean syncEncoding = false;
+        EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                INPUT_YUV,
+                ENCODED_IVF_BASE,
+                codecMimeType,
+                encodeSeconds,
+                WIDTH,
+                HEIGHT,
+                FPS,
+                BITRATE_MODE,
+                BITRATE,
+                syncEncoding);
+        ArrayList<MediaCodec.BufferInfo> bufInfos = encodeAsync(params);
+        if (bufInfos == null) {
+            Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
+            return;
+        }
+        computeEncodingStatistics(bufInfos);
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+        VpxDecodingStatistics statisticsAsync = computeDecodingStatistics(
+                params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+                params.frameWidth, params.frameHeight);
+
+
+        // Test the encoder running in a callee's thread.
+        syncEncoding = true;
+        params = getDefaultEncodingParameters(
+                INPUT_YUV,
+                ENCODED_IVF_BASE,
+                codecMimeType,
+                encodeSeconds,
+                WIDTH,
+                HEIGHT,
+                FPS,
+                BITRATE_MODE,
+                BITRATE,
+                syncEncoding);
+        bufInfos = encode(params);
+        if (bufInfos == null) {
+            Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
+            return;
+        }
+        computeEncodingStatistics(bufInfos);
+        decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+        VpxDecodingStatistics statisticsSync = computeDecodingStatistics(
+                params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+                params.frameWidth, params.frameHeight);
+
+        // Check PSNR difference.
+        Log.d(TAG, "PSNR Average: Async: " + statisticsAsync.mAveragePSNR +
+                ". Sync: " + statisticsSync.mAveragePSNR);
+        Log.d(TAG, "PSNR Minimum: Async: " + statisticsAsync.mMinimumPSNR +
+                ". Sync: " + statisticsSync.mMinimumPSNR);
+        if ((Math.abs(statisticsAsync.mAveragePSNR - statisticsSync.mAveragePSNR) >
+            MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE) ||
+            (Math.abs(statisticsAsync.mMinimumPSNR - statisticsSync.mMinimumPSNR) >
+            MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE)) {
+            throw new RuntimeException("Difference between PSNRs for async and sync encoders");
+        }
+    }
+
+    /**
+     * Check if MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME is honored.
+     *
+     * Encodes 9 seconds of raw stream and requests a sync frame every second (30 frames).
+     * The test does not verify the output stream.
+     */
+    private void internalTestSyncFrame(String codecMimeType) throws Exception {
+        int encodeSeconds = 9;
+
+        EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                INPUT_YUV,
+                ENCODED_IVF_BASE,
+                codecMimeType,
+                encodeSeconds,
+                WIDTH,
+                HEIGHT,
+                FPS,
+                BITRATE_MODE,
+                BITRATE,
+                true);
+        params.syncFrameInterval = encodeSeconds * FPS;
+        params.syncForceFrameInterval = FPS;
+        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+        if (bufInfo == null) {
+            Log.i(TAG, "SKIPPING testSyncFrame(): no suitable encoder found");
+            return;
+        }
+
+        VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+
+        // First check if we got expected number of key frames.
+        int actualKeyFrames = statistics.mKeyFrames.size();
+        if (actualKeyFrames != encodeSeconds) {
+            throw new RuntimeException("Number of key frames " + actualKeyFrames +
+                    " is different from the expected " + encodeSeconds);
+        }
+
+        // Check key frame intervals:
+        // Average value should be within +/- 1 frame of the target value,
+        // maximum value should not be greater than target value + 3,
+        // and minimum value should not be less that target value - 3.
+        if (Math.abs(statistics.mAverageKeyFrameInterval - FPS) >
+            MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION ||
+            (statistics.mMaximumKeyFrameInterval - FPS > MAX_KEYFRAME_INTERVAL_VARIATION) ||
+            (FPS - statistics.mMinimumKeyFrameInterval > MAX_KEYFRAME_INTERVAL_VARIATION)) {
+            throw new RuntimeException(
+                    "Key frame intervals are different from the expected " + FPS);
+        }
+    }
+
+    /**
+     * Check if MediaCodec.PARAMETER_KEY_VIDEO_BITRATE is honored.
+     *
+     * Run the the encoder for 12 seconds. Request changes to the
+     * bitrate after 6 seconds and ensure the encoder responds.
+     */
+    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,
+                FPS,
+                BITRATE_MODE,
+                bitrateTargetValues[0],
+                true);
+
+        // Number of seconds for each bitrate
+        int stepSeconds = encodeSeconds / bitrateTargetValues.length;
+        // Fill the bitrates values.
+        params.bitrateSet = new int[encodeSeconds * FPS];
+        for (int i = 0; i < bitrateTargetValues.length ; i++) {
+            Arrays.fill(params.bitrateSet,
+                    i * encodeSeconds * FPS / bitrateTargetValues.length,
+                    (i + 1) * encodeSeconds * FPS / bitrateTargetValues.length,
+                    bitrateTargetValues[i]);
+        }
+
+        ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+        if (bufInfo == null) {
+            Log.i(TAG, "SKIPPING testDynamicBitrateChange(): no suitable encoder found");
+            return;
+        }
+
+        VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+
+        // Calculate actual average bitrates  for every [stepSeconds] second.
+        int[] bitrateActualValues = new int[bitrateTargetValues.length];
+        for (int i = 0; i < bitrateTargetValues.length ; i++) {
+            bitrateActualValues[i] = 0;
+            for (int j = i * stepSeconds; j < (i + 1) * stepSeconds; j++) {
+                bitrateActualValues[i] += statistics.mBitrates.get(j);
+            }
+            bitrateActualValues[i] /= stepSeconds;
+            Log.d(TAG, "Actual bitrate for interval #" + i + " : " + bitrateActualValues[i] +
+                    ". Target: " + bitrateTargetValues[i]);
+
+            // Compare actual bitrate values to make sure at least same increasing/decreasing
+            // order as the target bitrate values.
+            for (int j = 0; j < i; j++) {
+                long differenceTarget = bitrateTargetValues[i] - bitrateTargetValues[j];
+                long differenceActual = bitrateActualValues[i] - bitrateActualValues[j];
+                if (differenceTarget * differenceActual < 0) {
+                    throw new RuntimeException("Target bitrates: " +
+                            bitrateTargetValues[j] + " , " + bitrateTargetValues[i] +
+                            ". Actual bitrates: "
+                            + bitrateActualValues[j] + " , " + bitrateActualValues[i]);
+                }
+            }
+        }
+    }
+
+     /**
+      * Check if encoder and decoder can run simultaneously on different threads.
+      *
+      * Encodes and decodes 9 seconds of raw stream sequentially in CBR mode,
+      * and then run parallel encoding and decoding of the same streams.
+      * Compares average bitrate and PSNR for sequential and parallel runs.
+      */
+     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(codecMimeType, WIDTH, HEIGHT);
+         if (mcl.findEncoderForFormat(format) == null) {
+             Log.i(TAG, "SKIPPING testParallelEncodingAndDecoding(): no suitable encoder found");
+             return;
+         }
+
+         int encodeSeconds = 9;
+         final int[] bitrate = new int[1];
+         final double[] psnr = new double[1];
+         final Exception[] exceptionEncoder = new Exception[1];
+         final Exception[] exceptionDecoder = new Exception[1];
+         final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                 INPUT_YUV,
+                 ENCODED_IVF_BASE,
+                 codecMimeType,
+                 encodeSeconds,
+                 WIDTH,
+                 HEIGHT,
+                 FPS,
+                 VIDEO_ControlRateConstant,
+                 BITRATE,
+                 true);
+         final String inputIvfFilename = params.outputIvfFilename;
+
+         Runnable runEncoder = new Runnable() {
+             public void run() {
+                 try {
+                     ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+                     VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+                     bitrate[0] = statistics.mAverageBitrate;
+                 } catch (Exception e) {
+                     Log.e(TAG, "Encoder error: " + e.toString());
+                     exceptionEncoder[0] = e;
+                 }
+             }
+         };
+         Runnable runDecoder = new Runnable() {
+             public void run() {
+                 try {
+                     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;
+                 } catch (Exception e) {
+                     Log.e(TAG, "Decoder error: " + e.toString());
+                     exceptionDecoder[0] = e;
+                 }
+             }
+         };
+
+         // Sequential encoding and decoding.
+         runEncoder.run();
+         if (exceptionEncoder[0] != null) {
+             throw exceptionEncoder[0];
+         }
+         int referenceBitrate = bitrate[0];
+         runDecoder.run();
+         if (exceptionDecoder[0] != null) {
+             throw exceptionDecoder[0];
+         }
+         double referencePsnr = psnr[0];
+
+         // Parallel encoding and decoding.
+         params.outputIvfFilename = SDCARD_DIR + File.separator + ENCODED_IVF_BASE + "_copy.ivf";
+         Thread threadEncoder = new Thread(runEncoder);
+         Thread threadDecoder = new Thread(runDecoder);
+         threadEncoder.start();
+         threadDecoder.start();
+         threadEncoder.join();
+         threadDecoder.join();
+         if (exceptionEncoder[0] != null) {
+             throw exceptionEncoder[0];
+         }
+         if (exceptionDecoder[0] != null) {
+             throw exceptionDecoder[0];
+         }
+
+         // Compare bitrates and PSNRs for sequential and parallel cases.
+         Log.d(TAG, "Sequential bitrate: " + referenceBitrate + ". PSNR: " + referencePsnr);
+         Log.d(TAG, "Parallel bitrate: " + bitrate[0] + ". PSNR: " + psnr[0]);
+         assertEquals("Bitrate for sequenatial encoding" + referenceBitrate +
+                 " is different from parallel encoding " + bitrate[0],
+                 referenceBitrate, bitrate[0], MAX_BITRATE_VARIATION * referenceBitrate);
+         assertEquals("PSNR for sequenatial encoding" + referencePsnr +
+                 " is different from parallel encoding " + psnr[0],
+                 referencePsnr, psnr[0], MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE);
+     }
+
+
+    /**
+     * Check the encoder quality for various bitrates by calculating PSNR
+     *
+     * Run the the encoder for 9 seconds for each bitrate and calculate PSNR
+     * for each encoded stream.
+     * Video streams with higher bitrates should have higher PSNRs.
+     * Also compares average and minimum PSNR of codec with PSNR values of reference Google codec.
+     */
+    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];
+        boolean[] completed = new boolean[TEST_BITRATES_SET.length];
+        boolean skipped = true;
+
+        // Run platform specific encoder for different bitrates
+        // and compare PSNR of codec with PSNR of reference Google codec.
+        for (int i = 0; i < TEST_BITRATES_SET.length; i++) {
+            EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+                    INPUT_YUV,
+                    ENCODED_IVF_BASE,
+                    codecMimeType,
+                    encodeSeconds,
+                    WIDTH,
+                    HEIGHT,
+                    FPS,
+                    BITRATE_MODE,
+                    TEST_BITRATES_SET[i],
+                    true);
+            if (encode(params) == null) {
+                // parameters not supported, try other bitrates
+                completed[i] = false;
+                continue;
+            }
+            completed[i] = true;
+            skipped = false;
+
+            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;
+            psnrPlatformCodecMin[i] = statistics.mMinimumPSNR;
+        }
+
+        if (skipped) {
+            Log.i(TAG, "SKIPPING testEncoderQuality(): no bitrates supported");
+            return;
+        }
+
+        // First do a sanity check - higher bitrates should results in higher PSNR.
+        for (int i = 1; i < TEST_BITRATES_SET.length ; i++) {
+            if (!completed[i]) {
+                continue;
+            }
+            for (int j = 0; j < i; j++) {
+                if (!completed[j]) {
+                    continue;
+                }
+                double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
+                double differencePSNR = psnrPlatformCodecAverage[i] - psnrPlatformCodecAverage[j];
+                if (differenceBitrate * differencePSNR < 0) {
+                    throw new RuntimeException("Target bitrates: " +
+                            TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
+                            ". Actual PSNRs: "
+                            + psnrPlatformCodecAverage[j] + ", " + psnrPlatformCodecAverage[i]);
+                }
+            }
+        }
+
+        // Then compare average and minimum PSNR of platform codec with reference Google codec -
+        // average PSNR for platform codec should be no more than 2 dB less than reference PSNR
+        // and minumum PSNR - no more than 4 dB less than reference minimum PSNR.
+        // These PSNR difference numbers are arbitrary for now, will need further estimation
+        // when more devices with HW VP8 codec will appear.
+        for (int i = 0; i < TEST_BITRATES_SET.length ; i++) {
+            if (!completed[i]) {
+                continue;
+            }
+
+            Log.d(TAG, "Bitrate " + TEST_BITRATES_SET[i]);
+            Log.d(TAG, "Reference: Average: " + REFERENCE_AVERAGE_PSNR[i] + ". Minimum: " +
+                    REFERENCE_MINIMUM_PSNR[i]);
+            Log.d(TAG, "Platform:  Average: " + psnrPlatformCodecAverage[i] + ". Minimum: " +
+                    psnrPlatformCodecMin[i]);
+            if (psnrPlatformCodecAverage[i] < REFERENCE_AVERAGE_PSNR[i] -
+                    MAX_AVERAGE_PSNR_DIFFERENCE) {
+                throw new RuntimeException("Low average PSNR " + psnrPlatformCodecAverage[i] +
+                        " comparing to reference PSNR " + REFERENCE_AVERAGE_PSNR[i] +
+                        " for bitrate " + TEST_BITRATES_SET[i]);
+            }
+            if (psnrPlatformCodecMin[i] < REFERENCE_MINIMUM_PSNR[i] -
+                    MAX_MINIMUM_PSNR_DIFFERENCE) {
+                throw new RuntimeException("Low minimum PSNR " + psnrPlatformCodecMin[i] +
+                        " comparing to reference PSNR " + REFERENCE_MINIMUM_PSNR[i] +
+                        " for bitrate " + TEST_BITRATES_SET[i]);
+            }
+        }
+    }
+
+    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/mediastress/Android.mk b/tests/tests/mediastress/Android.mk
index 4cbc4cc..34bc778 100644
--- a/tests/tests/mediastress/Android.mk
+++ b/tests/tests/mediastress/Android.mk
@@ -26,7 +26,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_HOST_SHARED_LIBRARIES := compatibility-device-media-preconditions
 
diff --git a/tests/tests/mediastress/AndroidTest.xml b/tests/tests/mediastress/AndroidTest.xml
index a0cc68a..b41fcf3 100644
--- a/tests/tests/mediastress/AndroidTest.xml
+++ b/tests/tests/mediastress/AndroidTest.xml
@@ -27,6 +27,6 @@
         <option name="package" value="android.mediastress.cts" />
         <!-- test-timeout unit is ms, value = 30 min -->
         <option name="test-timeout" value="1800000" />
-        <option name="runtime-hint" value="2h50m" />
+        <option name="runtime-hint" value="3h" />
     </test>
 </configuration>
diff --git a/tests/tests/mediastress/preconditions/Android.mk b/tests/tests/mediastress/preconditions/Android.mk
index 139bf23..573f083 100644
--- a/tests/tests/mediastress/preconditions/Android.mk
+++ b/tests/tests/mediastress/preconditions/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/tests/tests/mediastress/preconditions/app/Android.mk b/tests/tests/mediastress/preconditions/app/Android.mk
index b8aa32a..0ef2de4 100644
--- a/tests/tests/mediastress/preconditions/app/Android.mk
+++ b/tests/tests/mediastress/preconditions/app/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java b/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
index 9830cff..1b55196 100644
--- a/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
+++ b/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
@@ -16,9 +16,9 @@
 package android.mediastress.cts.preconditions.app;
 
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import com.android.compatibility.common.util.MediaUtils;
 
 import android.app.Instrumentation;
-import android.cts.util.MediaUtils;
 import android.media.MediaFormat;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
diff --git a/tests/tests/mediastress/preconditions/tests/Android.mk b/tests/tests/mediastress/preconditions/tests/Android.mk
index 28549f5..e2dae48 100644
--- a/tests/tests/mediastress/preconditions/tests/Android.mk
+++ b/tests/tests/mediastress/preconditions/tests/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := easymock
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt compatibility-host-media-preconditions
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed compatibility-host-media-preconditions
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
index 400aedf..d5d01c8 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
@@ -17,11 +17,11 @@
 package android.mediastress.cts;
 
 import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+import com.android.compatibility.common.util.MediaUtils;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
-import android.cts.util.MediaUtils;
 import android.media.MediaFormat;
 import android.media.MediaRecorder.AudioEncoder;
 import android.media.MediaRecorder.VideoEncoder;
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
index 40284a6..192f213 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
@@ -17,7 +17,6 @@
 
 import android.app.Instrumentation;
 import android.content.Intent;
-import android.cts.util.MediaUtils;
 import android.media.MediaFormat;
 import android.media.MediaRecorder.AudioEncoder;
 import android.media.MediaRecorder.VideoEncoder;
@@ -25,6 +24,8 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import junit.framework.Assert;
 
 public class NativeMediaTest extends ActivityInstrumentationTestCase2<NativeMediaActivity> {
diff --git a/tests/tests/midi/Android.mk b/tests/tests/midi/Android.mk
index 3dc0c8b..eeda8c8 100755
--- a/tests/tests/midi/Android.mk
+++ b/tests/tests/midi/Android.mk
@@ -25,7 +25,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/midi/AndroidTest.xml b/tests/tests/midi/AndroidTest.xml
index c95ab89..ebb2c72 100644
--- a/tests/tests/midi/AndroidTest.xml
+++ b/tests/tests/midi/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.midi.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/multiuser/Android.mk b/tests/tests/multiuser/Android.mk
index ae1be7e..67db1f5 100644
--- a/tests/tests/multiuser/Android.mk
+++ b/tests/tests/multiuser/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_PACKAGE_NAME := CtsMultiUserTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/multiuser/AndroidTest.xml b/tests/tests/multiuser/AndroidTest.xml
index c05430e..d5593627 100644
--- a/tests/tests/multiuser/AndroidTest.xml
+++ b/tests/tests/multiuser/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.multiuser.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java b/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
index 206a613..3e9122b 100644
--- a/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
+++ b/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
@@ -16,8 +16,8 @@
 
 package android.multiuser.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
 
-import android.cts.util.SystemUtil;
 import android.os.UserManager;
 import android.test.InstrumentationTestCase;
 import android.util.Log;
diff --git a/tests/tests/nativemedia/sl/AndroidTest.xml b/tests/tests/nativemedia/sl/AndroidTest.xml
index c73c1b4..849893a 100644
--- a/tests/tests/nativemedia/sl/AndroidTest.xml
+++ b/tests/tests/nativemedia/sl/AndroidTest.xml
@@ -22,5 +22,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="CtsNativeMediaSlTestCases" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/nativemedia/xa/AndroidTest.xml b/tests/tests/nativemedia/xa/AndroidTest.xml
index 229d8aa..4ca378c 100644
--- a/tests/tests/nativemedia/xa/AndroidTest.xml
+++ b/tests/tests/nativemedia/xa/AndroidTest.xml
@@ -22,5 +22,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="CtsNativeMediaXaTestCases" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/ndef/AndroidTest.xml b/tests/tests/ndef/AndroidTest.xml
index cfb40d3..5e4de24 100644
--- a/tests/tests/ndef/AndroidTest.xml
+++ b/tests/tests/ndef/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.ndef.cts" />
+        <option name="runtime-hint" value="10m10s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index c553a9b..4a77640 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -34,7 +34,7 @@
 
 LOCAL_PACKAGE_NAME := CtsNetTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support  ctsdeviceutil \
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support  compatibility-device-util \
                                ctstestrunner ctstestserver mockwebserver
 
 # uncomment when b/13249961 is fixed
diff --git a/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java b/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
index 7987a50..198f973 100644
--- a/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
+++ b/tests/tests/net/src/android/net/http/cts/HttpResponseCacheTest.java
@@ -21,9 +21,10 @@
 
 import junit.framework.TestCase;
 
-import android.cts.util.FileUtils;
 import android.net.http.HttpResponseCache;
 
+import com.android.compatibility.common.util.FileUtils;
+
 import java.io.File;
 import java.io.InputStream;
 import java.net.CacheRequest;
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
index 696d215..5983cb7 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.PollingCheck;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -29,6 +28,8 @@
 import android.net.wifi.WifiSsid;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.concurrent.Callable;
 
 public class WifiInfoTest extends AndroidTestCase {
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidTest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidTest.xml
index cd9e969..838367b 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidTest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.cts.netsecpolicy.usescleartext.false" />
+        <option name="runtime-hint" value="12m" />
     </test>
 </configuration>
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidTest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidTest.xml
index de0baf0..b30c53f 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidTest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.cts.netsecpolicy.usescleartext.true" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidTest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidTest.xml
index bbe34d7..9ede86b 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidTest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidTest.xml
@@ -21,5 +21,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.cts.netsecpolicy.usescleartext.unspecified" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidTest.xml
index db52e8a..b2c1400 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigAttributeTestCases" />
+        <option name="runtime-hint" value="8m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidTest.xml
index 6633c55..901022f 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigBasicDomainConfigTestCases" />
+        <option name="runtime-hint" value="11m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
index 9957342..829899c 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases" />
+        <option name="runtime-hint" value="8m10s" />
     </test>
 </configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidTest.xml
index de1cc1b..5d12f0a 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigBasicDebugDisabledTestCases" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidTest.xml
index fe6e6dc..38a2d31 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigBasicDebugEnabledTestCases" />
+        <option name="runtime-hint" value="12m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidTest.xml
index e966baa..7ce9f7a 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigDownloadManagerTestCases" />
+        <option name="runtime-hint" value="11m" />
     </test>
 </configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidTest.xml
index 4f9adbc..127927f 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigInvalidPinTestCases" />
+        <option name="runtime-hint" value="10m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidTest.xml
index c6a1dd1..e430dbd 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigNestedDomainConfigTestCases" />
+        <option name="runtime-hint" value="7m45s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidTest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidTest.xml
index aa6df4d..570160c 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidTest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.security.net.config.cts.CtsNetSecConfigResourcesSrcTestCases" />
+        <option name="runtime-hint" value="11m30s" />
     </test>
 </configuration>
diff --git a/tests/tests/opengl/Android.mk b/tests/tests/opengl/Android.mk
index 69090f5..b13f3ad 100644
--- a/tests/tests/opengl/Android.mk
+++ b/tests/tests/opengl/Android.mk
@@ -33,7 +33,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 18 # Mirroring the manifest minSdk
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/opengl/AndroidManifest.xml b/tests/tests/opengl/AndroidManifest.xml
index cc0ab8f..bb79490 100644
--- a/tests/tests/opengl/AndroidManifest.xml
+++ b/tests/tests/opengl/AndroidManifest.xml
@@ -19,7 +19,8 @@
     android:versionName="1.0" >
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-    <uses-sdk android:minSdkVersion="14" />
+    <!-- GLES30 requires 18 -->
+    <uses-sdk android:minSdkVersion="18" />
     <uses-feature android:glEsVersion="0x00020000"/>
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/opengl/AndroidTest.xml b/tests/tests/opengl/AndroidTest.xml
index 124d072..f112f83 100644
--- a/tests/tests/opengl/AndroidTest.xml
+++ b/tests/tests/opengl/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.opengl.cts" />
+        <option name="runtime-hint" value="11m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/opengl/DEPRECATED b/tests/tests/opengl/DEPRECATED
new file mode 100644
index 0000000..59d5124
--- /dev/null
+++ b/tests/tests/opengl/DEPRECATED
@@ -0,0 +1,3 @@
+This suite of tests is deprecated. Please add OpenGL CTS test to either:
+- dEQP for native tests
+- graphics/src/android/opengl/cts for Java bindings tests
diff --git a/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
index b7917e2..0b76770 100644
--- a/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/AttachShaderTest.java
@@ -146,4 +146,11 @@
         int error = mActivity.glGetError();
         assertEquals(GLES20.GL_NO_ERROR, error);
     }
+
+    public void test_glCompileShaders_shader_info_log_fail() throws Throwable {
+        mActivity = getShaderActivity(Constants.SHADER, 12);
+        String log = mActivity.glGetInfoLog();
+        assertNotNull(log);
+        assertTrue(log.length() > 0);
+    }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
index 5acac32..0e11165 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityOne.java
@@ -41,8 +41,11 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Window window = getWindow();
-        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
-
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         int viewType = getIntent().getIntExtra(EXTRA_VIEW_TYPE, -1);
         int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
 
@@ -58,6 +61,10 @@
         return ((RendererBase)mRenderer).mError;
     }
 
+    public String glGetInfoLog() {
+        return ((RendererBase)mRenderer).mInfoLog;
+    }
+
     public boolean waitForFrameDrawn() {
         boolean result = false;
         try {
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityTwo.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityTwo.java
index 8ed0b9c..f0c7881 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityTwo.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20ActivityTwo.java
@@ -20,6 +20,8 @@
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView.Renderer;
 import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
 
 import java.lang.InterruptedException;
 import java.util.concurrent.CountDownLatch;
@@ -48,14 +50,20 @@
     }
 
     public void setView(int type, int i, float[] vertexColors ) {
-        view = new OpenGLES20View(this,type,i, vertexColors, mLatch);
+        // Note: Flags should be modified before the content view is set
+        Window window = getWindow();
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        view = new OpenGLES20View(this, type, i, vertexColors, mLatch);
         setContentView(view);
     }
 
     public void setView(int type, int i) {
         float[] f = {};
-        view = new OpenGLES20View(this, type, i, f, mLatch)  ;
-        setContentView(view);
+        setView(type, i, f);
     }
 
     public int getNoOfAttachedShaders() {
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityOne.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityOne.java
index 4602d4f..61f97b3 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityOne.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityOne.java
@@ -51,8 +51,11 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Window window = getWindow();
-        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
-
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         int viewType = getIntent().getIntExtra(EXTRA_VIEW_TYPE, -1);
         int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
 
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityTwo.java b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityTwo.java
index 6bdf95f..90964f8 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityTwo.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGLES20NativeActivityTwo.java
@@ -20,8 +20,11 @@
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView.Renderer;
 import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
 
 import java.lang.InterruptedException;
+import java.lang.UnsupportedOperationException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -48,12 +51,19 @@
     }
 
     public void setView(int type, int i, float[] vertexColors ) {
+        // Note: Flags should be modified before the content view is set
+        Window window = getWindow();
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         view = new OpenGLES20View(this,type,i, vertexColors, mLatch);
         setContentView(view);
     }
 
     public void setView(int type, int i) {
-
+        throw new UnsupportedOperationException("No views without vertexColors, please!");
     }
 
     public int getNoOfAttachedShaders() {
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererBase.java b/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
index 994c1c6..a5a281b 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererBase.java
@@ -34,6 +34,7 @@
 
     int[] mShaderCount = null;
     int mError;
+    String mInfoLog = null;
 
     // child may need to manipulate them directly
     protected CountDownLatch mLatch;
@@ -52,6 +53,7 @@
         int shader = GLES20.glCreateShader(type);
         GLES20.glShaderSource(shader, shaderCode);
         GLES20.glCompileShader(shader);
+        mInfoLog = GLES20.glGetShaderInfoLog(shader);
         return shader;
     }
 
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererElevenShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererElevenShaderTest.java
index 35df7b5..cc047fa 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererElevenShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererElevenShaderTest.java
@@ -22,8 +22,6 @@
 import android.opengl.GLES20;
 
 public class RendererElevenShaderTest extends RendererBase {
-    private String fragmentShaderCode = Vertex.successfulcompile_vertex;
-
     public RendererElevenShaderTest(CountDownLatch latch) {
         super(latch);
     }
@@ -31,10 +29,10 @@
     @Override
     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
         GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
-        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, Vertex.successfulcompile_vertex);
         mProgram =  GLES20.glCreateProgram();
 
-        GLES20.glAttachShader(mProgram, fragmentShader);
+        GLES20.glAttachShader(mProgram, vertexShader);
         GLES20.glLinkProgram(mProgram);
 
         mError = GLES20.glGetError();
diff --git a/tests/tests/opengl/src/android/opengl/cts/RendererTwelveShaderTest.java b/tests/tests/opengl/src/android/opengl/cts/RendererTwelveShaderTest.java
index a3dab8e..3e18221 100644
--- a/tests/tests/opengl/src/android/opengl/cts/RendererTwelveShaderTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/RendererTwelveShaderTest.java
@@ -22,7 +22,7 @@
 import android.opengl.GLES20;
 
 public class RendererTwelveShaderTest extends RendererBase {
-    private String fragmentShaderCode = Shaders.successfulcompile_frag;
+    private String fragmentShaderCode = Shaders.errorcompile_frag;
 
     public RendererTwelveShaderTest(CountDownLatch latch) {
         super(latch);
@@ -32,8 +32,6 @@
     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
         GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
         int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
-        //invalid value
-        mProgram =  0;
 
         GLES20.glAttachShader(mProgram, fragmentShader);
         GLES20.glLinkProgram(mProgram);
diff --git a/tests/tests/opengl/src/android/opengl/cts/Shaders.java b/tests/tests/opengl/src/android/opengl/cts/Shaders.java
index e8025fc..7e0113e 100644
--- a/tests/tests/opengl/src/android/opengl/cts/Shaders.java
+++ b/tests/tests/opengl/src/android/opengl/cts/Shaders.java
@@ -54,4 +54,40 @@
         + "    gl_FragColor = vec4 (ct, 1.0); \n"
         + "} \n";
 
+    public static String errorcompile_frag =
+        "#ifdef GL_ES \n"
+        + "precision mediump float; \n"
+        + "#endif \n"
+        + "uniform float   mortarThickness; \n"
+        + "uniform vec3    brickColor; \n"
+        + "uniform vec3    mortarColor; \n"
+
+        + "uniform float   brickMortarWidth; \n"
+        + "uniform float   brickMortarHeight; \n"
+        + "uniform float   mhf; \n"
+
+        + "varying vec3  Position; \n"
+        + "varying float lightIntensity; \n"
+        + "\n"
+        + "void main (void){ \n"
+        + "    vec3    ct; \n"
+        + "    float   ss, tt, w, h; \n"
+        + ""
+        + "    vec3 pos = Position; \n"
+        + ""
+        + "    ss = pos.x / brickMortarWidth; \n"
+        + "    tt = pos.z / brickMortarHeight; \n"
+        + "    if (fract (tt * 0.5) > 0.5) \n"
+        + "        ss += 0.5; \n"
+
+        + "    ss = fract (ss); \n"
+        + "    tt = fract (tt); \n"
+
+        + "    w = step (mwf, ss) - step (1.0 - mwf, ss); \n"
+        + "    h = step (mhf, tt) - step (1.0 - mhf, tt); \n"
+
+        + "    ct = clamp(mix (mortarColor, brickColor, w * h) * lightIntensity, 0.0, 1.0); \n"
+
+        + "    gl_FragColor = vec4 (ct, 1); \n"
+        + "} \n";
 }
diff --git a/tests/tests/openglperf/Android.mk b/tests/tests/openglperf/Android.mk
index eea3b86..46e316a 100644
--- a/tests/tests/openglperf/Android.mk
+++ b/tests/tests/openglperf/Android.mk
@@ -24,7 +24,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsopenglperf_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/openglperf/src/android/openglperf/cts/PlanetsRenderer.java b/tests/tests/openglperf/src/android/openglperf/cts/PlanetsRenderer.java
index b286e46..1d79961 100644
--- a/tests/tests/openglperf/src/android/openglperf/cts/PlanetsRenderer.java
+++ b/tests/tests/openglperf/src/android/openglperf/cts/PlanetsRenderer.java
@@ -16,8 +16,9 @@
 
 package android.openglperf.cts;
 
+import com.android.compatibility.common.util.WatchDog;
+
 import android.content.Context;
-import android.cts.util.WatchDog;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.opengl.GLES20;
diff --git a/tests/tests/openglperf/src/android/openglperf/cts/PlanetsSurfaceView.java b/tests/tests/openglperf/src/android/openglperf/cts/PlanetsSurfaceView.java
index afe664f..16c8a32 100755
--- a/tests/tests/openglperf/src/android/openglperf/cts/PlanetsSurfaceView.java
+++ b/tests/tests/openglperf/src/android/openglperf/cts/PlanetsSurfaceView.java
@@ -16,8 +16,9 @@
 
 package android.openglperf.cts;
 
+import com.android.compatibility.common.util.WatchDog;
+
 import android.content.Context;
-import android.cts.util.WatchDog;
 
 class PlanetsSurfaceView extends GLSurfaceViewCustom {
     private final long RENDERING_TIMEOUT = 1900; // in msec, close to 2 secs
diff --git a/tests/tests/openglperf/src/android/openglperf/cts/TextureTestActivity.java b/tests/tests/openglperf/src/android/openglperf/cts/TextureTestActivity.java
index 4d7d641..6459c31 100644
--- a/tests/tests/openglperf/src/android/openglperf/cts/TextureTestActivity.java
+++ b/tests/tests/openglperf/src/android/openglperf/cts/TextureTestActivity.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.view.WindowManager;
 
 public class TextureTestActivity extends Activity {
     private GLSurfaceView mGLView;
@@ -27,6 +28,11 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mGLView = new TextureTestSurfaceView(this);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         setContentView(mGLView);
     }
 
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index e9a321f..7effcab 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 compatibility-device-util ctstestrunner guava platform-test-annotations
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libctsos_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index 6f9c237..2638c45 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1,3 +1 @@
-7.1
-7.1.1
-7.1.2
+O
diff --git a/tests/tests/os/src/android/os/cts/AbiTest.java b/tests/tests/os/src/android/os/cts/AbiTest.java
index 1d343e6..49ff8aa 100644
--- a/tests/tests/os/src/android/os/cts/AbiTest.java
+++ b/tests/tests/os/src/android/os/cts/AbiTest.java
@@ -16,9 +16,10 @@
 
 package android.os.cts;
 
-import android.cts.util.ReadElf;
 import android.util.ArraySet;
 
+import com.android.compatibility.common.util.ReadElf;
+
 import java.io.File;
 import java.util.Arrays;
 
diff --git a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
index 1c9aaba..335818a 100644
--- a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
+++ b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
@@ -17,11 +17,11 @@
 package android.os.cts;
 
 import android.support.annotation.NonNull;
-
-import android.cts.util.PollingCheck;
 import android.os.AsyncTask;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index a0446bf..a0f7d5b 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -19,6 +19,7 @@
 
 import android.os.Build;
 import android.os.SystemProperties;
+import android.platform.test.annotations.RestrictedBuildTest;
 
 import dalvik.system.VMRuntime;
 
@@ -232,6 +233,7 @@
      * Note: This test will fail on userdebug / eng devices, but should pass
      * on production (user) builds.
      */
+    @RestrictedBuildTest
     public void testIsSecureUserBuild() throws IOException {
         assertEquals("Must be a user build", "user", Build.TYPE);
         assertProperty("Must be a non-debuggable build", RO_DEBUGGABLE, "0");
diff --git a/tests/tests/os/src/android/os/cts/ConditionVariableTest.java b/tests/tests/os/src/android/os/cts/ConditionVariableTest.java
index cad9dec..d5593dc 100644
--- a/tests/tests/os/src/android/os/cts/ConditionVariableTest.java
+++ b/tests/tests/os/src/android/os/cts/ConditionVariableTest.java
@@ -16,9 +16,11 @@
 package android.os.cts;
 
 import junit.framework.TestCase;
-import android.cts.util.TestThread;
+
 import android.os.ConditionVariable;
 
+import com.android.compatibility.common.util.TestThread;
+
 public class ConditionVariableTest extends TestCase {
     private static final int WAIT_TIME = 3000;
     private static final int BLOCK_TIME = 1000;
diff --git a/tests/tests/os/src/android/os/cts/DebugTest.java b/tests/tests/os/src/android/os/cts/DebugTest.java
index 8301cfc..0f19078 100644
--- a/tests/tests/os/src/android/os/cts/DebugTest.java
+++ b/tests/tests/os/src/android/os/cts/DebugTest.java
@@ -15,6 +15,14 @@
  */
 package android.os.cts;
 
+import android.content.Context;
+import android.os.Debug;
+import android.test.AndroidTestCase;
+
+import com.android.compatibility.common.util.TestThread;
+
+import dalvik.system.VMDebug;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -22,12 +30,6 @@
 import java.util.logging.Logger;
 import java.util.Map;
 
-import android.content.Context;
-import android.cts.util.TestThread;
-import android.os.Debug;
-import android.test.AndroidTestCase;
-import dalvik.system.VMDebug;
-
 public class DebugTest extends AndroidTestCase {
     private static final Logger Log = Logger.getLogger(DebugTest.class.getName());
 
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index 0c3ada2..62c856d 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -15,9 +15,13 @@
  */
 package android.os.cts;
 
-import junit.framework.TestCase;
 import android.os.Environment;
 
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
 public class EnvironmentTest extends TestCase {
     public void testEnvironment() {
         new Environment();
@@ -38,4 +42,25 @@
         assertNull("environment variable TMPDIR should not be set",
                 System.getenv("TMPDIR"));
     }
+
+    /**
+     * Verify that all writable block filesystems are mounted "noatime" to avoid
+     * unnecessary flash churn.
+     */
+    public void testNoAtime() throws Exception {
+        try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                final String[] fields = line.split(" ");
+                final String source = fields[0];
+                final String options = fields[3];
+
+                if (source.startsWith("/dev/block/") && !options.startsWith("ro,")
+                        && !options.contains("noatime")) {
+                    fail("Found device mounted at " + source + " without 'noatime' option, "
+                            + "which can cause unnecessary flash churn; please update your fstab.");
+                }
+            }
+        }
+    }
 }
diff --git a/tests/tests/os/src/android/os/cts/HandlerTest.java b/tests/tests/os/src/android/os/cts/HandlerTest.java
index 7183d7e..d161f6a 100644
--- a/tests/tests/os/src/android/os/cts/HandlerTest.java
+++ b/tests/tests/os/src/android/os/cts/HandlerTest.java
@@ -17,7 +17,7 @@
 package android.os.cts;
 
 import junit.framework.TestCase;
-import android.cts.util.TestThread;
+
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -26,6 +26,8 @@
 import android.test.UiThreadTest;
 import android.util.Printer;
 
+import com.android.compatibility.common.util.TestThread;
+
 public class HandlerTest extends TestCase {
 
     public static final int MESSAGE_WHAT = 3;
diff --git a/tests/tests/os/src/android/os/cts/LocalService.java b/tests/tests/os/src/android/os/cts/LocalService.java
index cc427f8..41f1c18 100644
--- a/tests/tests/os/src/android/os/cts/LocalService.java
+++ b/tests/tests/os/src/android/os/cts/LocalService.java
@@ -18,12 +18,13 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.cts.util.IBinderParcelable;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
 
+import com.android.compatibility.common.util.IBinderParcelable;
+
 public class LocalService extends Service {
     public static final String SERVICE_LOCAL =
             "android.os.cts.activity.SERVICE_LOCAL";
diff --git a/tests/tests/os/src/android/os/cts/LooperTest.java b/tests/tests/os/src/android/os/cts/LooperTest.java
index 6f7cb6d..c0a176c 100644
--- a/tests/tests/os/src/android/os/cts/LooperTest.java
+++ b/tests/tests/os/src/android/os/cts/LooperTest.java
@@ -16,7 +16,6 @@
 
 package android.os.cts;
 
-import android.cts.util.TestThread;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -26,6 +25,8 @@
 import android.util.Printer;
 import android.util.StringBuilderPrinter;
 
+import com.android.compatibility.common.util.TestThread;
+
 public class LooperTest extends AndroidTestCase {
 
     public static final long WAIT_TIME = 1000;
diff --git a/tests/tests/os/src/android/os/cts/MessengerTest.java b/tests/tests/os/src/android/os/cts/MessengerTest.java
index 5bf9428..7612c14 100644
--- a/tests/tests/os/src/android/os/cts/MessengerTest.java
+++ b/tests/tests/os/src/android/os/cts/MessengerTest.java
@@ -31,6 +31,7 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.test.AndroidTestCase;
 
 import java.io.FileDescriptor;
@@ -91,7 +92,7 @@
 
         @Override
         public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-                String[] args, ResultReceiver resultReceiver) {
+                String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver) {
         }
 
     };
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index 5b7b187..305f0c8 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -3085,4 +3085,77 @@
 
         assertFalse(doesNotImplementParcelableInitializerHasRun);
     }
+
+    public static class SimpleParcelable implements Parcelable {
+        private final int value;
+
+        public SimpleParcelable(int value) {
+            this.value = value;
+        }
+
+        private SimpleParcelable(Parcel in) {
+            this.value = in.readInt();
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(value);
+        }
+
+        public static Parcelable.Creator<SimpleParcelable> CREATOR =
+                new Parcelable.Creator<SimpleParcelable>() {
+
+            @Override
+            public SimpleParcelable createFromParcel(Parcel source) {
+                return new SimpleParcelable(source);
+            }
+
+            @Override
+            public SimpleParcelable[] newArray(int size) {
+                return new SimpleParcelable[size];
+            }
+        };
+    }
+
+    public void testReadWriteParcellableList() {
+        Parcel parcel = Parcel.obtain();
+
+        ArrayList<SimpleParcelable> list = new ArrayList<>();
+        list.add(new SimpleParcelable(57));
+
+        // Writing a |null| list to a parcel should work, and reading it back
+        // from a parcel should clear the target list.
+        parcel.writeParcelableList(null, 0);
+        parcel.setDataPosition(0);
+        parcel.readParcelableList(list, SimpleParcelable.class.getClassLoader());
+        assertEquals(0, list.size());
+
+        list.clear();
+        list.add(new SimpleParcelable(42));
+        list.add(new SimpleParcelable(56));
+
+        parcel.setDataPosition(0);
+        parcel.writeParcelableList(list, 0);
+
+        // Populate the list with a value, we will later assert that the
+        // value has been removed.
+        list.clear();
+        list.add(new SimpleParcelable(100));
+
+        parcel.setDataPosition(0);
+        parcel.readParcelableList(list, SimpleParcelable.class.getClassLoader());
+
+        assertEquals(2, list.size());
+        assertEquals(42, list.get(0).getValue());
+        assertEquals(56, list.get(1).getValue());
+    }
 }
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index f9a58ad..13df2a9 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -23,7 +23,6 @@
 import android.content.res.Resources.NotFoundException;
 import android.os.Environment;
 import android.os.Parcel;
-import android.cts.util.FileUtils;
 import android.os.storage.OnObbStateChangeListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
@@ -31,6 +30,8 @@
 import android.test.ComparisonFailure;
 import android.util.Log;
 
+import com.android.compatibility.common.util.FileUtils;
+
 import libcore.io.Streams;
 
 import java.io.File;
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index f64db70..a01352a 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.permission.cts" />
+        <option name="runtime-hint" value="13m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/permission/jni/Android.mk b/tests/tests/permission/jni/Android.mk
index ea45096..91c0540 100644
--- a/tests/tests/permission/jni/Android.mk
+++ b/tests/tests/permission/jni/Android.mk
@@ -29,5 +29,6 @@
 
 LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++ liblog
 LOCAL_SDK_VERSION := 23
+LOCAL_CPPFLAGS := -std=gnu++11
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
index 6d55a69..909ac35 100644
--- a/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ProviderPermissionTest.java
@@ -17,18 +17,24 @@
 package android.permission.cts;
 
 import android.content.ContentValues;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.provider.CallLog;
 import android.provider.Contacts;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import java.util.List;
+import java.util.Objects;
+
 /**
  * Tests Permissions related to reading from and writing to providers
  */
 @MediumTest
 public class ProviderPermissionTest extends AndroidTestCase {
-
     /**
      * Verify that read and write to contact requires permissions.
      * <p>Tests Permission:
@@ -90,4 +96,38 @@
                     expected.getMessage().contains(permission));
         }
     }
+
+    /**
+     * Verify that the {@link android.Manifest.permission#MANAGE_DOCUMENTS}
+     * permission is only held by exactly one package: whoever handles the
+     * {@link android.content.Intent#ACTION_OPEN_DOCUMENT} intent.
+     * <p>
+     * No other apps should <em>ever</em> attempt to acquire this permission,
+     * since it would give those apps extremely broad access to all storage
+     * providers on the device without user involvement in the arbitration
+     * process. Apps should instead always rely on Uri permission grants for
+     * access, using
+     * {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} and related
+     * APIs.
+     */
+    public void testManageDocuments() {
+        final PackageManager pm = getContext().getPackageManager();
+
+        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        final ResolveInfo ri = pm.resolveActivity(intent, 0);
+        final String validPkg = ri.activityInfo.packageName;
+
+        final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] {
+                android.Manifest.permission.MANAGE_DOCUMENTS
+        }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (PackageInfo pi : holding) {
+            if (!Objects.equals(pi.packageName, validPkg)) {
+                fail("Exactly one package (must be " + validPkg
+                        + ") can request the MANAGE_DOCUMENTS permission; found package "
+                        + pi.packageName + " which must be revoked for security reasons");
+            }
+        }
+    }
 }
diff --git a/tests/tests/permission2/Android.mk b/tests/tests/permission2/Android.mk
index 1b4251a..d4f48f4 100755
--- a/tests/tests/permission2/Android.mk
+++ b/tests/tests/permission2/Android.mk
@@ -26,12 +26,12 @@
 
 LOCAL_JAVA_LIBRARIES := telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := CtsPermission2TestCases
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index b6b2f92..ca7a698 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|ephemeral" />
 
     <!-- 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|ephemeral" />
 
     <!-- ====================================================================== -->
     <!-- 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,30 @@
          <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 read access to the device's phone number. This is a subset of the capabilities
+         granted by {@link #READ_PHONE_STATE} but is exposed to ephemeral applications.
+         <p>Protection level: dangerous-->
+    <permission android:name="android.permission.READ_PHONE_NUMBER"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readPhoneNumber"
+        android:description="@string/permdesc_readPhoneNumber"
+        android:protectionLevel="dangerous|ephemeral" />
 
     <!-- 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 +769,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 +787,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 +806,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 +835,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 +849,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 +871,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 +891,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 +906,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|ephemeral" />
 
 
     <!-- ====================================================================== -->
@@ -915,28 +920,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 +949,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 +1035,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 +1079,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 +1092,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 +1109,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 +1136,7 @@
          @hide
     -->
     <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing networks -->
@@ -1144,73 +1147,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|ephemeral" />
 
     <!-- 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|ephemeral" />
 
     <!-- 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,48 +1224,48 @@
          <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 an internal user to use restricted Networks.
          @hide -->
@@ -1272,22 +1275,22 @@
     <!-- 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 -->
@@ -1306,15 +1309,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-->
@@ -1325,34 +1328,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|ephemeral" />
 
     <!-- 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|ephemeral" />
 
     <!-- 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   -->
@@ -1363,9 +1366,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 -->
@@ -1375,53 +1378,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. -->
@@ -1431,17 +1434,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 -->
@@ -1452,12 +1455,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 -->
@@ -1468,50 +1471,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.
@@ -1520,24 +1523,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 -->
@@ -1547,7 +1550,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.
@@ -1557,14 +1560,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         -->
@@ -1575,9 +1578,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  -->
@@ -1586,9 +1589,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
@@ -1601,32 +1604,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,
@@ -1639,69 +1642,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  -->
@@ -1724,9 +1727,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 -->
@@ -1737,17 +1740,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 -->
@@ -1757,15 +1760,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   -->
@@ -1776,9 +1779,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 -->
@@ -1789,17 +1792,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   -->
@@ -1810,25 +1813,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 -->
@@ -1837,12 +1840,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.
 
@@ -1857,51 +1860,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
@@ -1917,9 +1920,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,
@@ -1928,90 +1931,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
@@ -2020,12 +2023,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 -->
@@ -2035,40 +2033,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                  -->
@@ -2077,34 +2075,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.
@@ -2112,28 +2110,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.
@@ -2141,7 +2139,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.
@@ -2149,17 +2147,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
@@ -2168,24 +2166,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
@@ -2194,13 +2192,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
@@ -2208,7 +2206,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.
@@ -2216,42 +2214,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.
@@ -2260,7 +2258,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
@@ -2268,65 +2266,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}
@@ -2335,7 +2333,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.
@@ -2343,32 +2341,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.
@@ -2376,33 +2374,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
@@ -2410,41 +2408,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.
@@ -2452,250 +2450,250 @@
          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 modes set for displays system-wide.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
-                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
@@ -2704,25 +2702,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
@@ -2733,7 +2731,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
@@ -2743,33 +2741,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
@@ -2777,67 +2775,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,
@@ -2846,27 +2844,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.
@@ -2877,42 +2875,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},
@@ -2920,7 +2918,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.
@@ -2928,7 +2926,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
@@ -2936,7 +2934,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},
@@ -2944,57 +2942,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
@@ -3002,9 +3000,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.
@@ -3050,7 +3048,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.
@@ -3062,7 +3060,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.
@@ -3086,17 +3084,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.
@@ -3117,13 +3115,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" />
@@ -3131,102 +3128,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" />
@@ -3238,9 +3235,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"
@@ -3257,9 +3254,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" />
@@ -3267,20 +3264,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="*/*" />
@@ -3288,7 +3285,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="*/*" />
@@ -3296,7 +3293,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="*/*" />
@@ -3304,7 +3301,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="*/*" />
@@ -3312,7 +3309,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="*/*" />
@@ -3320,23 +3317,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 -->
@@ -3349,12 +3338,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>
@@ -3379,9 +3368,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/NoReceiveSmsPermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
index d0cafe9..5699d88 100644
--- a/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
@@ -42,6 +42,9 @@
         "com.android.cts.permission.sms.MESSAGE_STATUS_RECEIVED_ACTION";
     private static final String MESSAGE_SENT_ACTION =
         "com.android.cts.permission.sms.MESSAGE_SENT";
+    private static final String APP_SPECIFIC_SMS_RECEIVED_ACTION =
+        "com.android.cts.permission.sms.APP_SPECIFIC_SMS_RECEIVED";
+
 
     private static final String LOG_TAG = "NoReceiveSmsPermissionTest";
 
@@ -70,7 +73,7 @@
         filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
 
         getContext().registerReceiver(receiver, filter);
-        sendSMSToSelf();
+        sendSMSToSelf("test");
         synchronized(receiver) {
             try {
                 receiver.wait(WAIT_TIME);
@@ -84,7 +87,46 @@
         assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
     }
 
-    private void sendSMSToSelf() {
+    /**
+     * Verify that without {@link android.Manifest.permission#RECEIVE_SMS} that an SMS sent
+     * containing a nonce from {@link SmsManager#createAppSpecificSmsToken} is delivered
+     * to the app.
+     */
+    public void testAppSpecificSmsToken() {
+        PackageManager packageManager = mContext.getPackageManager();
+        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+
+        AppSpecificSmsReceiver receiver = new AppSpecificSmsReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(TELEPHONY_SMS_RECEIVED);
+        filter.addAction(MESSAGE_SENT_ACTION);
+        filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
+        filter.addAction(APP_SPECIFIC_SMS_RECEIVED_ACTION);
+        getContext().registerReceiver(receiver, filter);
+
+        PendingIntent receivedIntent = PendingIntent.getBroadcast(getContext(), 0,
+                new Intent(APP_SPECIFIC_SMS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
+
+        String token = SmsManager.getDefault().createAppSpecificSmsToken(receivedIntent);
+        String message = "test message, token=" + token;
+        sendSMSToSelf(message);
+        synchronized(receiver) {
+            try {
+                receiver.wait(WAIT_TIME);
+            } catch (InterruptedException e) {
+                Log.w(LOG_TAG, "wait for sms interrupted");
+            }
+        }
+
+        assertTrue("[RERUN] Sms not sent successfully. Check signal.",
+                receiver.isMessageSent());
+        assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
+        assertTrue("App specific SMS intent not triggered", receiver.isAppSpecificSmsReceived());
+    }
+
+    private void sendSMSToSelf(String message) {
         PendingIntent sentIntent = PendingIntent.getBroadcast(getContext(), 0,
                 new Intent(MESSAGE_SENT_ACTION), PendingIntent.FLAG_ONE_SHOT);
         PendingIntent deliveryIntent = PendingIntent.getBroadcast(getContext(), 0,
@@ -98,7 +140,7 @@
                 TextUtils.isEmpty(currentNumber));
 
         Log.i(LOG_TAG, String.format("Sending SMS to self: %s", currentNumber));
-        sendSms(currentNumber, "test message", sentIntent, deliveryIntent);
+        sendSms(currentNumber, message, sentIntent, deliveryIntent);
     }
 
     protected void sendSms(String currentNumber, String text, PendingIntent sentIntent,
@@ -180,4 +222,21 @@
             return "unknown";
         }
     }
+
+    public class AppSpecificSmsReceiver extends IllegalSmsReceiver {
+        private boolean mAppSpecificSmsReceived = false;
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (APP_SPECIFIC_SMS_RECEIVED_ACTION.equals(intent.getAction())) {
+                mAppSpecificSmsReceived = true;
+            } else {
+                super.onReceive(context, intent);
+            }
+        }
+
+        public boolean isAppSpecificSmsReceived() {
+            return mAppSpecificSmsReceived;
+        }
+    }
 }
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index e8de02d..d47f06b 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));
         }
 
@@ -197,6 +197,9 @@
                 case "setup": {
                     protectionLevel |= PermissionInfo.PROTECTION_FLAG_SETUP;
                 } break;
+                case "ephemeral": {
+                    protectionLevel |= PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
+                } break;
             }
         }
         return protectionLevel;
diff --git a/tests/tests/permission2/src/android/permission2/cts/PrivappPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/PrivappPermissionsTest.java
new file mode 100644
index 0000000..e1505f7
--- /dev/null
+++ b/tests/tests/permission2/src/android/permission2/cts/PrivappPermissionsTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.permission2.cts;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+/**
+ * Tests enforcement of signature|privileged permission whitelist:
+ * <ul>
+ * <li>Report what is granted into the CTS log
+ * <li>Ensure all priv permissions are exclusively granted to applications declared in
+ * &lt;privapp-permissions&gt;
+ * </ul>
+ */
+public class PrivappPermissionsTest extends AndroidTestCase {
+
+    private static final String TAG = "PrivappPermissionsTest";
+
+    private static final String PLATFORM_PACKAGE_NAME = "android";
+
+    public void testPrivappPermissionsEnforcement() throws Exception {
+        Set<String> platformPrivPermissions = new HashSet<>();
+        PackageManager pm = getContext().getPackageManager();
+        PackageInfo platformPackage = pm.getPackageInfo(PLATFORM_PACKAGE_NAME,
+                PackageManager.GET_PERMISSIONS);
+
+        for (PermissionInfo permission : platformPackage.permissions) {
+            int protectionLevel = permission.protectionLevel;
+            if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) {
+                platformPrivPermissions.add(permission.name);
+            }
+        }
+
+        List<PackageInfo> installedPackages = pm
+                .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
+
+        for (PackageInfo pkg : installedPackages) {
+            Set<String> requestedPrivPermissions = new TreeSet<>();
+            Set<String> grantedPrivPermissions = new TreeSet<>();
+            String[] requestedPermissions = pkg.requestedPermissions;
+            if (!pkg.applicationInfo.isPrivilegedApp()
+                    || PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+                continue;
+            }
+            if (requestedPermissions == null || requestedPermissions.length == 0) {
+                continue;
+            }
+            // Collect 2 sets: requestedPermissions and grantedPrivPermissions
+            for (int i = 0; i < requestedPermissions.length; i++) {
+                String permission = requestedPermissions[i];
+                if (platformPrivPermissions.contains(permission)) {
+                    requestedPrivPermissions.add(permission);
+                    if ((pkg.requestedPermissionsFlags[i]
+                            & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+                        grantedPrivPermissions.add(permission);
+                    }
+                }
+            }
+            // If an app is requesting any privileged permissions, log the details and verify
+            // that granted permissions are whitelisted
+            if (!requestedPrivPermissions.isEmpty()) {
+                Set<String> notGranted = new TreeSet<>(requestedPrivPermissions);
+                notGranted.removeAll(grantedPrivPermissions);
+                Set<String> whitelist = getPrivAppPermissions(pkg.packageName);
+                Log.i(TAG, "Application " + pkg.packageName + ". Requested permissions: "
+                        + requestedPrivPermissions + ". Granted permissions: "
+                        + grantedPrivPermissions + ". Not granted: " + notGranted + " Whitelisted: "
+                        + whitelist);
+
+                Set<String> grantedNotInWhitelist = new TreeSet<>(grantedPrivPermissions);
+                grantedNotInWhitelist.removeAll(whitelist);
+
+                assertTrue("Not whitelisted permissions are granted for package "
+                                + pkg.packageName + ": " + grantedNotInWhitelist,
+                        grantedNotInWhitelist.isEmpty());
+            }
+
+        }
+    }
+
+    private Set<String> getPrivAppPermissions(String packageName) throws IOException {
+        String output = SystemUtil.runShellCommand(
+                InstrumentationRegistry.getInstrumentation(),
+                "cmd package get-privapp-permissions " + packageName).trim();
+        if (output.startsWith("{") && output.endsWith("}")) {
+            String[] split = output.substring(1, output.length() - 1).split("\\s*,\\s*");
+            return new LinkedHashSet<>(Arrays.asList(split));
+        }
+        return Collections.emptySet();
+    }
+
+}
diff --git a/tests/tests/preference/AndroidTest.xml b/tests/tests/preference/AndroidTest.xml
index f9074fe..91e2ebe 100644
--- a/tests/tests/preference/AndroidTest.xml
+++ b/tests/tests/preference/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.preference.cts" />
+        <option name="runtime-hint" value="7m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/preference2/Android.mk b/tests/tests/preference2/Android.mk
index 2fd94a6..40346d4 100644
--- a/tests/tests/preference2/Android.mk
+++ b/tests/tests/preference2/Android.mk
@@ -25,7 +25,9 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    mockito-target-minus-junit4 \
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceDataStoreTest.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceDataStoreTest.java
new file mode 100644
index 0000000..5c3b181
--- /dev/null
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceDataStoreTest.java
@@ -0,0 +1,384 @@
+/*
+ * 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.preference2.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.AdditionalMatchers.or;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.preference.PreferenceDataStore;
+import android.preference.PreferenceScreen;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+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 java.util.HashSet;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PreferenceDataStoreTest {
+
+    private PreferenceWrapper mPreference;
+    private PreferenceDataStore mDataStore;
+
+    private static final String KEY = "TestPrefKey";
+    private static final String TEST_STR = "Test";
+
+    @Rule
+    public ActivityTestRule<PreferenceFragmentActivity> mActivityRule =
+            new ActivityTestRule<>(PreferenceFragmentActivity.class);
+
+
+    @Before
+    public void setup() {
+        PreferenceFragmentActivity activity = mActivityRule.getActivity();
+        mPreference = new PreferenceWrapper(activity);
+        mPreference.setKey(KEY);
+
+        // Assign the Preference to the PreferenceFragment.
+        PreferenceScreen screen =
+                activity.prefFragment.getPreferenceManager().createPreferenceScreen(activity);
+        screen.addPreference(mPreference);
+
+        mDataStore = mock(PreferenceDataStore.class);
+    }
+
+    @Test
+    public void testPutStringWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putStringTestCommon();
+    }
+
+    @Test
+    public void testPutStringWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putStringTestCommon();
+    }
+
+    @Test
+    public void testGetStringWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        mPreference.getString(TEST_STR);
+        verify(mDataStore, atLeastOnce()).getString(eq(KEY), eq(TEST_STR));
+    }
+
+    @Test
+    public void testGetStringWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        mPreference.getString(TEST_STR);
+        verify(mDataStore, atLeastOnce()).getString(eq(KEY), eq(TEST_STR));
+    }
+
+    @Test
+    public void testPutStringSetWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putStringSetTestCommon();
+    }
+
+    @Test
+    public void testPutStringSetWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putStringSetTestCommon();
+    }
+
+    @Test
+    public void testGetStringSetWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        Set<String> testSet = new HashSet<>();
+        mPreference.getStringSet(testSet);
+        verify(mDataStore, atLeastOnce()).getStringSet(eq(KEY), eq(testSet));
+    }
+
+    @Test
+    public void testGetStringSetWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        Set<String> testSet = new HashSet<>();
+        mPreference.getStringSet(testSet);
+        verify(mDataStore, atLeastOnce()).getStringSet(eq(KEY), eq(testSet));
+    }
+
+    @Test
+    public void testPutIntWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putIntTestCommon();
+    }
+
+    @Test
+    public void testPutIntWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putIntTestCommon();
+    }
+
+    @Test
+    public void testGetIntWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        mPreference.getInt(1);
+        verify(mDataStore, atLeastOnce()).getInt(eq(KEY), eq(1));
+    }
+
+    @Test
+    public void testGetIntWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        mPreference.getInt(1);
+        verify(mDataStore, atLeastOnce()).getInt(eq(KEY), eq(1));
+    }
+
+    @Test
+    public void testPutLongWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putLongTestCommon();
+    }
+
+    @Test
+    public void testPutLongWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putLongTestCommon();
+    }
+
+    @Test
+    public void testGetLongWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        mPreference.getLong(1L);
+        verify(mDataStore, atLeastOnce()).getLong(eq(KEY), eq(1L));
+    }
+
+    @Test
+    public void testGetLongWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        mPreference.getLong(1L);
+        verify(mDataStore, atLeastOnce()).getLong(eq(KEY), eq(1L));
+    }
+
+    @Test
+    public void testPutFloatWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putFloatTestCommon();
+    }
+
+    @Test
+    public void testPutFloatWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putFloatTestCommon();
+    }
+
+    @Test
+    public void testGetFloatWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        mPreference.getFloat(1f);
+        verify(mDataStore, atLeastOnce()).getFloat(eq(KEY), eq(1f));
+    }
+
+    @Test
+    public void testGetFloatWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        mPreference.getFloat(1f);
+        verify(mDataStore, atLeastOnce()).getFloat(eq(KEY), eq(1f));
+    }
+
+    @Test
+    public void testPutBooleanWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        putBooleanTestCommon();
+    }
+
+    @Test
+    public void testPutBooleanWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        putBooleanTestCommon();
+    }
+
+    @Test
+    public void testGetBooleanWithDataStoreOnPref() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        mPreference.getBoolean(true);
+        verify(mDataStore, atLeastOnce()).getBoolean(eq(KEY), eq(true));
+    }
+
+    @Test
+    public void testGetBooleanWithDataStoreOnMgr() {
+        mPreference.getPreferenceManager().setPreferenceDataStore(mDataStore);
+        mPreference.getBoolean(true);
+        verify(mDataStore, atLeastOnce()).getBoolean(eq(KEY), eq(true));
+    }
+
+    @Test
+    public void testDataStoresHierarchy() {
+        mPreference.setPreferenceDataStore(mDataStore);
+        PreferenceDataStore secondaryDataStore = mock(PreferenceDataStore.class);
+        mPreference.getPreferenceManager().setPreferenceDataStore(secondaryDataStore);
+        mPreference.putString(TEST_STR);
+
+        // Check that the Preference returns the correct data store.
+        assertEquals(mDataStore, mPreference.getPreferenceDataStore());
+
+        // Check that the secondary data store assigned to the manager was NOT used.
+        verifyZeroInteractions(secondaryDataStore);
+
+        // Check that the primary data store assigned directly to the preference was used.
+        verify(mDataStore, atLeast(0)).getString(eq(KEY), anyString());
+    }
+
+    private void putStringTestCommon() {
+        mPreference.putString(TEST_STR);
+
+        verify(mDataStore, atLeast(0)).getString(eq(KEY), anyString());
+        verify(mDataStore, atLeastOnce()).putString(eq(KEY), anyString());
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertNull(mPreference.getSharedPreferences().getString(KEY, null));
+    }
+
+    private void putStringSetTestCommon() {
+        Set<String> testSet = new HashSet<>();
+        testSet.add(TEST_STR);
+        mPreference.putStringSet(testSet);
+
+        verify(mDataStore, atLeast(0)).getStringSet(eq(KEY), or(isNull(Set.class), any()));
+        verify(mDataStore, atLeastOnce()).putStringSet(eq(KEY), or(isNull(Set.class), any()));
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertNull(mPreference.getSharedPreferences().getStringSet(KEY, null));
+    }
+
+    private void putIntTestCommon() {
+        mPreference.putInt(1);
+
+        verify(mDataStore, atLeast(0)).getInt(eq(KEY), anyInt());
+        verify(mDataStore, atLeastOnce()).putInt(eq(KEY), anyInt());
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertEquals(-1, mPreference.getSharedPreferences().getInt(KEY, -1));
+    }
+
+    private void putLongTestCommon() {
+        mPreference.putLong(1L);
+
+        verify(mDataStore, atLeast(0)).getLong(eq(KEY), anyLong());
+        verify(mDataStore, atLeastOnce()).putLong(eq(KEY), anyLong());
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertEquals(-1, mPreference.getSharedPreferences().getLong(KEY, -1L));
+    }
+
+    private void putFloatTestCommon() {
+        mPreference.putFloat(1f);
+
+        verify(mDataStore, atLeast(0)).getFloat(eq(KEY), anyFloat());
+        verify(mDataStore, atLeastOnce()).putFloat(eq(KEY), anyFloat());
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertEquals(-1, mPreference.getSharedPreferences().getFloat(KEY, -1f), 0.1f /* epsilon */);
+    }
+
+    private void putBooleanTestCommon() {
+        mPreference.putBoolean(true);
+
+        verify(mDataStore, atLeast(0)).getBoolean(eq(KEY), anyBoolean());
+        verify(mDataStore, atLeastOnce()).putBoolean(eq(KEY), anyBoolean());
+        verifyNoMoreInteractions(mDataStore);
+
+        // Test that the value was NOT propagated to SharedPreferences.
+        assertEquals(false, mPreference.getSharedPreferences().getBoolean(KEY, false));
+    }
+
+    /**
+     * Wrapper to allow to easily call protected methods.
+     */
+    private static class PreferenceWrapper extends Preference {
+
+        PreferenceWrapper(Context context) {
+            super(context);
+        }
+
+        void putString(String value) {
+            persistString(value);
+        }
+
+        String getString(String defaultValue) {
+            return getPersistedString(defaultValue);
+        }
+
+        void putStringSet(Set<String> values) {
+            persistStringSet(values);
+        }
+
+        Set<String> getStringSet(Set<String> defaultValues) {
+            return getPersistedStringSet(defaultValues);
+        }
+
+        void putInt(int value) {
+            persistInt(value);
+        }
+
+        int getInt(int defaultValue) {
+            return getPersistedInt(defaultValue);
+        }
+
+        void putLong(long value) {
+            persistLong(value);
+        }
+
+        long getLong(long defaultValue) {
+            return getPersistedLong(defaultValue);
+        }
+
+        void putFloat(float value) {
+            persistFloat(value);
+        }
+
+        float getFloat(float defaultValue) {
+            return getPersistedFloat(defaultValue);
+        }
+
+        void putBoolean(boolean value) {
+            persistBoolean(value);
+        }
+
+        boolean getBoolean(boolean defaultValue) {
+            return getPersistedBoolean(defaultValue);
+        }
+    }
+
+}
diff --git a/tests/tests/preference2/src/android/preference2/cts/PreferenceFragmentActivity.java b/tests/tests/preference2/src/android/preference2/cts/PreferenceFragmentActivity.java
index 4f12d17..8b7a6d9 100644
--- a/tests/tests/preference2/src/android/preference2/cts/PreferenceFragmentActivity.java
+++ b/tests/tests/preference2/src/android/preference2/cts/PreferenceFragmentActivity.java
@@ -13,12 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- package android.preference2.cts;
+package android.preference2.cts;
 
 import android.app.Activity;
 import android.app.FragmentTransaction;
 import android.os.Bundle;
+import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
 
 /**
  * Demonstration of PreferenceFragment, showing a single fragment in an
@@ -31,14 +33,15 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        prefFragment = new PrefFragment();
 
-        FragmentTransaction transaction = getFragmentManager().beginTransaction()
-                .replace(android.R.id.content, prefFragment, PrefFragment.TAG);
-        transaction.commit();
+        prefFragment = new PrefFragment();
+        getFragmentManager()
+                .beginTransaction()
+                .replace(android.R.id.content, prefFragment, PrefFragment.TAG)
+                .commit();
     }
 
-    public class PrefFragment extends PreferenceFragment {
+    public static class PrefFragment extends PreferenceFragment {
         public static final String TAG = "Pref-1";
 
         public PrefFragment() {
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..405c89e 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-minus-junit4 ctstestrunner ub-uiautomator compatibility-device-util android-support-test
 
 LOCAL_SDK_VERSION := test_current
 
diff --git a/tests/tests/print/AndroidManifest.xml b/tests/tests/print/AndroidManifest.xml
index bd58d3b..c5148c8 100644
--- a/tests/tests/print/AndroidManifest.xml
+++ b/tests/tests/print/AndroidManifest.xml
@@ -62,9 +62,15 @@
         </activity>
 
         <activity
+                android:name="android.print.cts.services.InfoActivity"
+                android:exported="true">
+        </activity>
+
+        <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..73d5285 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -16,6 +16,11 @@
 
 package android.print.cts;
 
+import static android.print.cts.Utils.getPrintManager;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
@@ -24,15 +29,13 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
+import android.app.Instrumentation;
+import android.content.Intent;
 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,26 +43,36 @@
 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.InstrumentationRegistry;
 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 com.android.compatibility.common.util.SystemUtil;
+
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
 import org.mockito.InOrder;
 import org.mockito.stubbing.Answer;
 
@@ -69,27 +82,40 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 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.
  */
-public abstract class BasePrintTest extends InstrumentationTestCase {
+abstract class BasePrintTest {
     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 float sWindowAnimationScaleBefore;
+    private static float sTransitionAnimationScaleBefore;
+    private static float sAnimatiorDurationScaleBefore;
 
     private static PrintDocumentActivity sActivity;
-    private UiDevice mUiDevice;
+    private static Instrumentation sInstrumentation;
+    private static UiDevice sUiDevice;
+
+    public final @Rule ShouldStartActivity mShouldStartActivityRule = new ShouldStartActivity();
 
     /**
      * Return the UI device
@@ -97,11 +123,9 @@
      * @return the UI device
      */
     public UiDevice getUiDevice() {
-        return mUiDevice;
+        return sUiDevice;
     }
 
-    private LocaleList mOldLocale;
-
     private CallCounter mCancelOperationCounter;
     private CallCounter mLayoutCallCounter;
     private CallCounter mWriteCallCounter;
@@ -112,12 +136,12 @@
     private static CallCounter sDestroyActivityCallCounter = new CallCounter();
     private static CallCounter sCreateActivityCallCounter = new CallCounter();
 
-    private String[] mEnabledImes;
+    private static String[] sEnabledImes;
 
-    private String[] getEnabledImes() throws IOException {
+    private static String[] getEnabledImes() throws IOException {
         List<String> imeList = new ArrayList<>();
 
-        ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+        ParcelFileDescriptor pfd = sInstrumentation.getUiAutomation()
                 .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
         try (BufferedReader reader = new BufferedReader(
                 new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
@@ -134,40 +158,35 @@
         return imeArray;
     }
 
-    private void disableImes() throws Exception {
-        mEnabledImes = getEnabledImes();
-        for (String ime : mEnabledImes) {
+    private static void disableImes() throws Exception {
+        sEnabledImes = getEnabledImes();
+        for (String ime : sEnabledImes) {
             String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime;
-            SystemUtil.runShellCommand(getInstrumentation(), disableImeCommand);
+            SystemUtil.runShellCommand(sInstrumentation, disableImeCommand);
         }
     }
 
-    private void enableImes() throws Exception {
-        for (String ime : mEnabledImes) {
+    private static void enableImes() throws Exception {
+        for (String ime : sEnabledImes) {
             String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime;
-            SystemUtil.runShellCommand(getInstrumentation(), enableImeCommand);
+            SystemUtil.runShellCommand(sInstrumentation, enableImeCommand);
         }
-        mEnabledImes = null;
+        sEnabledImes = null;
     }
 
-    @Override
-    protected void runTest() throws Throwable {
-        // Do nothing if the device does not support printing.
-        if (supportsPrinting()) {
-            super.runTest();
-        }
+    protected static Instrumentation getInstrumentation() {
+        return sInstrumentation;
     }
 
-    @Override
-    public void setUp() throws Exception {
-        Log.d(LOG_TAG, "setUp()");
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        Log.d(LOG_TAG, "setUpClass()");
 
-        super.setUp();
-        if (!supportsPrinting()) {
-            return;
-        }
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_PRINTING));
 
-        mUiDevice = UiDevice.getInstance(getInstrumentation());
+        sUiDevice = UiDevice.getInstance(sInstrumentation);
 
         // Make sure we start with a clean slate.
         Log.d(LOG_TAG, "clearPrintSpoolerData()");
@@ -177,20 +196,47 @@
 
         // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
         // Dexmaker is used by mockito.
-        System.setProperty("dexmaker.dexcache", getInstrumentation()
+        System.setProperty("dexmaker.dexcache", sInstrumentation
                 .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);
+        Log.d(LOG_TAG, "disable animations");
+        try {
+            sWindowAnimationScaleBefore = Float.parseFloat(SystemUtil.runShellCommand(
+                    sInstrumentation, "settings get global window_animation_scale"));
+
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global window_animation_scale 0");
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, "Could not read window_animation_scale", e);
+            sWindowAnimationScaleBefore = Float.NaN;
         }
+        try {
+            sTransitionAnimationScaleBefore = Float.parseFloat(SystemUtil.runShellCommand(
+                    sInstrumentation, "settings get global transition_animation_scale"));
+
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global transition_animation_scale 0");
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, "Could not read transition_animation_scale", e);
+            sTransitionAnimationScaleBefore = Float.NaN;
+        }
+        try {
+            sAnimatiorDurationScaleBefore = Float.parseFloat(SystemUtil.runShellCommand(
+                    sInstrumentation, "settings get global animator_duration_scale"));
+
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global animator_duration_scale 0");
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, "Could not read animator_duration_scale", e);
+            sAnimatiorDurationScaleBefore = Float.NaN;
+        }
+
+        Log.d(LOG_TAG, "setUpClass() done");
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Log.d(LOG_TAG, "setUp()");
 
         // Initialize the latches.
         Log.d(LOG_TAG, "init counters");
@@ -203,73 +249,95 @@
         mCreateSessionCallCounter = new CallCounter();
         mDestroySessionCallCounter = new CallCounter();
 
-        // Create the activity for the right locale.
-        Log.d(LOG_TAG, "createActivity()");
-        createActivity();
+        // Create the activity if needed
+        if (!mShouldStartActivityRule.noActivity) {
+            createActivity();
+        }
+
         Log.d(LOG_TAG, "setUp() done");
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         Log.d(LOG_TAG, "tearDown()");
 
-        if (!supportsPrinting()) {
-            return;
+        // Done with the activity.
+        if (getActivity() != null) {
+            Log.d(LOG_TAG, "finish activity");
+            if (!getActivity().isFinishing()) {
+                getActivity().finish();
+            }
+
+            sActivity = null;
         }
 
-        // Done with the activity.
-        Log.d(LOG_TAG, "finish activity");
-        if (!getActivity().isFinishing()) {
-            getActivity().finish();
-        }
+        Log.d(LOG_TAG, "tearDown() done");
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+        Log.d(LOG_TAG, "tearDownClass()");
 
         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();
 
-        super.tearDown();
-        Log.d(LOG_TAG, "tearDown() done");
+        Log.d(LOG_TAG, "enable animations");
+        if (sWindowAnimationScaleBefore != Float.NaN) {
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global window_animation_scale " + sWindowAnimationScaleBefore);
+        }
+        if (sTransitionAnimationScaleBefore != Float.NaN) {
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global transition_animation_scale " +
+                            sTransitionAnimationScaleBefore);
+        }
+        if (sAnimatiorDurationScaleBefore != Float.NaN) {
+            SystemUtil.runShellCommand(sInstrumentation,
+                    "settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
+        }
+
+        Log.d(LOG_TAG, "tearDownClass() done");
     }
 
     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.
+        sInstrumentation
+                .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 +345,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 +361,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 +423,7 @@
      *
      * @return The number of onDestroy calls on the print activity.
      */
-    protected static int getActivityDestroyCallbackCallCount() {
+    static int getActivityDestroyCallbackCallCount() {
         return sDestroyActivityCallCounter.getCallCount();
     }
 
@@ -364,7 +432,7 @@
      *
      * @return The number of onCreate calls on the print activity.
      */
-    protected static int getActivityCreateCallbackCallCount() {
+    private static int getActivityCreateCallbackCallCount() {
         return sCreateActivityCallCounter.getCallCount();
     }
 
@@ -381,7 +449,7 @@
     /**
      * Reset all counters.
      */
-    protected void resetCounters() {
+    void resetCounters() {
         mCancelOperationCounter.reset();
         mLayoutCallCounter.reset();
         mWriteCallCounter.reset();
@@ -393,15 +461,16 @@
         sCreateActivityCallCounter.reset();
     }
 
-    protected void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
+    void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
         try {
-            long delay = 100;
+            long delay = 1;
             while (true) {
                 try {
-                    UiObject destinationSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+                    UiObject destinationSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                             "com.android.printspooler:id/destination_spinner"));
 
                     destinationSpinner.click();
+                    getUiDevice().waitForIdle();
 
                     // Give spinner some time to expand
                     try {
@@ -411,25 +480,31 @@
                     }
 
                     // try to select printer
-                    UiObject printerOption = mUiDevice
+                    UiObject printerOption = sUiDevice
                             .findObject(new UiSelector().text(printerName));
                     printerOption.click();
                 } catch (UiObjectNotFoundException e) {
                     Log.e(LOG_TAG, "Could not select printer " + printerName, e);
                 }
 
-                // Make sure printer is selected
-                if (getUiDevice().hasObject(By.text(printerName))) {
-                    break;
-                } else {
-                    if (delay <= OPERATION_TIMEOUT_MILLIS) {
-                        Log.w(LOG_TAG, "Cannot find printer " + printerName + ", retrying.");
-                        delay *= 2;
-                        continue;
+                getUiDevice().waitForIdle();
+
+                if (!printerName.equals("All printers…")) {
+                    // Make sure printer is selected
+                    if (getUiDevice().hasObject(By.text(printerName))) {
+                        break;
                     } else {
-                        throw new UiObjectNotFoundException("Could find printer " + printerName +
-                                " even though we retried");
+                        if (delay <= OPERATION_TIMEOUT_MILLIS) {
+                            Log.w(LOG_TAG, "Cannot find printer " + printerName + ", retrying.");
+                            delay *= 2;
+                        } else {
+                            throw new UiObjectNotFoundException(
+                                    "Could find printer " + printerName +
+                                            " even though we retried");
+                        }
                     }
+                } else {
+                    break;
                 }
             }
         } catch (UiObjectNotFoundException e) {
@@ -438,24 +513,22 @@
         }
     }
 
-    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 = sUiDevice.findObject(new UiSelector().resourceId("android:id/button1"));
         } else {
-            button = uiDevice.findObject(new UiSelector().resourceId("android:id/button2"));
+            button = sUiDevice.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(
+            UiObject orientationSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/orientation_spinner"));
             orientationSpinner.click();
-            UiObject orientationOption = mUiDevice.findObject(new UiSelector().text(orientation));
+            UiObject orientationOption = sUiDevice.findObject(new UiSelector().text(orientation));
             orientationOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -465,7 +538,7 @@
 
     protected String getOrientation() throws UiObjectNotFoundException, IOException {
         try {
-            UiObject orientationSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject orientationSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/orientation_spinner"));
             return orientationSpinner.getText();
         } catch (UiObjectNotFoundException e) {
@@ -474,12 +547,12 @@
         }
     }
 
-    protected void changeMediaSize(String mediaSize) throws UiObjectNotFoundException, IOException {
+    void changeMediaSize(String mediaSize) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject mediaSizeSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject mediaSizeSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/paper_size_spinner"));
             mediaSizeSpinner.click();
-            UiObject mediaSizeOption = mUiDevice.findObject(new UiSelector().text(mediaSize));
+            UiObject mediaSizeOption = sUiDevice.findObject(new UiSelector().text(mediaSize));
             mediaSizeOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -487,23 +560,12 @@
         }
     }
 
-    protected String getMediaSize() throws UiObjectNotFoundException, IOException {
+    void changeColor(String color) 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 {
-        try {
-            UiObject colorSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject colorSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/color_spinner"));
             colorSpinner.click();
-            UiObject colorOption = mUiDevice.findObject(new UiSelector().text(color));
+            UiObject colorOption = sUiDevice.findObject(new UiSelector().text(color));
             colorOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -513,7 +575,7 @@
 
     protected String getColor() throws UiObjectNotFoundException, IOException {
         try {
-            UiObject colorSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject colorSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/color_spinner"));
             return colorSpinner.getText();
         } catch (UiObjectNotFoundException e) {
@@ -522,12 +584,12 @@
         }
     }
 
-    protected void changeDuplex(String duplex) throws UiObjectNotFoundException, IOException {
+    void changeDuplex(String duplex) throws UiObjectNotFoundException, IOException {
         try {
-            UiObject duplexSpinner = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject duplexSpinner = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/duplex_spinner"));
             duplexSpinner.click();
-            UiObject duplexOption = mUiDevice.findObject(new UiSelector().text(duplex));
+            UiObject duplexOption = sUiDevice.findObject(new UiSelector().text(duplex));
             duplexOption.click();
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
@@ -535,11 +597,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 = sUiDevice.findObject(new UiSelector().resourceId(
+                    "com.android.printspooler:id/copies_edittext"));
+            copies.setText(Integer.valueOf(newCopies).toString());
         } catch (UiObjectNotFoundException e) {
             dumpWindowHierarchy();
             throw e;
@@ -548,7 +610,7 @@
 
     protected String getCopies() throws UiObjectNotFoundException, IOException {
         try {
-            UiObject copies = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject copies = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/copies_edittext"));
             return copies.getText();
         } catch (UiObjectNotFoundException e) {
@@ -557,9 +619,9 @@
         }
     }
 
-    protected void clickPrintButton() throws UiObjectNotFoundException, IOException {
+    void clickPrintButton() throws UiObjectNotFoundException, IOException {
         try {
-            UiObject printButton = mUiDevice.findObject(new UiSelector().resourceId(
+            UiObject printButton = sUiDevice.findObject(new UiSelector().resourceId(
                     "com.android.printspooler:id/print_button"));
             printButton.click();
         } catch (UiObjectNotFoundException e) {
@@ -568,9 +630,20 @@
         }
     }
 
-    protected void dumpWindowHierarchy() throws IOException {
+    void clickRetryButton() throws UiObjectNotFoundException, IOException {
+        try {
+            UiObject retryButton = sUiDevice.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);
+        sUiDevice.dumpWindowHierarchy(os);
 
         Log.w(LOG_TAG, "Window hierarchy:");
         for (String line : os.toString("UTF-8").split("\n")) {
@@ -583,34 +656,39 @@
     }
 
     protected void createActivity() {
+        Log.d(LOG_TAG, "createActivity()");
+
         int createBefore = getActivityCreateCallbackCallCount();
 
-        launchActivity(getInstrumentation().getTargetContext().getPackageName(),
-                PrintDocumentActivity.class, null);
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(sInstrumentation.getTargetContext().getPackageName(),
+                PrintDocumentActivity.class.getName());
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        sInstrumentation.startActivitySync(intent);
 
         waitForActivityCreateCallbackCalled(createBefore + 1);
     }
 
-    protected void openPrintOptions() throws UiObjectNotFoundException {
-        UiObject expandHandle = mUiDevice.findObject(new UiSelector().resourceId(
+    void openPrintOptions() throws UiObjectNotFoundException {
+        UiObject expandHandle = sUiDevice.findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/expand_collapse_handle"));
         expandHandle.click();
     }
 
-    protected void openCustomPrintOptions() throws UiObjectNotFoundException {
-        UiObject expandHandle = mUiDevice.findObject(new UiSelector().resourceId(
+    void openCustomPrintOptions() throws UiObjectNotFoundException {
+        UiObject expandHandle = sUiDevice.findObject(new UiSelector().resourceId(
                 "com.android.printspooler:id/more_options_button"));
         expandHandle.click();
     }
 
-    protected void clearPrintSpoolerData() throws Exception {
+    static void clearPrintSpoolerData() throws Exception {
         assertTrue("failed to clear print spooler data",
-                SystemUtil.runShellCommand(getInstrumentation(), String.format(
+                SystemUtil.runShellCommand(sInstrumentation, 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 +708,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,8 +728,51 @@
         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(
+    protected static PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
             Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
             Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
             Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
@@ -697,7 +818,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 +846,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 +879,7 @@
             }
         }
 
-        public int getCallCount() {
+        int getCallCount() {
             synchronized (mLock) {
                 return mCallCount;
             }
@@ -779,7 +918,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");
@@ -799,12 +938,104 @@
         Log.d(LOG_TAG, "getActivity().finish()");
         getActivity().finish();
 
-        Log.d(LOG_TAG, "createActivity");
         createActivity();
     }
 
-    protected boolean supportsPrinting() {
-        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);
+        }
+    }
+
+    /**
+     * Annotation used to signal that a test does not need an activity.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    @interface NoActivity { }
+
+    /**
+     * Rule that handles the {@link NoActivity} annotation.
+     */
+    private static class ShouldStartActivity implements TestRule {
+        boolean noActivity;
+
+        @Override
+        public Statement apply(Statement base, org.junit.runner.Description description) {
+            for (Annotation annotation : description.getAnnotations()) {
+                if (annotation instanceof NoActivity) {
+                    noActivity = true;
+                    break;
+                }
+            }
+
+            return base;
+        }
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/ClassParametersTest.java b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
index bad47f8..e0c41ea 100644
--- a/tests/tests/print/src/android/print/cts/ClassParametersTest.java
+++ b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
@@ -24,39 +24,22 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import static android.print.cts.Utils.*;
+import static org.junit.Assert.*;
+
 /**
- * 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 illegalPrintAttributesColorMode() throws Throwable {
         assertException(() -> (new PrintAttributes.Builder()).setColorMode(-1),
                 IllegalArgumentException.class);
         assertException(() -> (new PrintAttributes.Builder()).setColorMode(0),
@@ -64,7 +47,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 illegalPrintAttributesDuplexMode() throws Throwable {
         assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(-1),
                 IllegalArgumentException.class);
         assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(0),
@@ -72,7 +63,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 illegalPrintAttributesResolution() throws Throwable {
         assertException(() -> new Resolution(null, "label", 10, 10),
                 IllegalArgumentException.class);
         assertException(() -> new Resolution("", "label", 10, 10),
@@ -89,7 +88,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 legalPrintAttributesResolution() 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 illegalPrintAttributesMediaSize() throws Throwable {
         assertException(() -> new MediaSize(null, "label", 10, 10),
                 IllegalArgumentException.class);
         assertException(() -> new MediaSize("", "label", 10, 10),
@@ -106,8 +143,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 legalPrintAttributesMediaSize() 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 +226,7 @@
      * @throws Exception If anything is unexpected
      */
     @Test
-    public void testIllegalPrintDocumentInfo() throws Exception {
+    public void illegalPrintDocumentInfo() throws Throwable {
         assertException(() -> new PrintDocumentInfo.Builder(null),
                 IllegalArgumentException.class);
         assertException(() -> new PrintDocumentInfo.Builder(""),
@@ -124,8 +234,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 legalPrintDocumentInfo() 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..eb9806e 100644
--- a/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java
+++ b/tests/tests/print/src/android/print/cts/CustomPrintOptionsTest.java
@@ -36,11 +36,16 @@
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
 import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.util.Log;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -49,9 +54,12 @@
 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.
  */
+@RunWith(AndroidJUnit4.class)
 public class CustomPrintOptionsTest extends BasePrintTest {
     private final static String LOG_TAG = "CustomPrintOptionsTest";
     private static final String PRINTER_NAME = "Test printer";
@@ -79,6 +87,10 @@
             new Resolution("600x600", "600x600", 600, 600)
     };
 
+    private PrintAttributes mLayoutAttributes;
+    private PrintDocumentAdapter mAdapter;
+    private static boolean sHasDefaultPrinterSet;
+
     /**
      * Get the page ranges currently selected as described in the UI.
      *
@@ -87,7 +99,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];
         }
 
@@ -110,30 +123,8 @@
         }
     }
 
-    /**
-     * Test that we can switch to a specific set of settings via the custom print options activity
-     *
-     * @param copyFromOriginal If the print job info should be copied from the original
-     * @param numCopies        The copies to print
-     * @param pages            The page ranges to print
-     * @param mediaSize        The media size to use
-     * @param isPortrait       If the mediaSize is portrait
-     * @param colorMode        The color mode to use
-     * @param duplexMode       The duplex mode to use
-     * @param resolution       The resolution to use
-     *
-     * @throws Exception If anything is unexpected
-     */
-    private void testCase(final boolean copyFromOriginal, final Integer numCopies,
-            final PageRange[] pages, final MediaSize mediaSize, final boolean isPortrait,
-            final Integer colorMode, final Integer duplexMode, final Resolution resolution)
-            throws Throwable {
-        if (!supportsPrinting()) {
-            return;
-        }
-
-        final PrintAttributes[] layoutAttributes = new PrintAttributes[1];
-
+    @Before
+    public void setUpServicesAndAdapter() {
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
                 createMockPrinterDiscoverySessionCallbacks(invocation -> {
                     StubbablePrinterDiscoverySession session =
@@ -164,7 +155,7 @@
                     return null;
                 });
 
-        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+        mAdapter = createMockPrintDocumentAdapter(
                 invocation -> {
                     LayoutResultCallback callback = (LayoutResultCallback) invocation
                             .getArguments()[3];
@@ -174,7 +165,7 @@
                             .build();
 
                     synchronized (CustomPrintOptionsTest.this) {
-                        layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                        mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
 
                         CustomPrintOptionsTest.this.notifyAll();
                     }
@@ -189,7 +180,7 @@
 
                     PageRange[] writtenPages = (PageRange[]) args[0];
 
-                    writeBlankPages(layoutAttributes[0], fd, writtenPages[0].getStart(),
+                    writeBlankPages(mLayoutAttributes, fd, writtenPages[0].getStart(),
                             writtenPages[0].getEnd());
                     fd.close();
 
@@ -208,6 +199,51 @@
         FirstPrintService.setCallbacks(firstServiceCallbacks);
         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
+        // Set default printer
+        if (!sHasDefaultPrinterSet) {
+            // This is the first print test that runs. If this is run after other tests these other
+            // test can still cause memory pressure and make the printactivity to go through a
+            // destroy-create cycle. In this case we have to retry to operation.
+            int tries = 0;
+            while (true) {
+                try {
+                    resetCounters();
+                    makeDefaultPrinter(mAdapter, PRINTER_NAME);
+                    break;
+                } catch (Throwable e) {
+                    if (getActivityDestroyCallbackCallCount() > 0 && tries < MAX_TRIES) {
+                        Log.e(LOG_TAG, "Activity was destroyed during test, retrying", e);
+
+                        tries++;
+                        continue;
+                    }
+
+                    throw new RuntimeException(e);
+                }
+            }
+
+            sHasDefaultPrinterSet = true;
+        }
+    }
+
+    /**
+     * Test that we can switch to a specific set of settings via the custom print options activity
+     *
+     * @param copyFromOriginal If the print job info should be copied from the original
+     * @param numCopies        The copies to print
+     * @param pages            The page ranges to print
+     * @param mediaSize        The media size to use
+     * @param isPortrait       If the mediaSize is portrait
+     * @param colorMode        The color mode to use
+     * @param duplexMode       The duplex mode to use
+     * @param resolution       The resolution to use
+     *
+     * @throws Exception If anything is unexpected
+     */
+    private void testCase(final boolean copyFromOriginal, final Integer numCopies,
+            final PageRange[] pages, final MediaSize mediaSize, final boolean isPortrait,
+            final Integer colorMode, final Integer duplexMode, final Resolution resolution)
+            throws Throwable {
         final PrintAttributes.Builder additionalAttributesBuilder = new PrintAttributes.Builder();
         final PrintAttributes.Builder newAttributesBuilder = new PrintAttributes.Builder();
 
@@ -272,28 +308,6 @@
                     return printJobBuilder.build();
                 });
 
-        // This is the first print test that runs. If this is run after other tests these other test
-        // can still cause memory pressure and make the printactivity to go through a destroy-create
-        // cycle. In this case we have to retry to operation.
-        int tries = 0;
-        while (true) {
-            try {
-                clearPrintSpoolerData();
-                resetCounters();
-                makeDefaultPrinter(adapter, PRINTER_NAME);
-                break;
-            } catch (Throwable e) {
-                if (getActivityDestroyCallbackCallCount() > 0 && tries < MAX_TRIES) {
-                    Log.e(LOG_TAG, "Activity was destroyed during test, retrying", e);
-
-                    tries++;
-                    continue;
-                }
-
-                throw e;
-            }
-        }
-
         // Check that the attributes were send to the print service
         PrintAttributes newAttributes = newAttributesBuilder.build();
         Log.i(LOG_TAG, "Change to attributes: " + newAttributes + ", copies: " + numCopies +
@@ -302,12 +316,13 @@
         // This is the first print test that runs. If this is run after other tests these other test
         // can still cause memory pressure and make the printactivity to go through a destroy-create
         // cycle. In this case we have to retry to operation.
+        int tries = 0;
         while (true) {
             try {
                 resetCounters();
 
                 // Start printing
-                print(adapter);
+                print(mAdapter);
 
                 // Wait for write.
                 waitForWriteAdapterCallback(1);
@@ -322,15 +337,15 @@
                 Log.d(LOG_TAG, "Check attributes");
                 long endTime = System.currentTimeMillis() + OPERATION_TIMEOUT_MILLIS;
                 synchronized (this) {
-                    while (layoutAttributes[0] == null ||
-                            !layoutAttributes[0].equals(newAttributes)) {
+                    while (mLayoutAttributes == null ||
+                            !mLayoutAttributes.equals(newAttributes)) {
                         wait(Math.max(1, endTime - System.currentTimeMillis()));
 
                         if (endTime < System.currentTimeMillis()) {
                             throw new TimeoutException(
                                     "Print attributes did not change to " + newAttributes + " in " +
                                             OPERATION_TIMEOUT_MILLIS + " ms. Current attributes"
-                                            + layoutAttributes[0]);
+                                            + mLayoutAttributes);
                         }
                     }
                 }
@@ -344,25 +359,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,53 +382,70 @@
         }
 
         // 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],
+    @Test
+    public void changeToChangeEveryThingButPages() throws Throwable {
+        testCase(false, 2, null, MEDIA_SIZES[1], false, COLOR_MODES[1], DUPLEX_MODES[1],
                 RESOLUTIONS[1]);
     }
 
-    public void testChangeToAttributes() throws Throwable {
+    @Test
+    public void changeToAttributes() throws Throwable {
         testCase(false, null, null, MEDIA_SIZES[1], false, COLOR_MODES[1], DUPLEX_MODES[1],
                 RESOLUTIONS[1]);
     }
 
-    public void testChangeToNonAttributes() throws Throwable {
+    @Test
+    public void changeToNonAttributes() throws Throwable {
         testCase(false, 2, PAGESS[1], null, true, null, null, null);
     }
 
-    public void testChangeToAttributesNoCopy() throws Throwable {
+    @Test
+    public void changeToAttributesNoCopy() throws Throwable {
         testCase(true, null, null, MEDIA_SIZES[1], false, COLOR_MODES[1], DUPLEX_MODES[1],
                 RESOLUTIONS[1]);
     }
 
-    public void testChangeToNonAttributesNoCopy() throws Throwable {
+    @Test
+    public void changeToNonAttributesNoCopy() throws Throwable {
         testCase(true, 2, PAGESS[1], null, true, null, null, null);
     }
 
-    public void testChangeToDefault() throws Throwable {
+    @Test
+    public void changeToDefault() throws Throwable {
         testCase(false, 1, DEFAULT_PAGES, DEFAULT_MEDIA_SIZE, DEFAULT_MEDIA_SIZE.isPortrait(),
                 DEFAULT_COLOR_MODE, DEFAULT_DUPLEX_MODE, DEFAULT_RESOLUTION);
     }
 
-    public void testChangeToDefaultNoCopy() throws Throwable {
+    @Test
+    public void changeToDefaultNoCopy() throws Throwable {
         testCase(true, 1, DEFAULT_PAGES, DEFAULT_MEDIA_SIZE, DEFAULT_MEDIA_SIZE.isPortrait(),
                 DEFAULT_COLOR_MODE, DEFAULT_DUPLEX_MODE, DEFAULT_RESOLUTION);
     }
 
-    public void testChangeToNothing() throws Throwable {
+    @Test
+    public void changeToNothing() throws Throwable {
         testCase(false, null, null, null, true, null, null, null);
     }
 
+    @Test
     public void testChangeToNothingNoCopy() throws Throwable {
         testCase(true, null, null, null, true, null, null, null);
     }
 
-    public void testChangeToAllPages() throws Throwable {
+    @Test
+    public void changeToAllPages() throws Throwable {
         testCase(false, null, PAGESS[2], null, true, null, null, null);
     }
+
+    @Test
+    public void changeToSomePages() 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..37eab57
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/InterfaceForAppsTest.java
@@ -0,0 +1,387 @@
+/*
+ * 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.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+import static android.print.cts.Utils.*;
+import static org.junit.Assert.*;
+
+/**
+ * Test interface from the application to the print service.
+ */
+@RunWith(AndroidJUnit4.class)
+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);
+    private static boolean sHasBeenSetUp;
+
+    /**
+     * 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);
+    }
+
+    @Before
+    public void setPrinter() throws Exception {
+        if (!sHasBeenSetUp) {
+            resetCounters();
+            PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_COMPLETED);
+            makeDefaultPrinter(adapter, TEST_PRINTER);
+
+            sHasBeenSetUp = true;
+        }
+
+        resetCounters();
+    }
+
+    /**
+     * 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);
+        clickPrintButton();
+
+        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);
+    }
+
+    @Test
+    public void attemptCancelCreatedPrintJob() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_STARTED);
+
+        print(adapter, "testAttemptCancelCreatedPrintJob");
+        waitForWriteAdapterCallback(1);
+
+        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);
+    }
+
+    @Test
+    public void cancelStartedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_STARTED, "testCancelStartedPrintJob");
+    }
+
+    @Test
+    public void cancelBlockedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_BLOCKED, "testCancelBlockedPrintJob");
+    }
+
+    @Test
+    public void cancelFailedPrintJob() throws Throwable {
+        cancelPrintJobBaseTest(PrintJobInfo.STATE_FAILED, "testCancelFailedPrintJob");
+    }
+
+    @Test
+    public void restartFailedPrintJob() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_FAILED);
+
+        print(adapter, "testRestartFailedPrintJob");
+        waitForWriteAdapterCallback(1);
+        clickPrintButton();
+
+        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);
+    }
+
+    @Test
+    public void getTwoPrintJobStates() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_BLOCKED);
+
+        print(adapter, "testGetTwoPrintJobStates-block");
+        waitForWriteAdapterCallback(1);
+        clickPrintButton();
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        PrintJob job1 = getPrintJob(getPrintManager(getActivity()),
+                "testGetTwoPrintJobStates-block");
+        eventually(() -> assertTrue(job1.isBlocked()));
+
+        adapter = setupPrint(PrintJobInfo.STATE_COMPLETED);
+        print(adapter, "testGetTwoPrintJobStates-complete");
+        waitForWriteAdapterCallback(2);
+        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);
+    }
+
+    @Test
+    public void changedPrintJobInfo() throws Throwable {
+        PrintDocumentAdapter adapter = setupPrint(PrintJobInfo.STATE_COMPLETED);
+
+        long beforeStart = System.currentTimeMillis();
+        print(adapter, "testPrintJobInfo");
+        waitForWriteAdapterCallback(1);
+        long afterStart = System.currentTimeMillis();
+
+        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();
+        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..0364624 100644
--- a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -16,6 +16,7 @@
 
 package android.print.cts;
 
+import static org.junit.Assert.*;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
@@ -41,13 +42,12 @@
 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 android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.InOrder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -57,81 +57,61 @@
  * page ranges to be printed depending whether the app gave
  * the requested pages, more pages, etc.
  */
+@RunWith(AndroidJUnit4.class)
 public class PageRangeAdjustmentTest extends BasePrintTest {
 
     private static final int MAX_PREVIEW_PAGES_BATCH = 50;
     private static final int PAGE_COUNT = 60;
     private static final String FIRST_PRINTER = "First printer";
 
-    public void testAllPagesWantedAndAllPagesWritten() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
+    private static boolean sIsDefaultPrinterSet;
 
+    @Before
+    public void setDefaultPrinter() throws Exception {
+        if (!sIsDefaultPrinterSet) {
+            // Create a callback for the target print service.
+            PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                    invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
+                    invocation -> {
+                        PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                        printJob.complete();
+                        return null;
+                    }, null);
+
+            // Configure the print services.
+            FirstPrintService.setCallbacks(firstServiceCallbacks);
+            SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+            // Create a mock print adapter.
+            final PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(PAGE_COUNT);
+
+            makeDefaultPrinter(adapter, FIRST_PRINTER);
+            resetCounters();
+
+            sIsDefaultPrinterSet = true;
+        }
+    }
+
+    @Test
+    public void allPagesWantedAndAllPagesWritten() throws Exception {
         // 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);
@@ -139,18 +119,9 @@
         // Wait for write.
         waitForWriteAdapterCallback(1);
 
-        // Select the first printer.
-        selectPrinter(FIRST_PRINTER);
-
-        // Wait for layout as the printer has different capabilities.
-        waitForLayoutAdapterCallbackCount(2);
-
         // Click the print button.
         clickPrintButton();
 
-        // Answer the dialog for the print service cloud warning
-        answerPrintServicesWarning(true);
-
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -169,32 +140,21 @@
                 any(PrintJob.class));
     }
 
-    public void testSomePagesWantedAndAllPagesWritten() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
+    @Test
+    public void somePagesWantedAndAllPagesWritten() throws Exception {
         // 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 +164,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);
@@ -251,21 +202,12 @@
         // Open the print options.
         openPrintOptions();
 
-        // Select the first printer.
-        selectPrinter(FIRST_PRINTER);
-
-        // Wait for layout as the printer has different capabilities.
-        waitForLayoutAdapterCallbackCount(2);
-
         // Select only the second page.
-        selectPages("2");
+        selectPages("2", PAGE_COUNT);
 
         // Click the print button.
         clickPrintButton();
 
-        // Answer the dialog for the print service cloud warning
-        answerPrintServicesWarning(true);
-
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -284,37 +226,26 @@
                 any(PrintJob.class));
     }
 
-    public void testSomePagesWantedAndSomeMorePagesWritten() throws Exception {
+    @Test
+    public void somePagesWantedAndSomeMorePagesWritten() throws Exception {
         final int REQUESTED_PAGE = 55;
 
-        if (!supportsPrinting()) {
-            return;
-        }
-
         // 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 +255,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);
@@ -385,21 +307,12 @@
         // Open the print options.
         openPrintOptions();
 
-        // Select the first printer.
-        selectPrinter(FIRST_PRINTER);
-
-        // Wait for layout as the printer has different capabilities.
-        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();
 
-        // Answer the dialog for the print service cloud warning
-        answerPrintServicesWarning(true);
-
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -418,19 +331,11 @@
                 any(PrintJob.class));
     }
 
-    public void testSomePagesWantedAndNotWritten() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
+    @Test
+    public void somePagesWantedAndNotWritten() throws Exception {
         // 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 +346,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);
@@ -510,35 +406,24 @@
                 any(PrintJob.class));
     }
 
-    public void testWantedPagesAlreadyWrittenForPreview() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
+    @Test
+    public void wantedPagesAlreadyWrittenForPreview() throws Exception {
         // 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 +433,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);
@@ -600,21 +476,12 @@
         // Open the print options.
         openPrintOptions();
 
-        // Select the first printer.
-        selectPrinter(FIRST_PRINTER);
-
-        // Wait for layout as the printer has different capabilities.
-        waitForLayoutAdapterCallbackCount(2);
-
         // Select a page not written for preview.
-        selectPages("3");
+        selectPages("3", PAGE_COUNT);
 
         // Click the print button.
         clickPrintButton();
 
-        // Answer the dialog for the print service cloud warning
-        answerPrintServicesWarning(true);
-
         // Wait for finish.
         waitForAdapterFinishCallbackCalled();
 
@@ -633,58 +500,42 @@
                 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);
             }
-        }, null, null, null, null, null, null);
+
+            return null;
+        }, null, null, null, null, null, invocation -> {
+            onPrinterDiscoverySessionDestroyCalled();
+            return null;
+        });
     }
 
     private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
index 5459c31..e6bc164 100644
--- a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -36,17 +36,22 @@
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
 
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import static org.junit.Assert.*;
+
 /**
  * Test that the print attributes are correctly propagated through the print framework
  */
+@RunWith(AndroidJUnit4.class)
 public class PrintAttributesTest extends BasePrintTest {
     private static final String LOG_TAG = "PrintAttributesTest";
     private final String PRINTER_NAME = "Test printer";
@@ -78,6 +83,7 @@
      * Stores the {@link PrintAttributes} passed to the layout method
      */
     private PrintAttributes mLayoutAttributes;
+    private static boolean sHasBeenSetup;
 
     /**
      * Create a new {@link PrintAttributes} object with the given properties.
@@ -140,73 +146,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 +224,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 +279,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.
@@ -341,6 +319,26 @@
         return false;
     }
 
+    @Before
+    public void setUpServicesAndAdapter() throws Exception {
+        if (!sHasBeenSetup) {
+            // Set up printer with supported and default attributes
+            PrintDocumentAdapter adapter =
+                    setUpPrinter(MIN_MARGINS[0], MEDIA_SIZES, MEDIA_SIZES[0], COLOR_MODES,
+                            COLOR_MODES[0], DUPLEX_MODES, DUPLEX_MODES[0], RESOLUTIONS,
+                            RESOLUTIONS[0]);
+
+            Log.d(LOG_TAG, "makeDefaultPrinter");
+            // Make printer default. This is necessary as a different default printer might pre-select
+            // its default attributes and thereby overrides the defaults of the tested printer.
+            makeDefaultPrinter(adapter, PRINTER_NAME);
+
+            sHasBeenSetup = true;
+        }
+
+        resetCounters();
+    }
+
     /**
      * Flexible base test for all print attribute tests.
      *
@@ -368,20 +366,10 @@
             int defaultColorMode, int suggestedColorMode, int duplexModes[],
             int defaultDuplexMode, int suggestedDuplexMode, Resolution resolutions[],
             Resolution defaultResolution, Resolution suggestedResolution) throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
-        // Set up printer with supported and default attributes
         PrintDocumentAdapter adapter =
                 setUpPrinter(minMargins, mediaSizes, defaultMediaSize, colorModes, defaultColorMode,
                         duplexModes, defaultDuplexMode, resolutions, defaultResolution);
 
-        Log.d(LOG_TAG, "makeDefaultPrinter");
-        // Make printer default. This is necessary as a different default printer might pre-select
-        // its default attributes and thereby overrides the defaults of the tested printer.
-        makeDefaultPrinter(adapter, PRINTER_NAME);
-
         // Select suggested attributes
         PrintAttributes suggestedAttributes = createAttributes(suggestedMediaSize,
                 suggestedColorMode, suggestedDuplexMode, suggestedResolution);
@@ -391,11 +379,11 @@
         Log.d(LOG_TAG, "print");
         print(adapter, suggestedAttributes);
         Log.d(LOG_TAG, "waitForWriteAdapterCallback");
-        waitForWriteAdapterCallback(2);
+        waitForWriteAdapterCallback(1);
         Log.d(LOG_TAG, "clickPrintButton");
         clickPrintButton();
         Log.d(LOG_TAG, "waitForPrinterDiscoverySessionDestroyCallbackCalled");
-        waitForPrinterDiscoverySessionDestroyCallbackCalled(2);
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
 
         // It does not make sense to suggest minMargins, hence the print framework always picks
         // the one set up for the printer.
@@ -443,7 +431,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testDefaultMatchesSuggested0() throws Exception {
+    @Test
+    public void defaultMatchesSuggested0() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[0],
                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[0],
@@ -459,7 +448,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testDefaultMatchesSuggested1() throws Exception {
+    @Test
+    public void defaultMatchesSuggested1() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[1],
                  MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[1],
@@ -475,7 +465,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testDefaultMatchesSuggested2() throws Exception {
+    @Test
+    public void defaultMatchesSuggested2() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[2],
                  MEDIA_SIZES,  MEDIA_SIZES[2],  MEDIA_SIZES[2],
@@ -492,7 +483,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testNoSuggestion0() throws Exception {
+    @Test
+    public void noSuggestion0() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[0],
                  MEDIA_SIZES,  MEDIA_SIZES[0],  null,
@@ -508,7 +500,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testNoSuggestion1() throws Exception {
+    @Test
+    public void noSuggestion1() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[1],
                  MEDIA_SIZES,  MEDIA_SIZES[1],  null,
@@ -524,7 +517,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testNoSuggestion2() throws Exception {
+    @Test
+    public void noSuggestion2() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[2],
                  MEDIA_SIZES,  MEDIA_SIZES[2],  null,
@@ -542,7 +536,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testMediaSizeSuggestion0() throws Exception {
+    @Test
+    public void mediaSizeSuggestion0() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[0],
                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
@@ -559,7 +554,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testMediaSizeSuggestion1() throws Exception {
+    @Test
+    public void mediaSizeSuggestion1() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[1],
                  MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[0],
@@ -576,7 +572,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testDuplexModeSuggestion0() throws Exception {
+    @Test
+    public void duplexModeSuggestion0() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[0],
                  MEDIA_SIZES,  MEDIA_SIZES[0],  null,
@@ -593,7 +590,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testDuplexModeSuggestion1() throws Exception {
+    @Test
+    public void duplexModeSuggestion1() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[1],
                  MEDIA_SIZES,  MEDIA_SIZES[1],  null,
@@ -608,7 +606,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testSuggestedDifferentFromDefault() throws Exception {
+    @Test
+    public void suggestedDifferentFromDefault() throws Exception {
         //       available     default          suggestion
         baseTest(              MIN_MARGINS[0],
                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
@@ -623,7 +622,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testUnsupportedSuggested() throws Exception {
+    @Test
+    public void unsupportedSuggested() throws Exception {
         //       available                               default          suggestion
         baseTest(                                        MIN_MARGINS[0],
                  Arrays.copyOfRange(MEDIA_SIZES, 0, 1),  MEDIA_SIZES[0],  MEDIA_SIZES[1],
@@ -638,7 +638,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testNegativeMargins() throws Exception {
+    @Test
+    public void negativeMargins() throws Exception {
         //       available     default                          suggestion
         baseTest(              new Margins(-10, -10, -10, -10),
                  MEDIA_SIZES,  MEDIA_SIZES[1],                  null,
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index f171884..32b269e 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -22,7 +22,6 @@
 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,10 +42,13 @@
 import android.print.cts.services.StubbablePrinterDiscoverySession;
 import android.printservice.PrintJob;
 import android.printservice.PrintService;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.InOrder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -56,56 +58,54 @@
  * This test verifies that the system respects the {@link PrintDocumentAdapter}
  * contract and invokes all callbacks as expected.
  */
+@RunWith(AndroidJUnit4.class)
 public class PrintDocumentAdapterContractTest extends BasePrintTest {
+    private static final String LOG_TAG = "PrintDocumentAdapterContractTest";
 
-    public void testNoPrintOptionsOrPrinterChange() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
+    @Before
+    public void setDefaultPrinter() throws Exception {
         FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
         SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+    }
 
+    @Before
+    public void clearPrintSpoolerState() throws Exception {
+        clearPrintSpoolerData();
+    }
+
+    @Test
+    public void noPrintOptionsOrPrinterChange() throws Exception {
         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(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 +141,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)
@@ -182,53 +182,10 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testNoPrintOptionsOrPrinterChangeCanceled() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
-
+    @Test
+    public void noPrintOptionsOrPrinterChangeCanceled() throws Exception {
         // 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 +213,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,55 +233,104 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testPrintOptionsChangeAndNoPrinterChange() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+    @Test
+    public void nonCallingBackWrite() throws Exception {
+        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);
+    }
+
+    @Test
+    public void printOptionsChangeAndNoPrinterChange() throws Exception {
         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);
-                // 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 +348,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 +393,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 +438,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 +451,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 +464,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)
@@ -480,55 +486,40 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testPrintOptionsChangeAndPrinterChange() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void printOptionsChangeAndPrinterChange() throws Exception {
         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);
-                // 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 +537,7 @@
         waitForLayoutAdapterCallbackCount(2);
 
         // Change the color.
-        changeColor("Black & White");
+        changeColor(getPrintSpoolerStringArray("color_mode_labels")[0]);
 
         // Wait for layout.
         waitForLayoutAdapterCallbackCount(3);
@@ -580,7 +571,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 +613,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)
@@ -644,56 +635,41 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testPrintOptionsChangeAndNoPrinterChangeAndContentChange()
+    @Test
+    public void printOptionsChangeAndNoPrinterChangeAndContentChange()
             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(
-            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 +708,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)
@@ -778,53 +754,38 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testNewPrinterSupportsSelectedPrintOptions() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void newPrinterSupportsSelectedPrintOptions() throws Exception {
         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();
-                // 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 +821,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)
@@ -887,54 +848,39 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testNothingChangesAllPagesWrittenFirstTime() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void nothingChangesAllPagesWrittenFirstTime() throws Exception {
         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(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 +919,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)
@@ -1017,40 +963,25 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testCancelLongRunningLayout() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void cancelLongRunningLayout() throws Exception {
         // 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 +1012,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)
@@ -1095,36 +1026,23 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testCancelLongRunningWrite() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void cancelLongRunningWrite() throws Exception {
         // 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 +1050,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 +1089,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)
@@ -1195,33 +1108,21 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testFailedLayout() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void failedLayout() throws Exception {
         // 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 +1150,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)
@@ -1265,46 +1166,31 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testFailedWrite() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void failedWrite() throws Exception {
         // 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 +1218,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,52 +1237,169 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testRequestedPagesNotWritten() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+    @Test
+    public void unexpectedLayoutCancel() throws Exception {
+        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);
+    }
+
+    @Test
+    public void unexpectedWriteCancel() throws Exception {
+        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);
+    }
+
+    @Test
+    public void requestedPagesNotWritten() throws Exception {
         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();
-                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 +1427,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)
@@ -1443,32 +1446,20 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testLayoutCallbackNotCalled() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void layoutCallbackNotCalled() throws Exception {
         // 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 +1487,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)
@@ -1510,45 +1501,30 @@
         verifyNoMoreInteractions(adapter);
     }
 
-    public void testWriteCallbackNotCalled() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void writeCallbackNotCalled() throws Exception {
         // 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 +1552,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,60 +1571,201 @@
         verifyNoMoreInteractions(adapter);
     }
 
+    @Test
+    public void layoutCallbackCalledTwice() throws Exception {
+        // 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);
+    }
+
+    @Test
+    public void writeCallbackCalledTwice() throws Exception {
+        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
      *
      * @throws Exception If anything is unexpected
      */
-    public void testNotEnoughPages() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
-
+    @Test
+    public void notEnoughPages() throws Exception {
         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);
@@ -1665,247 +1782,95 @@
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
     }
 
-    /**
-     * Executes a print process with a given print document info
-     *
-     * @param info The print document info to declare on layout
-     */
-    private void printDocumentInfoBaseTest(final PrintDocumentInfo info) throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-        // Configure the print services.
-        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
-        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+    private PrinterDiscoverySessionCallbacks createFirstMockDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
+                    invocation.getMock();
 
-        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+            StubbablePrinterDiscoverySession session = mock.getSession();
+            PrintService service = session.getService();
 
-        // 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;
-                    }
-                });
+            if (session.getPrinters().isEmpty()) {
+                List<PrinterInfo> printers = new ArrayList<>();
 
-        // Start printing.
-        print(adapter);
+                // 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);
 
-        // Select the second printer.
-        selectPrinter("Second printer");
+                // 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);
 
-        // Wait for layout.
-        waitForLayoutAdapterCallbackCount(2);
+                // 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);
 
-        // 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);
-    }
-
-    /**
-     * Test that the default values of the PrintDocumentInfo are fine.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoNothingSet() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build());
-    }
-
-    /**
-     * Test that a unknown page count is handled correctly.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoUnknownPageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build());
-    }
-
-    /**
-     * Test that zero page count is handled correctly.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoZeroPageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(0).build());
-    }
-
-    /**
-     * Test that page count one is handled correctly. (The document has two pages)
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoOnePageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(1).build());
-    }
-
-    /**
-     * Test that page count three is handled correctly. (The document has two pages)
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoThreePageCount() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setPageCount(3).build());
-    }
-
-    /**
-     * Test that a photo content type is handled correctly.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoContentTypePhoto() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO).build());
-    }
-
-    /**
-     * Test that a unknown content type is handled correctly.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoContentTypeUnknown() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN).build());
-    }
-
-    /**
-     * Test that a undefined content type is handled correctly.
-     *
-     * @throws Exception If anything unexpected happens
-     */
-    public void testDocumentInfoContentTypeNonDefined() throws Exception {
-        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
-                .setContentType(-23).build());
+                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/PrintDocumentInfoTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentInfoTest.java
new file mode 100644
index 0000000..a9d03c9
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentInfoTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+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;
+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.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.print.cts.Utils.eventually;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * This test verifies that the system respects the {@link PrintDocumentAdapter}
+ * contract and invokes all callbacks as expected.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PrintDocumentInfoTest extends android.print.cts.BasePrintTest {
+    private static boolean sIsDefaultPrinterSet;
+
+    @Before
+    public void setDefaultPrinter() throws Exception {
+        if (!sIsDefaultPrinterSet) {
+            // Create a callback for the target print service.
+            FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+            SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+            // Create a mock print adapter.
+            final PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+            makeDefaultPrinter(adapter, "First printer");
+            resetCounters();
+
+            sIsDefaultPrinterSet = true;
+        }
+    }
+
+    /**
+     * Executes a print process with a given print document info
+     *
+     * @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 printDocumentBaseTest(String name, Integer contentType, Integer pageCount)
+            throws Throwable {
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        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);
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[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(info, false);
+                    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);
+                    onWriteCalled();
+                    return null;
+                }, invocation -> null);
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for layout.
+        waitForWriteAdapterCallback(1);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // 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);
+    }
+
+    /**
+     * Test that the default values of the PrintDocumentInfo are fine.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoNothingSet() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, null);
+    }
+
+    /**
+     * Test that a unknown page count is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoUnknownPageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, PrintDocumentInfo.PAGE_COUNT_UNKNOWN);
+    }
+
+    /**
+     * Test that zero page count is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoZeroPageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 0);
+    }
+
+    /**
+     * Test that page count one is handled correctly. (The document has two pages)
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoOnePageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 1);
+    }
+
+    /**
+     * Test that page count three is handled correctly. (The document has two pages)
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoThreePageCount() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, null, 3);
+    }
+
+    /**
+     * Test that a photo content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoContentTypePhoto() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, PrintDocumentInfo.CONTENT_TYPE_PHOTO, null);
+    }
+
+    /**
+     * Test that a unknown content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoContentTypeUnknown() throws Throwable {
+        printDocumentBaseTest(PRINT_JOB_NAME, PrintDocumentInfo.CONTENT_TYPE_UNKNOWN, null);
+    }
+
+    /**
+     * Test that a undefined content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    @Test
+    public void documentInfoContentTypeNonDefined() 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);
+
+                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 =
+                createFirstMockDiscoverySessionCallbacks();
+        return createMockPrintServiceCallbacks(invocation -> callbacks, invocation -> {
+            PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+            printJob.complete();
+            return null;
+        }, null);
+    }
+
+    private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
+        return createMockPrintServiceCallbacks(null, null, null);
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintJobStateTransitionsTest.java b/tests/tests/print/src/android/print/cts/PrintJobStateTransitionsTest.java
new file mode 100644
index 0000000..f0674a2
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintJobStateTransitionsTest.java
@@ -0,0 +1,376 @@
+/*
+ * 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.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+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.printservice.PrintJob;
+import android.util.Log;
+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;
+
+import static android.print.cts.Utils.eventually;
+import static org.junit.Assert.*;
+
+/**
+ * Tests all possible states of print jobs.
+ */
+@RunWith(Parameterized.class)
+public class PrintJobStateTransitionsTest extends BasePrintTest {
+    private static final String PRINTER_NAME = "TestPrinter";
+    private static final String LOG_TAG = "PrintJobStateTransTest";
+
+    /** The printer discovery session used in this test */
+    private static StubbablePrinterDiscoverySession sDiscoverySession;
+    private static boolean sHasBeenSetUp;
+
+    private final static int STATES[] = new int[] { PrintJobInfo.STATE_QUEUED,
+            PrintJobInfo.STATE_STARTED,
+            PrintJobInfo.STATE_BLOCKED,
+            PrintJobInfo.STATE_COMPLETED,
+            PrintJobInfo.STATE_FAILED,
+            PrintJobInfo.STATE_CANCELED
+    };
+
+    private final static boolean sKnownFailures[][] = new boolean[8][8];
+
+    private final int mState1;
+    private final int mState2;
+    private final int mState3;
+    private final boolean[] mTestSuccess = new boolean[1];
+
+    /**
+     * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a simple test printer.
+     *
+     * @return The mock session callbacks
+     */
+    private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(invocation -> {
+            // Get the session.
+            sDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                    .getSession();
+
+            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());
+
+                ArrayList<PrinterInfo> printers = new ArrayList<>(1);
+                printers.add(printer.build());
+
+                sDiscoverySession.addPrinters(printers);
+            }
+            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 Throwable;
+    }
+
+    /**
+     * 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 printJobTest test function to call
+     */
+    private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
+            final PrinterDiscoverySessionCallbacks sessionCallbacks,
+            final PrintJobTestFn printJobTest) {
+        return createMockPrintServiceCallbacks(
+                invocation -> sessionCallbacks, invocation -> {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+
+                    try {
+                        printJobTest.onPrintJobQueued(printJob);
+                        mTestSuccess[0] = true;
+                    } catch (Throwable t) {
+                        throw new RuntimeException(t);
+                    }
+
+                    onPrintJobQueuedCalled();
+
+                    return null;
+                }, null);
+    }
+
+    public PrintJobStateTransitionsTest(int state1, int state2, int state3) {
+        mState1 = state1;
+        mState2 = state2;
+        mState3 = state3;
+    }
+
+    private static boolean setState(PrintJob job, int state) {
+        switch (state) {
+            case PrintJobInfo.STATE_QUEUED:
+                // queue cannot be set, but is set at the beginning
+                return job.isQueued();
+            case PrintJobInfo.STATE_STARTED:
+                return job.start();
+            case PrintJobInfo.STATE_BLOCKED:
+                return job.block(null);
+            case PrintJobInfo.STATE_COMPLETED:
+                return job.complete();
+            case PrintJobInfo.STATE_FAILED:
+                return job.fail(null);
+            case PrintJobInfo.STATE_CANCELED:
+                return job.cancel();
+            default:
+                // not reached
+                throw new IllegalArgumentException("Cannot switch to " + state);
+        }
+    }
+
+    private static boolean isStateTransitionAllowed(int before, int after) {
+        switch (before) {
+            case PrintJobInfo.STATE_QUEUED:
+                switch (after) {
+                    case PrintJobInfo.STATE_QUEUED:
+                        // queued is not actually set, see setState
+                    case PrintJobInfo.STATE_STARTED:
+                    case PrintJobInfo.STATE_FAILED:
+                    case PrintJobInfo.STATE_CANCELED:
+                        return true;
+                    default:
+                        return false;
+                }
+            case PrintJobInfo.STATE_STARTED:
+                switch (after) {
+                    case PrintJobInfo.STATE_QUEUED:
+                    case PrintJobInfo.STATE_STARTED:
+                        return false;
+                    default:
+                        return true;
+                }
+            case PrintJobInfo.STATE_BLOCKED:
+                switch (after) {
+                    case PrintJobInfo.STATE_STARTED:
+                        // blocked -> started == restart
+                    case PrintJobInfo.STATE_FAILED:
+                    case PrintJobInfo.STATE_CANCELED:
+                        return true;
+                    default:
+                        return false;
+                }
+            case PrintJobInfo.STATE_COMPLETED:
+                return false;
+            case PrintJobInfo.STATE_FAILED:
+                return false;
+            case PrintJobInfo.STATE_CANCELED:
+                return false;
+            default:
+                // not reached
+                throw new IllegalArgumentException("Cannot switch from " + before);
+        }
+    }
+
+    private static void checkState(PrintJob job, int state) throws Throwable {
+        eventually(() -> assertEquals(state, job.getInfo().getState()));
+        switch (state) {
+            case PrintJobInfo.STATE_QUEUED:
+                eventually(() -> assertTrue(job.isQueued()));
+                break;
+            case PrintJobInfo.STATE_STARTED:
+                eventually(() -> assertTrue(job.isStarted()));
+                break;
+            case PrintJobInfo.STATE_BLOCKED:
+                eventually(() -> assertTrue(job.isBlocked()));
+                break;
+            case PrintJobInfo.STATE_COMPLETED:
+                eventually(() -> assertTrue(job.isCompleted()));
+                break;
+            case PrintJobInfo.STATE_FAILED:
+                eventually(() -> assertTrue(job.isFailed()));
+                break;
+            case PrintJobInfo.STATE_CANCELED:
+                eventually(() -> assertTrue(job.isCancelled()));
+                break;
+            default:
+                // not reached
+                throw new IllegalArgumentException("Cannot check " + state);
+        }
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        ArrayList<Object[]> parameters = new ArrayList<>((int)Math.pow(STATES.length, 3));
+        for (final int state1 : STATES) {
+            for (final int state2 : STATES) {
+                for (final int state3 : STATES) {
+                    // No need to test the same non-transitions twice
+                    if (state1 == state2 && state2 == state3) {
+                        continue;
+                    }
+
+                    // QUEUED does not actually set a state, see setState
+                    if (state1 == PrintJobInfo.STATE_QUEUED) {
+                        continue;
+                    }
+
+                    parameters.add(new Object[]{state1, state2, state3});
+                }
+            }
+        }
+
+        return parameters;
+    }
+
+    @Before
+    public void setPrinter() throws Exception {
+        if (!sHasBeenSetUp) {
+            createActivity();
+
+            resetCounters();
+            PrinterDiscoverySessionCallbacks sessionCallbacks
+                    = createFirstMockPrinterDiscoverySessionCallbacks();
+
+            // Create the service callbacks for the first print service.
+            PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+                    sessionCallbacks, printJob -> { });
+
+            // 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));
+
+            // Create a print adapter that respects the print contract.
+            PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+            makeDefaultPrinter(adapter, PRINTER_NAME);
+
+            sHasBeenSetUp = true;
+        }
+
+        resetCounters();
+    }
+
+    /**
+     * Base test for the print job tests. Starts a print job and executes a testFn once the job is
+     * queued.
+     *
+     * @throws Exception If anything is unexpected.
+     */
+    @Test
+    @NoActivity
+    public void stateTransitions() throws Exception {
+        // No need to repeat what previously failed
+        if(sKnownFailures[mState1][mState2] || sKnownFailures[mState2][mState3]) {
+            Log.i(LOG_TAG, "Skipped " + mState1 + " -> " + mState2 + " -> " + mState3);
+            return;
+        } else {
+            Log.i(LOG_TAG, "Test " + mState1 + " -> " + mState2 + " -> " + mState3);
+            if (getActivity() == null) {
+                createActivity();
+            }
+        }
+
+        // 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, printJob -> {
+                    sKnownFailures[PrintJobInfo.STATE_QUEUED][mState1] = true;
+
+                    boolean success = setState(printJob, mState1);
+                    assertEquals(isStateTransitionAllowed(PrintJobInfo.STATE_QUEUED,
+                            mState1), success);
+                    if (!success) {
+                        return;
+                    }
+                    checkState(printJob, mState1);
+
+                    sKnownFailures[PrintJobInfo.STATE_QUEUED][mState1] = false;
+
+                    sKnownFailures[mState1][mState2] = true;
+
+                    success = setState(printJob, mState2);
+                    assertEquals(isStateTransitionAllowed(mState1, mState2), success);
+                    if (!success) {
+                        return;
+                    }
+                    checkState(printJob, mState2);
+
+                    sKnownFailures[mState1][mState2] = false;
+
+                    sKnownFailures[mState2][mState3] = true;
+
+                    success = setState(printJob, mState3);
+                    assertEquals(isStateTransitionAllowed(mState2, mState3), success);
+                    if (!success) {
+                        return;
+                    }
+                    checkState(printJob, mState3);
+
+                    sKnownFailures[mState2][mState3] = false;
+                });
+
+        // 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));
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+        // Start printing.
+        print(adapter);
+        clickPrintButton();
+
+        // Wait for print job to be queued
+        waitForServiceOnPrintJobQueuedCallbackCalled(1);
+
+        // Wait for discovery session to be destroyed to isolate tests from each other
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+
+        assertTrue(mTestSuccess[0]);
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintJobTest.java b/tests/tests/print/src/android/print/cts/PrintJobTest.java
index b0f3742e..f3081fb 100644
--- a/tests/tests/print/src/android/print/cts/PrintJobTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintJobTest.java
@@ -16,17 +16,13 @@
 
 package android.print.cts;
 
-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.PrintJobInfo;
+import android.print.PrintManager;
 import android.print.PrinterCapabilitiesInfo;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
@@ -37,27 +33,21 @@
 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 android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 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;
+import static org.junit.Assert.*;
 
 /**
  * Tests all possible states of print jobs.
  */
+@RunWith(AndroidJUnit4.class)
 public class PrintJobTest extends BasePrintTest {
-    private static final String LOG_TAG = "PrintJobTest";
-
     private static final String PRINTER_NAME = "TestPrinter";
 
     private final static String VALID_NULL_KEY = "validNullKey";
@@ -71,53 +61,8 @@
     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;
+    private static boolean sHasBeenSetUp;
 
     /**
      * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a simple test printer.
@@ -125,51 +70,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 +117,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);
     }
 
     /**
@@ -242,12 +139,8 @@
      *
      * @throws Exception If anything is unexpected.
      */
-    private void baseTest(PrintJobTestFn testFn, int testCaseNum)
+    private void baseTest(PrintJobTestFn testFn)
             throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
         testSuccess[0] = false;
 
         // Create the session of the printers that we will be checking.
@@ -265,23 +158,14 @@
         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);
-
-        if (testCaseNum == 0) {
-            selectPrinter(PRINTER_NAME);
-        }
-
         clickPrintButton();
 
-        if (testCaseNum == 0) {
-            answerPrintServicesWarning(true);
-        }
-
         // Wait for print job to be queued
-        waitForServiceOnPrintJobQueuedCallbackCalled(testCaseNum + 1);
+        waitForServiceOnPrintJobQueuedCallbackCalled(1);
 
         // Wait for discovery session to be destroyed to isolate tests from each other
         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
@@ -291,71 +175,7 @@
         }
     }
 
-    private static boolean setState(PrintJob job, int state) {
-        switch (state) {
-            case PrintJobInfo.STATE_QUEUED:
-                // queue cannot be set, but is set at the beginning
-                return job.isQueued();
-            case PrintJobInfo.STATE_STARTED:
-                return job.start();
-            case PrintJobInfo.STATE_BLOCKED:
-                return job.block(null);
-            case PrintJobInfo.STATE_COMPLETED:
-                return job.complete();
-            case PrintJobInfo.STATE_FAILED:
-                return job.fail(null);
-            case PrintJobInfo.STATE_CANCELED:
-                return job.cancel();
-            default:
-                // not reached
-                throw new IllegalArgumentException("Cannot switch to " + state);
-        }
-    }
-
-    private static boolean isStateTransitionAllowed(int before, int after) {
-        switch (before) {
-            case PrintJobInfo.STATE_QUEUED:
-                switch (after) {
-                    case PrintJobInfo.STATE_QUEUED:
-                        // queued is not actually set, see setState
-                    case PrintJobInfo.STATE_STARTED:
-                    case PrintJobInfo.STATE_FAILED:
-                    case PrintJobInfo.STATE_CANCELED:
-                        return true;
-                    default:
-                        return false;
-                }
-            case PrintJobInfo.STATE_STARTED:
-                switch (after) {
-                    case PrintJobInfo.STATE_QUEUED:
-                    case PrintJobInfo.STATE_STARTED:
-                        return false;
-                    default:
-                        return true;
-                }
-            case PrintJobInfo.STATE_BLOCKED:
-                switch (after) {
-                    case PrintJobInfo.STATE_STARTED:
-                        // blocked -> started == restart
-                    case PrintJobInfo.STATE_FAILED:
-                    case PrintJobInfo.STATE_CANCELED:
-                        return true;
-                    default:
-                        return false;
-                }
-            case PrintJobInfo.STATE_COMPLETED:
-                return false;
-            case PrintJobInfo.STATE_FAILED:
-                return false;
-            case PrintJobInfo.STATE_CANCELED:
-                return false;
-            default:
-                // not reached
-                throw new IllegalArgumentException("Cannot switch from " + before);
-        }
-    }
-
-    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:
@@ -382,158 +202,98 @@
         }
     }
 
-    public void testStateTransitions() throws Exception {
-        int states[] = new int[] { PrintJobInfo.STATE_QUEUED,
-                PrintJobInfo.STATE_STARTED,
-                PrintJobInfo.STATE_BLOCKED,
-                PrintJobInfo.STATE_COMPLETED,
-                PrintJobInfo.STATE_FAILED,
-                PrintJobInfo.STATE_CANCELED
-        };
+    @Before
+    public void setPrinter() throws Exception {
+        if (!sHasBeenSetUp) {
+            resetCounters();
+            PrinterDiscoverySessionCallbacks sessionCallbacks
+                    = createFirstMockPrinterDiscoverySessionCallbacks();
 
-        final boolean knownFailures[][] = new boolean[8][8];
+            // Create the service callbacks for the first print service.
+            PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+                    sessionCallbacks, printJob -> { });
 
-        int testCaseNum = 0;
+            // Configure the print services.
+            FirstPrintService.setCallbacks(serviceCallbacks);
 
-        for (final int state1 : states) {
-            for (final int state2 : states) {
-                for (final int state3 : states) {
-                    // No need to test the same non-transitions twice
-                    if (state1 == state2 && state2 == state3) {
-                        continue;
-                    }
+            // We don't use the second service, but we have to still configure it
+            SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
 
-                    // No need to repeat what previously failed
-                    if (knownFailures[state1][state2]
-                            || knownFailures[state2][state3]) {
-                        continue;
-                    }
+            // Create a print adapter that respects the print contract.
+            PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
 
-                    // QUEUED does not actually set a state, see setState
-                    if (state1 == PrintJobInfo.STATE_QUEUED) {
-                        continue;
-                    }
+            makeDefaultPrinter(adapter, PRINTER_NAME);
 
-                    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;
-
-                            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++;
-                }
-            }
-        }
-    }
-
-    public void testBlockWithReason() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                printJob.start();
-                checkState(printJob, PrintJobInfo.STATE_STARTED);
-
-                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())));
-
-                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())));
-            }
-        }, 0);
-    }
-
-    public void testFailWithReason() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                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())));
-
-                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());
-
-                printJob.setTag("testTag");
-                eventually(() -> assertEquals("testTag", printJob.getTag()));
-
-                printJob.setTag(null);
-                eventually(() -> assertNull(printJob.getTag()));
-            }
-        }, 0);
-    }
-
-    public void testAdvancedOption() throws Exception {
-        if (!supportsPrinting()) {
-            return;
+            sHasBeenSetUp = true;
         }
 
+        resetCounters();
+    }
+
+    @Test
+    public void blockWithReason() throws Exception {
+        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())));
+
+            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())));
+
+            printJob.setStatus(R.string.testStr2);
+            eventually(() -> assertEquals(getActivity().getString(R.string.testStr2),
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
+        });
+    }
+
+    @Test
+    public void failWithReason() throws Exception {
+        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())));
+
+            success = printJob.fail("another reason");
+            assertFalse(success);
+            checkState(printJob, PrintJobInfo.STATE_FAILED);
+            eventually(() -> assertEquals("test reason",
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
+        });
+    }
+
+    @Test
+    public void tag() throws Exception {
+        baseTest(printJob -> {
+            // Default value should be null
+            assertNull(printJob.getTag());
+
+            printJob.setTag("testTag");
+            eventually(() -> assertEquals("testTag", printJob.getTag()));
+
+            printJob.setTag(null);
+            eventually(() -> assertNull(printJob.getTag()));
+        });
+    }
+
+    @Test
+    public void advancedOption() throws Exception {
         testSuccess[0] = false;
 
         // Create the session of the printers that we will be checking.
@@ -542,34 +302,31 @@
 
         // 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));
                 });
 
+        final int[] callCount = new int[1];
+
         CustomPrintOptionsActivity.setCallBack(
-                new CustomPrintOptionsActivity.CustomPrintOptionsCallback() {
-                    @Override
-                    public PrintJobInfo executeCustomPrintOptionsActivity(
-                            PrintJobInfo printJob, PrinterInfo printer) {
+                (printJob, printer) -> {
+                    if (callCount[0] == 0) {
                         PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(printJob);
 
                         try {
@@ -588,7 +345,40 @@
 
                         printJobBuilder.putAdvancedOption(VALID_NULL_KEY, null);
 
+                        // Rotate the media size to force adapter to write again
+                        PrintAttributes.Builder attributeBuilder = new PrintAttributes.Builder();
+                        attributeBuilder.setMediaSize(printJob.getAttributes().getMediaSize()
+                                .asLandscape());
+                        attributeBuilder.setResolution(printJob.getAttributes().getResolution());
+                        attributeBuilder.setDuplexMode(printJob.getAttributes().getDuplexMode());
+                        attributeBuilder.setColorMode(printJob.getAttributes().getColorMode());
+                        attributeBuilder.setMinMargins(printJob.getAttributes().getMinMargins());
+
+                        printJobBuilder.setAttributes(attributeBuilder.build());
+
                         return printJobBuilder.build();
+                    } else {
+                        // Check that options are readable
+                        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));
+
+                        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));
+
+                        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));
+
+                        return null;
                     }
                 });
 
@@ -599,16 +389,46 @@
         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);
+        print(adapter, "advancedOption");
 
-        selectPrinter(PRINTER_NAME);
+        waitForWriteAdapterCallback(1);
+
         openPrintOptions();
         openCustomPrintOptions();
+
+        waitForWriteAdapterCallback(2);
+
+        callCount[0]++;
+
+        // The advanced option should not be readable from the activity
+        getActivity().getSystemService(PrintManager.class).getPrintJobs().stream()
+                .filter(printJob -> printJob.getInfo().getLabel().equals("advancedOption"))
+                .forEach(printJob -> {
+                    assertFalse(printJob.getInfo().hasAdvancedOption(VALID_STRING_KEY));
+                    assertEquals(null,
+                            printJob.getInfo().getAdvancedStringOption(VALID_STRING_KEY));
+
+                    assertFalse(printJob.getInfo().hasAdvancedOption(INVALID_STRING_KEY));
+                    assertNull(printJob.getInfo().getAdvancedStringOption(INVALID_STRING_KEY));
+
+                    assertFalse(printJob.getInfo().hasAdvancedOption(VALID_INT_KEY));
+                    assertEquals(0, printJob.getInfo().getAdvancedIntOption(VALID_INT_KEY));
+
+                    assertFalse(printJob.getInfo().hasAdvancedOption(VALID_NULL_KEY));
+                    assertNull(printJob.getInfo().getAdvancedStringOption(VALID_NULL_KEY));
+
+                    assertFalse(printJob.getInfo().hasAdvancedOption(INVALID_INT_KEY));
+                    assertEquals(0, printJob.getInfo().getAdvancedIntOption(INVALID_INT_KEY));
+
+                    assertNull(printJob.getInfo().getAdvancedStringOption(VALID_INT_KEY));
+                    assertEquals(0, printJob.getInfo().getAdvancedIntOption(VALID_STRING_KEY));
+                });
+
+        openCustomPrintOptions();
         clickPrintButton();
-        answerPrintServicesWarning(true);
 
         // Wait for print job to be queued
         waitForServiceOnPrintJobQueuedCallbackCalled(1);
@@ -621,58 +441,54 @@
         }
     }
 
-    public void testOther() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                assertNotNull(printJob.getDocument());
-                assertNotNull(printJob.getId());
-            }
-        }, 0);
+    @Test
+    public void other() throws Exception {
+        baseTest(printJob -> {
+            assertNotNull(printJob.getDocument());
+            assertNotNull(printJob.getId());
+        });
     }
 
-    public void testSetStatus() throws Exception {
-        baseTest(new PrintJobTestFn() {
-            @Override
-            public void onPrintJobQueued(PrintJob printJob) throws Exception {
-                printJob.start();
+    @Test
+    public void setStatus() throws Exception {
+        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())));
-            }
-        }, 0);
+            printJob.setStatus(-1);
+            eventually(() -> assertNull(
+                    printJob.getInfo().getStatus(getActivity().getPackageManager())));
+        });
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
index ccb1f07..7be5fc1 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,315 +29,207 @@
 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;
 import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.InfoActivity;
 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;
+import android.printservice.PrintService;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 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 org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
-import java.util.concurrent.TimeoutException;
+
+import static android.print.cts.Utils.*;
+import static org.junit.Assert.*;
 
 /**
  * Test the interface from a print service to the print manager
  */
+@RunWith(AndroidJUnit4.class)
 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, ArrayList<String> trackedPrinters) {
+        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(), InfoActivity.class);
+                infoIntent.putExtra("PRINTER_NAME", PRINTER_NAME);
 
-                    mPrinter = new PrinterInfo.Builder(printerId, PRINTER_NAME,
-                            PrinterInfo.STATUS_IDLE)
-                                    .setCapabilities(capabilities)
-                                    .setDescription("Minimal capabilities")
-                                    .setInfoIntent(infoPendingIntent)
-                                    .build();
-                    printers.add(mPrinter);
+                PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(), 0,
+                        infoIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
-                    mDiscoverySession.addPrinters(printers);
+                sPrinter = new PrinterInfo.Builder(printerId, printerName,
+                        PrinterInfo.STATUS_IDLE)
+                        .setCapabilities(capabilities)
+                        .setDescription("Minimal capabilities")
+                        .setInfoIntent(infoPendingIntent)
+                        .build();
+                printers.add(sPrinter);
+
+                session.addPrinters(printers);
+            }
+
+            onPrinterDiscoverySessionCreateCalled();
+
+            return null;
+        }, null, null, invocation -> {
+            if (trackedPrinters != null) {
+                synchronized (trackedPrinters) {
+                    trackedPrinters
+                            .add(((PrinterId) invocation.getArguments()[0]).getLocalId());
+                    trackedPrinters.notifyAll();
                 }
-                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];
+            return null;
+        }, invocation -> {
+            CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
+                    .getArguments()[2];
 
-                if (mIcon != null) {
-                    callback.onCustomPrinterIconLoaded(mIcon);
+            if (mIcon != null) {
+                callback.onCustomPrinterIconLoaded(mIcon);
+            }
+            return null;
+        }, invocation -> {
+            if (trackedPrinters != null) {
+                synchronized (trackedPrinters) {
+                    trackedPrinters.remove(((PrinterId) invocation.getArguments()[0]).getLocalId());
+                    trackedPrinters.notifyAll();
                 }
-                return null;
             }
-        }, null, new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                // Take a note onDestroy was called.
-                onPrinterDiscoverySessionDestroyCalled();
-                return null;
-            }
+
+            return 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(), 0.1));
+        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 +241,37 @@
      *
      * @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 {
-        if (!supportsPrinting()) {
-            return;
-        }
+    @Test
+    public void progress() throws Throwable {
         // Create the session callbacks that we will be checking.
         PrinterDiscoverySessionCallbacks sessionCallbacks
-                = createFirstMockPrinterDiscoverySessionCallbacks();
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME, null);
 
         // Create the service callbacks for the first print service.
-        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
                 sessionCallbacks);
 
         // Configure the print services.
@@ -394,7 +281,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 +298,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 +307,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 +317,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 +334,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 +357,27 @@
      * 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 {
-        if (!supportsPrinting()) {
-            return;
-        }
+    @Test
+    public void updateIcon() throws Throwable {
         // Create the session callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks sessionCallbacks
-                = createFirstMockPrinterDiscoverySessionCallbacks();
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME, null);
 
         // Create the service callbacks for the first print service.
-        PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
                 sessionCallbacks);
 
         // Configure the print services.
@@ -539,7 +387,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 +408,224 @@
         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())));
+
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    /**
+     * Test that we cannot call attachBaseContext
+     *
+     * @throws Throwable If anything is unexpected.
+     */
+    @Test
+    public void cannotUseAttachBaseContext() throws Throwable {
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks sessionCallbacks
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME, null);
+
+        // 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);
+
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    /**
+     * Test that the active print jobs can be read
+     *
+     * @throws Throwable If anything is unexpected.
+     */
+    @Test
+    public void getActivePrintJobs() throws Throwable {
+        clearPrintSpoolerData();
+
+        try {
+            PrintManager pm = (PrintManager) getActivity().getSystemService(Context.PRINT_SERVICE);
+
+            // Configure first print service
+            PrinterDiscoverySessionCallbacks sessionCallbacks1
+                    = createMockPrinterDiscoverySessionCallbacks("Printer1", null);
+            PrintServiceCallbacks serviceCallbacks1 = createMockPrinterServiceCallbacks(
+                    sessionCallbacks1);
+            FirstPrintService.setCallbacks(serviceCallbacks1);
+
+            // Configure second print service
+            PrinterDiscoverySessionCallbacks sessionCallbacks2
+                    = createMockPrinterDiscoverySessionCallbacks("Printer2", null);
+            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);
+        } finally {
+            clearPrintSpoolerData();
+        }
+    }
+
+    /**
+     * Test that the icon get be updated.
+     *
+     * @throws Throwable If anything is unexpected.
+     */
+    @Test
+    public void selectViaInfoIntent() throws Throwable {
+        ArrayList<String> trackedPrinters = new ArrayList<>();
+
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks sessionCallbacks
+                = createMockPrinterDiscoverySessionCallbacks(PRINTER_NAME, trackedPrinters);
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks serviceCallbacks = createMockPrinterServiceCallbacks(
+                sessionCallbacks);
+
+        // 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));
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+        // Start printing.
+        print(adapter);
+
+        // Enter select printer activity
+        selectPrinter("All printers…");
+
+        assertFalse(trackedPrinters.contains(PRINTER_NAME));
+
+        InfoActivity.addObserver(activity -> {
+            Intent intent = activity.getIntent();
+
+            assertEquals(PRINTER_NAME, intent.getStringExtra("PRINTER_NAME"));
+            assertTrue(intent.getBooleanExtra(PrintService.EXTRA_CAN_SELECT_PRINTER,
+                            false));
+
+            activity.setResult(Activity.RESULT_OK,
+                    (new Intent()).putExtra(PrintService.EXTRA_SELECT_PRINTER, true));
+            activity.finish();
+        });
+
+        // Open info activity which executed the code above
+        UiObject moreInfoButton = getUiDevice().findObject(new UiSelector().resourceId(
+                "com.android.printspooler:id/more_info"));
+        moreInfoButton.click();
+
+        // Wait until printer is selected and thereby tracked
+        eventually(() -> assertTrue(trackedPrinters.contains(PRINTER_NAME)));
+
+        InfoActivity.clearObservers();
+
+        getUiDevice().pressBack();
+        getUiDevice().pressBack();
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
     }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
new file mode 100644
index 0000000..9b277e9
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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.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;
+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.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+import android.util.Log;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import static android.print.cts.Utils.runOnMainThread;
+
+/**
+ * This test verifies changes to the printer capabilities are applied correctly.
+ */
+@RunWith(Parameterized.class)
+public class PrinterCapabilitiesChangeTest extends BasePrintTest {
+    private static final String LOG_TAG = "PrinterCapChangeTest";
+    private static final String PRINTER_NAME = "Test printer";
+
+    private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
+    private static final Resolution RESOLUTION_300 =
+            new Resolution("300", "300", 300, 300);
+
+    private boolean mAvailBefore;
+    private MediaSize mMsBefore;
+    private boolean mAvailAfter;
+    private MediaSize mMsAfter;
+
+    private final StubbablePrinterDiscoverySession[] mSession = new StubbablePrinterDiscoverySession[1];
+    private final PrinterId[] mPrinterId = new PrinterId[1];
+    private final PrintAttributes[] mLayoutAttributes = new PrintAttributes[1];
+    private final PrintAttributes[] mWriteAttributes = new PrintAttributes[1];
+    private PrintDocumentAdapter mAdapter;
+    private static boolean sHasDefaultPrinterBeenSet;
+
+    /**
+     * Generate a new list of printers containing a singer printer with the given media size and
+     * status. The other capabilities are default values.
+     *
+     * @param printerId The id of the printer
+     * @param mediaSize The media size to use
+     * @param status    The status of th printer
+     *
+     * @return The list of printers
+     */
+    private List<PrinterInfo> generatePrinters(PrinterId printerId, MediaSize mediaSize,
+            int status) {
+        List<PrinterInfo> printers = new ArrayList<>(1);
+
+        PrinterCapabilitiesInfo cap;
+
+        if (mediaSize != null) {
+            PrinterCapabilitiesInfo.Builder builder = new PrinterCapabilitiesInfo.Builder(
+                    printerId);
+            builder.setMinMargins(DEFAULT_MARGINS)
+                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                            PrintAttributes.COLOR_MODE_COLOR)
+                    .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
+                            PrintAttributes.DUPLEX_MODE_NONE)
+                    .addMediaSize(mediaSize, true)
+                    .addResolution(RESOLUTION_300, true);
+            cap = builder.build();
+        } else {
+            cap = null;
+        }
+
+        printers.add(new PrinterInfo.Builder(printerId, PRINTER_NAME, status).setCapabilities(cap)
+                .build());
+
+        return printers;
+    }
+
+    /**
+     * Wait until the print activity requested an update with print attributes matching the media
+     * size.
+     *
+     * @param printAttributes The print attributes container
+     * @param mediaSize       The media size to match
+     *
+     * @throws Exception If anything unexpected happened, e.g. the attributes did not change.
+     */
+    private void waitForMediaSizeChange(PrintAttributes[] printAttributes, MediaSize mediaSize)
+            throws Exception {
+        synchronized (PrinterCapabilitiesChangeTest.this) {
+            long endTime = System.currentTimeMillis() + OPERATION_TIMEOUT_MILLIS;
+            while (printAttributes[0] == null ||
+                    !printAttributes[0].getMediaSize().equals(mediaSize)) {
+                wait(Math.max(0, endTime - System.currentTimeMillis()));
+
+                if (endTime < System.currentTimeMillis()) {
+                    throw new TimeoutException(
+                            "Print attributes did not change to " + mediaSize + " in " +
+                                    OPERATION_TIMEOUT_MILLIS + " ms. Current attributes"
+                                    + printAttributes[0]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Change the media size of the capabilities of the printer
+     *
+     * @param session     The mSession used in the test
+     * @param printerId   The printer to change
+     * @param mediaSize   The new mediaSize to apply
+     * @param isAvailable If the printer should be available or not
+     */
+    private void changeCapabilities(final StubbablePrinterDiscoverySession session,
+            final PrinterId printerId, final MediaSize mediaSize, final boolean isAvailable)
+            throws Throwable {
+        runOnMainThread(
+                () -> session.addPrinters(generatePrinters(printerId, mediaSize, isAvailable ?
+                        PrinterInfo.STATUS_IDLE :
+                        PrinterInfo.STATUS_UNAVAILABLE)));
+    }
+
+    /**
+     * Wait until the message is shown that indicates that a printer is unavilable.
+     *
+     * @throws Exception If anything was unexpected.
+     */
+    private void waitForPrinterUnavailable() throws Exception {
+        final String PRINTER_UNAVAILABLE_MSG =
+                getPrintSpoolerString("print_error_printer_unavailable");
+
+        UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
+                "com.android.printspooler:id/message"));
+        if (!message.getText().equals(PRINTER_UNAVAILABLE_MSG)) {
+            throw new Exception("Wrong message: " + message.getText() + " instead of " +
+                    PRINTER_UNAVAILABLE_MSG);
+        }
+    }
+
+    @Before
+    public void setUpPrinting() throws Exception {
+        // Create the mSession[0] callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(invocation -> {
+                    mSession[0] = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
+                            .getSession();
+
+                    mPrinterId[0] = mSession[0].getService().generatePrinterId(PRINTER_NAME);
+
+                    mSession[0].addPrinters(generatePrinters(mPrinterId[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(
+                invocation -> firstSessionCallbacks, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        mAdapter = createMockPrintDocumentAdapter(
+                invocation -> {
+                    LayoutResultCallback callback = (LayoutResultCallback) invocation
+                            .getArguments()[3];
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                            .setPageCount(1)
+                            .build();
+
+                    synchronized (PrinterCapabilitiesChangeTest.this) {
+                        mLayoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+
+                        PrinterCapabilitiesChangeTest.this.notify();
+                    }
+
+                    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(mLayoutAttributes[0], fd, pages[0].getStart(),
+                            pages[0].getEnd());
+                    fd.close();
+
+                    synchronized (PrinterCapabilitiesChangeTest.this) {
+                        mWriteAttributes[0] = mLayoutAttributes[0];
+
+                        PrinterCapabilitiesChangeTest.this.notify();
+                    }
+
+                    callback.onWriteFinished(pages);
+
+                    onWriteCalled();
+                    return null;
+                }, null);
+
+        if (!sHasDefaultPrinterBeenSet) {
+            makeDefaultPrinter(mAdapter, PRINTER_NAME);
+            sHasDefaultPrinterBeenSet = true;
+        }
+
+        resetCounters();
+    }
+
+    @Test
+    public void changeCapabilities() throws Throwable {
+        Log.i(LOG_TAG, "Test case: " + mAvailBefore + ", " + mMsBefore + " -> " + mAvailAfter + ", "
+                + mMsAfter);
+
+        // Start printing.
+        print(mAdapter);
+
+        waitForWriteAdapterCallback(1);
+
+        changeCapabilities(mSession[0], mPrinterId[0], mMsBefore, mAvailBefore);
+        if (mAvailBefore && mMsBefore != null) {
+            waitForMediaSizeChange(mLayoutAttributes, mMsBefore);
+            waitForMediaSizeChange(mWriteAttributes, mMsBefore);
+        } else {
+            waitForPrinterUnavailable();
+        }
+
+        changeCapabilities(mSession[0], mPrinterId[0], mMsAfter, mAvailAfter);
+        if (mAvailAfter && mMsAfter != null) {
+            waitForMediaSizeChange(mLayoutAttributes, mMsAfter);
+            waitForMediaSizeChange(mWriteAttributes, mMsAfter);
+        } else {
+            waitForPrinterUnavailable();
+        }
+
+        // Reset printer to default in case discovery mSession is reused
+        changeCapabilities(mSession[0], mPrinterId[0], MediaSize.NA_LETTER, true);
+        waitForMediaSizeChange(mLayoutAttributes, MediaSize.NA_LETTER);
+        waitForMediaSizeChange(mWriteAttributes, MediaSize.NA_LETTER);
+
+        getUiDevice().pressBack();
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> getParameters() {
+        ArrayList<Object[]> parameters = new ArrayList<>();
+
+        parameters.add(new Object[]{false, null, false, null});
+        parameters.add(new Object[]{false, null, false, MediaSize.ISO_A0});
+        parameters.add(new Object[]{false, null, false, MediaSize.ISO_B0});
+        parameters.add(new Object[]{false, null, true, null});
+        parameters.add(new Object[]{false, null, true, MediaSize.ISO_A0});
+        parameters.add(new Object[]{false, null, true, MediaSize.ISO_B0});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, false, null});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, false, MediaSize.ISO_A0});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, false, MediaSize.ISO_B0});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, true, null});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, true, MediaSize.ISO_A0});
+        parameters.add(new Object[]{false, MediaSize.ISO_A0, true, MediaSize.ISO_B0});
+        parameters.add(new Object[]{true, null, false, null});
+        parameters.add(new Object[]{true, null, false, MediaSize.ISO_B0});
+        parameters.add(new Object[]{true, null, true, null});
+        parameters.add(new Object[]{true, null, true, MediaSize.ISO_B0});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, false, null});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, false, MediaSize.ISO_A0});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, false, MediaSize.ISO_B0});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, true, null});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, true, MediaSize.ISO_A0});
+        parameters.add(new Object[]{true, MediaSize.ISO_A0, true, MediaSize.ISO_B0});
+
+        return parameters;
+    }
+
+    public PrinterCapabilitiesChangeTest(boolean availBefore, MediaSize msBefore,
+            boolean availAfter, MediaSize msAfter) {
+        mAvailBefore = availBefore;
+        mMsBefore = msBefore;
+        mAvailAfter = availAfter;
+        mMsAfter = msAfter;
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
index 8e3f984..3ea03af 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
@@ -34,23 +34,22 @@
 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
 import android.print.cts.services.SecondPrintService;
 import android.print.cts.services.StubbablePrinterDiscoverySession;
-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 android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
+import static android.print.cts.Utils.assertException;
+import static org.junit.Assert.*;
+
 /**
  * This test verifies changes to the printer capabilities are applied correctly.
  */
+@RunWith(AndroidJUnit4.class)
 public class PrinterCapabilitiesTest extends BasePrintTest {
-    private static final String LOG_TAG = "PrinterCapabilitiesTest";
     private static final String PRINTER_NAME = "Test printer";
 
     private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
@@ -58,413 +57,104 @@
             new PrintAttributes.Resolution("300", "300", 300, 300);
     private static final PrintAttributes.Resolution RESOLUTION_600 =
             new PrintAttributes.Resolution("600", "600", 600, 600);
-
-    /**
-     * Generate a new list of printers containing a singer printer with the given media size and
-     * status. The other capabilities are default values.
-     *
-     * @param printerId The id of the printer
-     * @param mediaSize The media size to use
-     * @param status    The status of th printer
-     *
-     * @return The list of printers
-     */
-    private List<PrinterInfo> generatePrinters(PrinterId printerId, MediaSize mediaSize,
-            int status) {
-        List<PrinterInfo> printers = new ArrayList<>(1);
-
-        PrinterCapabilitiesInfo cap;
-
-        if (mediaSize != null) {
-            PrinterCapabilitiesInfo.Builder builder = new PrinterCapabilitiesInfo.Builder(
-                    printerId);
-            builder.setMinMargins(DEFAULT_MARGINS)
-                    .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
-                            PrintAttributes.COLOR_MODE_COLOR)
-                    .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
-                            PrintAttributes.DUPLEX_MODE_NONE)
-                    .addMediaSize(mediaSize, true)
-                    .addResolution(RESOLUTION_300, true);
-            cap = builder.build();
-        } else {
-            cap = null;
-        }
-
-        printers.add(new PrinterInfo.Builder(printerId, PRINTER_NAME, status).setCapabilities(cap)
-                .build());
-
-        return printers;
-    }
-
-    /**
-     * Wait until the print activity requested an update with print attributes matching the media
-     * size.
-     *
-     * @param printAttributes The print attributes container
-     * @param mediaSize       The media size to match
-     *
-     * @throws Exception If anything unexpected happened, e.g. the attributes did not change.
-     */
-    private void waitForMediaSizeChange(PrintAttributes[] printAttributes, MediaSize mediaSize)
-            throws Exception {
-        synchronized (PrinterCapabilitiesTest.this) {
-            long endTime = System.currentTimeMillis() + OPERATION_TIMEOUT_MILLIS;
-            while (printAttributes[0] == null ||
-                    !printAttributes[0].getMediaSize().equals(mediaSize)) {
-                wait(Math.max(0, endTime - System.currentTimeMillis()));
-
-                if (endTime < System.currentTimeMillis()) {
-                    throw new TimeoutException(
-                            "Print attributes did not change to " + mediaSize + " in " +
-                                    OPERATION_TIMEOUT_MILLIS + " ms. Current attributes"
-                                    + printAttributes[0]);
-                }
-            }
-        }
-    }
-
-    /**
-     * Change the media size of the capabilities of the printer
-     *
-     * @param session     The session used in the test
-     * @param printerId   The printer to change
-     * @param mediaSize   The new mediaSize to apply
-     * @param isAvailable If the printer should be available or not
-     */
-    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 ?
-                        PrinterInfo.STATUS_IDLE :
-                        PrinterInfo.STATUS_UNAVAILABLE));
-            }
-        });
-    }
-
-    /**
-     * Wait until the message is shown that indicates that a printer is unavilable.
-     *
-     * @throws Exception If anything was unexpected.
-     */
-    private void waitForPrinterUnavailable() throws Exception {
-        final String PRINTER_UNAVAILABLE_MSG = "This printer isn't available right now.";
-
-        UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
-                "com.android.printspooler:id/message"));
-        if (!message.getText().equals(PRINTER_UNAVAILABLE_MSG)) {
-            throw new Exception("Wrong message: " + message.getText() + " instead of " +
-                    PRINTER_UNAVAILABLE_MSG);
-        }
-    }
-
-    /**
-     * A single test case from {@link #testPrinterCapabilityChange}. Tests a single capability
-     * change.
-     *
-     * @param session     The session used in  the test
-     * @param printerId   The ID of the test printer
-     * @param availBefore If the printer should be available before the change
-     * @param msBefore    The media size of the printer before the change
-     * @param availAfter  If the printer should be available after the change
-     * @param msAfter     The media size of the printer after the change
-     *
-     * @throws Exception If anything is unexpected
-     */
-    private void testCase(final StubbablePrinterDiscoverySession[] session,
-            final PrinterId[] printerId, final boolean availBefore, final MediaSize msBefore,
-            final boolean availAfter, final MediaSize msAfter) throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
-        Log.i(LOG_TAG, "Test case: " + availBefore + ", " + msBefore + " -> " + availAfter + ", "
-                + msAfter);
-
-        final PrintAttributes[] layoutAttributes = new PrintAttributes[1];
-        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();
-
-                        synchronized (PrinterCapabilitiesTest.this) {
-                            layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
-
-                            PrinterCapabilitiesTest.this.notify();
-                        }
-
-                        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(layoutAttributes[0], fd, pages[0].getStart(),
-                                pages[0].getEnd());
-                        fd.close();
-
-                        synchronized (PrinterCapabilitiesTest.this) {
-                            writeAttributes[0] = layoutAttributes[0];
-
-                            PrinterCapabilitiesTest.this.notify();
-                        }
-
-                        callback.onWriteFinished(pages);
-                        return null;
-                    }
-                }, null);
-
-        // Start printing.
-        print(adapter);
-
-        // Select the printer.
-        selectPrinter(PRINTER_NAME);
-
-        changeCapabilities(session[0], printerId[0], msBefore, availBefore);
-        if (availBefore && msBefore != null) {
-            waitForMediaSizeChange(layoutAttributes, msBefore);
-            waitForMediaSizeChange(writeAttributes, msBefore);
-        } else {
-            waitForPrinterUnavailable();
-        }
-
-        changeCapabilities(session[0], printerId[0], msAfter, availAfter);
-        if (availAfter && msAfter != null) {
-            waitForMediaSizeChange(layoutAttributes, msAfter);
-            waitForMediaSizeChange(writeAttributes, msAfter);
-        } else {
-            waitForPrinterUnavailable();
-        }
-
-        // Reset printer to default in case discovery session is reused
-        changeCapabilities(session[0], printerId[0], MediaSize.NA_LETTER, true);
-        waitForMediaSizeChange(layoutAttributes, MediaSize.NA_LETTER);
-        waitForMediaSizeChange(writeAttributes, MediaSize.NA_LETTER);
-
-        getUiDevice().pressBack();
-
-        // Wait until PrintActivity is gone
-        Thread.sleep(500);
-    }
-
-    /**
-     * Tests that the printActivity propertly requests (layout and write) updates when the printer
-     * capabilities change. This tests all combination of changes.
-     *
-     * @throws Exception If something is unexpected.
-     */
-    public void testPrinterCapabilityChange() throws Exception {
-        // The session might be reused between test cases, hence carry them from test case to case
-        final StubbablePrinterDiscoverySession[] session = new StubbablePrinterDiscoverySession[1];
-        final PrinterId[] printerId = new PrinterId[1];
-
-        // 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();
-
-                        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;
-                    }
-                });
-
-        // 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);
-
-        // Configure the print services.
-        FirstPrintService.setCallbacks(firstServiceCallbacks);
-        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
-
-        testCase(session, printerId, false, null, false, null);
-        testCase(session, printerId, false, null, false, MediaSize.ISO_A0);
-        testCase(session, printerId, false, null, false, MediaSize.ISO_B0);
-        testCase(session, printerId, false, null, true, null);
-        testCase(session, printerId, false, null, true, MediaSize.ISO_A0);
-        testCase(session, printerId, false, null, true, MediaSize.ISO_B0);
-        testCase(session, printerId, false, MediaSize.ISO_A0, false, null);
-        testCase(session, printerId, false, MediaSize.ISO_A0, false, MediaSize.ISO_A0);
-        testCase(session, printerId, false, MediaSize.ISO_A0, false, MediaSize.ISO_B0);
-        testCase(session, printerId, false, MediaSize.ISO_A0, true, null);
-        testCase(session, printerId, false, MediaSize.ISO_A0, true, MediaSize.ISO_A0);
-        testCase(session, printerId, false, MediaSize.ISO_A0, true, MediaSize.ISO_B0);
-        testCase(session, printerId, true, null, false, null);
-        testCase(session, printerId, true, null, false, MediaSize.ISO_B0);
-        testCase(session, printerId, true, null, true, null);
-        testCase(session, printerId, true, null, true, MediaSize.ISO_B0);
-        testCase(session, printerId, true, MediaSize.ISO_A0, false, null);
-        testCase(session, printerId, true, MediaSize.ISO_A0, false, MediaSize.ISO_A0);
-        testCase(session, printerId, true, MediaSize.ISO_A0, false, MediaSize.ISO_B0);
-        testCase(session, printerId, true, MediaSize.ISO_A0, true, null);
-        testCase(session, printerId, true, MediaSize.ISO_A0, true, MediaSize.ISO_A0);
-        testCase(session, printerId, true, MediaSize.ISO_A0, true, MediaSize.ISO_B0);
-
-        waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
-    }
-
-    /**
-     * 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");
-    }
+    private static boolean sDefaultPrinterBeenSet;
 
     /**
      * That that you cannot create illegal PrinterCapabilityInfos.
      *
      * @throws Exception If anything is unexpected
      */
-    public void testIllegalPrinterCapabilityInfos() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
+    @Test
+    public void illegalPrinterCapabilityInfos() throws Exception {
         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);
@@ -487,97 +177,117 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testSanePrinterCapabilityInfos() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
+    @Test
+    public void sanePrinterCapabilityInfos() throws Exception {
         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);
@@ -603,47 +313,32 @@
      */
     private void testPrinterCapabilityInfo(final Function<PrinterId, PrinterCapabilitiesInfo>
             capBuilder, Consumer<PrintAttributes> test) throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
-
         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 +347,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.
@@ -689,12 +378,17 @@
         // make sure that options does not crash
         openPrintOptions();
 
-        // Select printer under test
-        selectPrinter(PRINTER_NAME);
+        if (!sDefaultPrinterBeenSet) {
+            // Select printer under test
+            selectPrinter(PRINTER_NAME);
+        }
 
         clickPrintButton();
 
-        answerPrintServicesWarning(true);
+        if (!sDefaultPrinterBeenSet) {
+            answerPrintServicesWarning(true);
+            sDefaultPrinterBeenSet = true;
+        }
 
         test.accept(layoutAttributes[0]);
 
@@ -707,7 +401,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testInvalidDefaultColor() throws Exception {
+    @Test
+    public void invalidDefaultColor() throws Exception {
         testPrinterCapabilityInfo(
                 (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
                         .addMediaSize(MediaSize.ISO_A4, true)
@@ -724,7 +419,8 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testInvalidDefaultDuplexMode() throws Exception {
+    @Test
+    public void invalidDefaultDuplexMode() throws Exception {
         testPrinterCapabilityInfo(
                 (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
                         .addMediaSize(MediaSize.ISO_A4, true)
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index defbee3..499d21e 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.*;
+import static org.junit.Assert.*;
 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;
@@ -39,10 +36,12 @@
 import android.printservice.PrintJob;
 import android.printservice.PrinterDiscoverySession;
 
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 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;
@@ -52,6 +51,7 @@
  * This test verifies that the system respects the {@link PrinterDiscoverySession}
  * contract is respected.
  */
+@RunWith(AndroidJUnit4.class)
 public class PrinterDiscoverySessionLifecycleTest extends BasePrintTest {
     private static final String FIRST_PRINTER_NAME = "First printer";
     private static final String SECOND_PRINTER_NAME = "Second printer";
@@ -59,38 +59,35 @@
     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 {
-        if (!supportsPrinting()) {
-            return;
-        }
+    private static StubbablePrinterDiscoverySession sSession;
+
+    @Before
+    public void clearPrintSpoolerState() throws Exception {
+        clearPrintSpoolerData();
+    }
+
+    @Test
+    public void normalLifecycle() throws Throwable {
         // Create the session callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
                 createFirstMockPrinterDiscoverySessionCallbacks();
 
         // 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 +95,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 +113,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 +137,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,30 +172,20 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
-    public void testCancelPrintServicesAlertDialog() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
+    @Test
+    public void cancelPrintServicesAlertDialog() throws Throwable {
         // Create the session callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
                 createFirstMockPrinterDiscoverySessionCallbacks();
 
         // 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 +193,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 +201,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 +235,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,38 +262,28 @@
         inOrder.verify(firstSessionCallbacks).onDestroy();
     }
 
-    public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
+    @Test
+    public void startPrinterDiscoveryWithHistoricalPrinters() throws Throwable {
         // Create the session callbacks that we will be checking.
         final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
                 createFirstMockPrinterDiscoverySessionCallbacks();
 
         // 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 +291,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 +311,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 +339,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 +388,83 @@
         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());
-            }
+    @Test
+    public void addRemovePrinters() throws Throwable {
+        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 +484,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..415ace8 100644
--- a/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
@@ -19,17 +19,11 @@
 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;
 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;
@@ -38,13 +32,12 @@
 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.runner.AndroidJUnit4;
 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 org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -52,70 +45,12 @@
 /**
  * Tests all allowed types of printerInfo
  */
+@RunWith(AndroidJUnit4.class)
 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 +65,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 +285,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 +305,7 @@
     private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
             final PrinterDiscoverySessionCallbacks sessionCallbacks) {
         return createMockPrintServiceCallbacks(
-                new Answer<PrinterDiscoverySessionCallbacks>() {
-                    @Override
-                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
-                        return sessionCallbacks;
-                    }
-                },
+                invocation -> sessionCallbacks,
                 null, null);
     }
 
@@ -406,11 +314,8 @@
      *
      * @throws Exception If anything is unexpected.
      */
-    public void testPrinterInfos()
-            throws Exception {
-        if (!supportsPrinting()) {
-            return;
-        }
+    @Test
+    public void printerInfos() throws Exception {
         // Create the session of the printers that we will be checking.
         PrinterDiscoverySessionCallbacks sessionCallbacks
                 = createFirstMockPrinterDiscoverySessionCallbacks();
@@ -426,7 +331,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/InfoActivity.java b/tests/tests/print/src/android/print/cts/services/InfoActivity.java
new file mode 100644
index 0000000..22c1bb5
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/InfoActivity.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 android.print.cts.services;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.Observable;
+
+public class InfoActivity extends Activity {
+    public interface Observer {
+        void onCreate(Activity createdActivity);
+    }
+
+    private static final ArrayList<Observer> sObservers = new ArrayList<>();
+
+    public static void addObserver(Observer observer) {
+        synchronized (sObservers) {
+            sObservers.add(observer);
+        }
+    }
+
+    public static void clearObservers() {
+        synchronized (sObservers) {
+            sObservers.clear();
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        synchronized (sObservers) {
+            ArrayList<Observer> observers = (ArrayList<Observer>) sObservers.clone();
+
+            for (Observer observer : observers) {
+                observer.onCreate(this);
+            }
+        }
+    }
+}
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..344bcfc
--- /dev/null
+++ b/tests/tests/print/src/android/print/pdf/cts/PrintedPdfDocumentTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.BeforeClass;
+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 static Context sContext;
+
+    @BeforeClass
+    public static void setUp() {
+        sContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    @Test
+    public void createWithNullAttributes() throws Throwable {
+        assertException(() -> new PrintedPdfDocument(sContext, null), NullPointerException.class);
+    }
+
+    @Test
+    public void createWithNullMediaSize() throws Throwable {
+        PrintAttributes attr = new PrintAttributes.Builder().setMinMargins(ZERO_MARGINS).build();
+        assertException(() -> new PrintedPdfDocument(sContext, attr), NullPointerException.class);
+    }
+
+    @Test
+    public void createWithNullMargins() throws Throwable {
+        PrintAttributes attr = new PrintAttributes.Builder()
+                .setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
+        assertException(() -> new PrintedPdfDocument(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, 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(sContext, attr);
+        doc.close();
+        assertEquals(new Rect(0, 0, milsToPts(attr.getMediaSize().getWidthMils()),
+                milsToPts(attr.getMediaSize().getHeightMils())), doc.getPageContentRect());
+    }
+}
diff --git a/tests/tests/proto/Android.mk b/tests/tests/proto/Android.mk
new file mode 100644
index 0000000..23dba67
--- /dev/null
+++ b/tests/tests/proto/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-proto-files-under, src)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_PACKAGE_NAME := CtsProtoTestCases
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+#LOCAL_SDK_VERSION := current
+LOCAL_JAVA_LIBRARIES += android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        ctstestrunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/proto/AndroidManifest.xml b/tests/tests/proto/AndroidManifest.xml
new file mode 100644
index 0000000..b8af5d0
--- /dev/null
+++ b/tests/tests/proto/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.util.proto.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".Whatever" />
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.util.proto.cts"
+                     android:label="CTS tests of android.util.proto">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/proto/AndroidTest.xml b/tests/tests/proto/AndroidTest.xml
new file mode 100644
index 0000000..1395739
--- /dev/null
+++ b/tests/tests/proto/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for OS Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsOsTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.util.proto.cts" />
+        <option name="runtime-hint" value="5s" />
+    </test>
+</configuration>
diff --git a/tests/tests/proto/src/android/util/proto/cts/EncodedBufferTest.java b/tests/tests/proto/src/android/util/proto/cts/EncodedBufferTest.java
new file mode 100644
index 0000000..e29bb21
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/EncodedBufferTest.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.util.proto.cts;
+
+import android.util.proto.EncodedBuffer;
+
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the EncodedBuffer class.
+ *
+ * Most of the tests here operate on an EncodedBuffer with two different chunk sizes,
+ * the default size, which checks that the code is operating as it usually does, and
+ * with the chunk size set to 1, which forces the boundary condition at the write of
+ * every byte.
+ */
+public class EncodedBufferTest extends TestCase {
+    private static final String TAG = "EncodedBufferTest";
+
+    public void assertEquals(byte[] expected, EncodedBuffer actual) {
+        if (expected == null) {
+            expected = new byte[0];
+        }
+        assertEquals("actual.getWritePos() == expected.length", expected.length,
+                actual.getWritePos());
+        Assert.assertArrayEquals(expected, actual.getBytes(expected.length));
+    }
+
+    /**
+     * Tests that a variety of chunk sizes advance the chunks correctly.
+     */
+    public void testWriteRawByteWrapsChunks() throws Exception {
+        EncodedBuffer buffer;
+
+        buffer = new EncodedBuffer(1);
+        for (int i=0; i<100; i++) {
+            buffer.writeRawByte((byte)i);
+        }
+        assertEquals(100, buffer.getChunkCount());
+        assertEquals(99, buffer.getWriteBufIndex());
+        assertEquals(1, buffer.getWriteIndex());
+
+        buffer = new EncodedBuffer(50);
+        for (int i=0; i<100; i++) {
+            buffer.writeRawByte((byte)i);
+        }
+        assertEquals(2, buffer.getChunkCount());
+        assertEquals(1, buffer.getWriteBufIndex());
+        assertEquals(50, buffer.getWriteIndex());
+
+        buffer = new EncodedBuffer(50);
+        for (int i=0; i<101; i++) {
+            buffer.writeRawByte((byte)i);
+        }
+        assertEquals(3, buffer.getChunkCount());
+        assertEquals(2, buffer.getWriteBufIndex());
+        assertEquals(1, buffer.getWriteIndex());
+
+        buffer = new EncodedBuffer();
+        for (int i=0; i<100; i++) {
+            buffer.writeRawByte((byte)i);
+        }
+        assertEquals(1, buffer.getChunkCount());
+        assertEquals(0, buffer.getWriteBufIndex());
+        assertEquals(100, buffer.getWriteIndex());
+    }
+
+    /**
+     * Tests that writeRawBytes writes what is expected.
+     */
+    public void testWriteRawBuffer() throws Exception {
+        testWriteRawBuffer(0);
+        testWriteRawBuffer(1);
+        testWriteRawBuffer(5);
+    }
+
+    public void testWriteRawBuffer(int chunkSize) throws Exception {
+        testWriteRawBuffer(chunkSize, 0);
+        testWriteRawBuffer(chunkSize, 1);
+        testWriteRawBuffer(chunkSize, 3);
+        testWriteRawBuffer(chunkSize, 5);
+        testWriteRawBuffer(chunkSize, 7);
+        testWriteRawBuffer(chunkSize, 1024);
+        testWriteRawBuffer(chunkSize, 1024*1024);
+    }
+
+    public void testWriteRawBuffer(int chunkSize, int bufferSize) throws Exception {
+        final EncodedBuffer buffer = new EncodedBuffer(chunkSize);
+
+        final byte[] data = bufferSize > 0 ? new byte[bufferSize] : null;
+        final byte[] expected = bufferSize > 0 ? new byte[bufferSize] : null;
+        for (int i=0; i<bufferSize; i++) {
+            data[i] = (byte)i;
+            expected[i] = (byte)i;
+        }
+
+        buffer.writeRawBuffer(data);
+
+        // Make sure it didn't touch the original array
+        Assert.assertArrayEquals(expected, data);
+
+        // Make sure it wrote the array correctly
+        assertEquals(data, buffer);
+    }
+
+    /**
+     * Tests that writeRawBytes writes what is expected.
+     */
+    public void testWriteRawByte() throws Exception {
+        testWriteRawByte(0);
+        testWriteRawByte(1);
+    }
+
+    public void testWriteRawByte(int chunkSize) throws Exception {
+        final EncodedBuffer buffer = new EncodedBuffer(chunkSize);
+
+        buffer.writeRawByte((byte)0);
+        buffer.writeRawByte((byte)42);
+        buffer.writeRawByte((byte)127);
+        buffer.writeRawByte((byte)-128);
+
+        assertEquals(new byte[] { 0, 42, 127, -128 }, buffer);
+    }
+
+    /**
+     * Tests the boundary conditions of getRawVarint32Size.
+     */
+    public void testGetRawUnsigned32Size() throws Exception {
+        assertEquals(1, EncodedBuffer.getRawVarint32Size(0));
+        assertEquals(1, EncodedBuffer.getRawVarint32Size(0x0000007f));
+        assertEquals(2, EncodedBuffer.getRawVarint32Size(0x00000080));
+        assertEquals(2, EncodedBuffer.getRawVarint32Size(0x00003fff));
+        assertEquals(3, EncodedBuffer.getRawVarint32Size(0x00004000));
+        assertEquals(3, EncodedBuffer.getRawVarint32Size(0x001fffff));
+        assertEquals(4, EncodedBuffer.getRawVarint32Size(0x00200000));
+        assertEquals(4, EncodedBuffer.getRawVarint32Size(0x0fffffff));
+        assertEquals(5, EncodedBuffer.getRawVarint32Size(0x10000000));
+        assertEquals(5, EncodedBuffer.getRawVarint32Size(0xffffffff));
+    }
+
+    /**
+     * Tests that writeRawVarint32 writes what is expected.
+     */
+    public void testWriteRawVarint32() throws Exception {
+        testWriteRawVarint32(0);
+        testWriteRawVarint32(1);
+    }
+
+    public void testWriteRawVarint32(int chunkSize) throws Exception {
+        final EncodedBuffer buffer = new EncodedBuffer(chunkSize);
+
+        buffer.writeRawVarint32(0);
+        buffer.writeRawVarint32(0x0000007f << (7 * 0));
+        buffer.writeRawVarint32(0x0000007f << (7 * 1));
+        buffer.writeRawVarint32(0x0000007f << (7 * 2));
+        buffer.writeRawVarint32(0x0000007f << (7 * 3));
+        buffer.writeRawVarint32(0xf0000000);
+        buffer.writeRawVarint32(-1);
+        buffer.writeRawVarint32(Integer.MIN_VALUE);
+        buffer.writeRawVarint32(Integer.MAX_VALUE);
+
+        assertEquals(new byte[] { 
+                (byte)0x00,                                                 // 0
+                (byte)0x7f,                                                 // 0x7f << (7 * 0)
+                (byte)0x80, (byte)0x7f,                                     // 0x7f << (7 * 1)
+                (byte)0x80, (byte)0x80, (byte)0x7f,                         // 0x7f << (7 * 2)
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x7f,             // 0x7f << (7 * 3)
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x0f, // 0xf0000000
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f, // 0xffffffff
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08, // 0x80000000
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, // 0x7fffffff
+                }, buffer);
+    }
+
+    /**
+     * Tests the boundary conditions of getRawVarint64Size.
+     */
+    public void testGetRawVarint64Size() throws Exception {
+        assertEquals(1, EncodedBuffer.getRawVarint64Size(0));
+        assertEquals(1, EncodedBuffer.getRawVarint64Size(0x00000000000007fL));
+        assertEquals(2, EncodedBuffer.getRawVarint64Size(0x000000000000080L));
+        assertEquals(2, EncodedBuffer.getRawVarint64Size(0x000000000003fffL));
+        assertEquals(3, EncodedBuffer.getRawVarint64Size(0x000000000004000L));
+        assertEquals(3, EncodedBuffer.getRawVarint64Size(0x0000000001fffffL));
+        assertEquals(4, EncodedBuffer.getRawVarint64Size(0x000000000200000L));
+        assertEquals(4, EncodedBuffer.getRawVarint64Size(0x00000000fffffffL));
+        assertEquals(5, EncodedBuffer.getRawVarint64Size(0x000000010000000L));
+        assertEquals(5, EncodedBuffer.getRawVarint64Size(0x0000007ffffffffL));
+        assertEquals(6, EncodedBuffer.getRawVarint64Size(0x000000800000000L));
+        assertEquals(6, EncodedBuffer.getRawVarint64Size(0x00003ffffffffffL));
+        assertEquals(7, EncodedBuffer.getRawVarint64Size(0x000040000000000L));
+        assertEquals(7, EncodedBuffer.getRawVarint64Size(0x001ffffffffffffL));
+        assertEquals(8, EncodedBuffer.getRawVarint64Size(0x002000000000000L));
+        assertEquals(8, EncodedBuffer.getRawVarint64Size(0x0ffffffffffffffL));
+        assertEquals(9, EncodedBuffer.getRawVarint64Size(0x0100000000000000L));
+        assertEquals(9, EncodedBuffer.getRawVarint64Size(0x7fffffffffffffffL));
+        assertEquals(10, EncodedBuffer.getRawVarint64Size(0x8000000000000000L));
+        assertEquals(10, EncodedBuffer.getRawVarint64Size(0xffffffffffffffffL));
+    }
+
+    /**
+     * With chunk size 1: Tests that startEditing puts the EncodedBuffer into
+     * a state where the read and write pointers are reset, the ranges are set,
+     * and it is ready to read / rewrite.
+     */
+    public void testStartEditingChunkSize1() {
+        final byte[] DATA = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        final EncodedBuffer buffer = new EncodedBuffer(1);
+
+        buffer.writeRawBuffer(DATA);
+
+        // All the pointers are at the end of what we just wrote
+        assertEquals(DATA.length, buffer.getWritePos());
+        assertEquals(DATA.length-1, buffer.getWriteBufIndex());
+        assertEquals(1, buffer.getWriteIndex());
+        assertEquals(DATA.length, buffer.getChunkCount());
+        assertEquals(-1, buffer.getReadableSize());
+
+        buffer.startEditing();
+
+        // Should be reset
+        assertEquals(0, buffer.getWritePos());
+        assertEquals(0, buffer.getWriteBufIndex());
+        assertEquals(0, buffer.getWriteIndex());
+
+        // The data should still be there
+        assertEquals(DATA.length, buffer.getChunkCount());
+        assertEquals(DATA.length, buffer.getReadableSize());
+    }
+
+    /**
+     * With chunk size 100 (big enough to fit everything): Tests that
+     * startEditing puts the EncodedBuffer into a state where the read
+     * and write pointers are reset, the ranges are set, and it is ready
+     * to read / rewrite.
+     */
+    public void testStartEditingChunkSize100() {
+        final byte[] DATA = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        final EncodedBuffer buffer = new EncodedBuffer(100);
+
+        buffer.writeRawBuffer(DATA);
+
+        // All the pointers are at the end of what we just wrote
+        assertEquals(DATA.length, buffer.getWritePos());
+        assertEquals(0, buffer.getWriteBufIndex());
+        assertEquals(DATA.length, buffer.getWriteIndex());
+        assertEquals(1, buffer.getChunkCount());
+
+        // Not set yet
+        assertEquals(-1, buffer.getReadableSize());
+
+        buffer.startEditing();
+
+        // Should be reset
+        assertEquals(0, buffer.getWritePos());
+        assertEquals(0, buffer.getWriteBufIndex());
+        assertEquals(0, buffer.getWriteIndex());
+
+        // The data should still be there
+        assertEquals(1, buffer.getChunkCount());
+        assertEquals(DATA.length, buffer.getReadableSize());
+    }
+
+    /**
+     * Tests that writeFromThisBuffer writes what is expected.
+     */
+    public void testWriteFromThisBuffer() throws Exception {
+        testWriteFromThisBuffer(0);
+        testWriteFromThisBuffer(1);
+        testWriteFromThisBuffer(23);
+        testWriteFromThisBuffer(25);
+        testWriteFromThisBuffer(50);
+        testWriteFromThisBuffer(75);
+        testWriteFromThisBuffer(100);
+        testWriteFromThisBuffer(101);
+        testWriteFromThisBuffer(1000);
+    }
+
+    public void testWriteFromThisBuffer(int chunkSize) throws Exception {
+        testWriteFromThisBuffer(chunkSize, 0, 0, 0);
+        testWriteFromThisBuffer(chunkSize, 0, 0, 10);
+        testWriteFromThisBuffer(chunkSize, 0, 0, 100);
+        testWriteFromThisBuffer(chunkSize, 0, 1, 99);
+        testWriteFromThisBuffer(chunkSize, 0, 10, 10);
+        testWriteFromThisBuffer(chunkSize, 0, 10, 90);
+        testWriteFromThisBuffer(chunkSize, 0, 25, 25);
+        testWriteFromThisBuffer(chunkSize, 0, 50, 25);
+        testWriteFromThisBuffer(chunkSize, 0, 50, 50);
+
+        testWriteFromThisBufferFails(chunkSize, 0, 0, -1);
+        testWriteFromThisBufferFails(chunkSize, 0, 0, 101);
+        testWriteFromThisBufferFails(chunkSize, 0, 10, 100);
+        testWriteFromThisBufferFails(chunkSize, 10, 0, 0);
+        testWriteFromThisBufferFails(chunkSize, 10, 0, 1);
+        testWriteFromThisBufferFails(chunkSize, 10, 0, 89);
+        testWriteFromThisBufferFails(chunkSize, 10, 0, 90);
+    }
+
+    private void testWriteFromThisBuffer(int chunkSize, int destOffset, int srcOffset, int size)
+            throws Exception {
+        // Setup
+        final EncodedBuffer buffer = new EncodedBuffer(chunkSize);
+
+        // Input data: { 0 .. 99 }
+        final byte[] DATA = new byte[100];
+        final byte[] expected = new byte[DATA.length];
+        for (byte i=0; i<DATA.length; i++) {
+            DATA[i] = i;
+            expected[i] = i;
+        }
+        // This *should* be the same as System.arraycopy
+        System.arraycopy(expected, srcOffset, expected, destOffset, size);
+
+        buffer.writeRawBuffer(DATA);
+
+        buffer.startEditing();
+        Assert.assertArrayEquals(DATA, buffer.getBytes(buffer.getReadableSize()));
+
+
+        // Skip destOffset bytes (also tests that writing from offset 0 to offset 0 works).
+        if (destOffset != 0) {
+            buffer.writeFromThisBuffer(0, destOffset);
+            Assert.assertArrayEquals(DATA, buffer.getBytes(buffer.getReadableSize()));
+        }
+
+        // Test call
+        buffer.writeFromThisBuffer(srcOffset, size);
+
+        // Assert correctness
+        Assert.assertArrayEquals(expected, buffer.getBytes(buffer.getReadableSize()));
+        assertEquals(destOffset+size, buffer.getWritePos());
+    }
+
+    private void testWriteFromThisBufferFails(int chunkSize, int destOffset, int srcOffset,
+            int size) throws Exception {
+        try {
+            testWriteFromThisBuffer(chunkSize, destOffset, srcOffset, size);
+            throw new RuntimeException("Should have thorown an exception: "
+                    + " chunkSize=" + chunkSize + " destOffset=" + destOffset
+                    + " srcOffset=" + srcOffset + " size=" + size);
+        } catch (Exception ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBoolTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBoolTest.java
new file mode 100644
index 0000000..330e654
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBoolTest.java
@@ -0,0 +1,321 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the bool methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamBoolTest extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeBool
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeBool.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        po.writeBool(ProtoOutputStream.makeFieldId(1, fieldFlags), false);
+        po.writeBool(ProtoOutputStream.makeFieldId(2, fieldFlags), true);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(false);
+        testWriteCompat(true);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(boolean val) throws Exception {
+        final int fieldId = 130;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.boolField = val;
+        po.writeBool(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.boolField);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedBool
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeRepeatedBool.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        po.writeRepeatedBool(ProtoOutputStream.makeFieldId(1, fieldFlags), false);
+        po.writeRepeatedBool(ProtoOutputStream.makeFieldId(2, fieldFlags), true);
+
+        po.writeRepeatedBool(ProtoOutputStream.makeFieldId(1, fieldFlags), false);
+        po.writeRepeatedBool(ProtoOutputStream.makeFieldId(2, fieldFlags), true);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new boolean[0]);
+        testRepeatedCompat(new boolean[] { false, true });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(boolean[] val) throws Exception {
+        final int fieldId = 131;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.boolFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedBool(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.boolFieldRepeated);
+        assertEquals(val.length, readback.boolFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.boolFieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedBool
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writePackedBool.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedBool(ProtoOutputStream po, int fieldId, boolean val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BOOL;
+        po.writePackedBool(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new boolean[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        po.writePackedBool(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedBool(ProtoOutputStream.makeFieldId(1001, fieldFlags), new boolean[0]);
+        writePackedBool(po, 1, false);
+        writePackedBool(po, 2, true);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new boolean[] {});
+        testPackedCompat(new boolean[] { false, true });
+    }
+
+    /**
+     * Implementation of testPackedBoolCompat with a given value.
+     */
+    public void testPackedCompat(boolean[] val) throws Exception {
+        final int fieldId = 132;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BOOL;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.boolFieldPacked = val;
+        po.writePackedBool(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.boolFieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), false);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BOOL), false);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), false);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BOOL), false);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new boolean[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedBool(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BOOL),
+                    new boolean[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBytesTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBytesTest.java
new file mode 100644
index 0000000..ae323dd
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamBytesTest.java
@@ -0,0 +1,267 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the bytes methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamBytesTest extends TestCase {
+    private static byte[] makeData() {
+        final byte[] data = new byte[523];
+        for (int i=0; i<data.length; i++) {
+            data[i] = (byte)i;
+        }
+        return data;
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeBytes
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeBytes.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BYTES;
+
+        final byte[] data = makeData();
+
+        po.writeBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), data);
+
+        final byte[] expected = new byte[data.length + 3];
+        expected[0] = (byte)0x0a;
+        expected[1] = (byte)0x8b;
+        expected[2] = (byte)0x04;
+        for (int i=0; i<data.length; i++) {
+            expected[i+3] = (byte)i;
+        }
+
+        Assert.assertArrayEquals(expected, po.getBytes());
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        // Nano doesn't work with null.
+        // testWriteCompat(null);
+
+        testWriteCompat(new byte[0]);
+        testWriteCompat(new byte[] { 0 } );
+        testWriteCompat(new byte[] { 1 } );
+        testWriteCompat(makeData());
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(byte[] val) throws Exception {
+        final int fieldId = 150;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BYTES;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.bytesField = val;
+        po.writeBytes(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.bytesField);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedBytes
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeBytes.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BYTES;
+
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), null);
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(2, fieldFlags), new byte[0]);
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(3, fieldFlags),
+                new byte[] { 0, 1, 2, 3, 4, 5 });
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(4, fieldFlags),
+                new byte[] { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc });
+
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), null);
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(2, fieldFlags), new byte[0]);
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(3, fieldFlags),
+                new byte[] { 0, 1, 2, 3, 4, 5 });
+        po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(4, fieldFlags),
+                new byte[] { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc });
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> null - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte)0x12,
+                (byte)0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte)0x1a,
+                (byte)0x06,
+                (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte)0x22,
+                (byte)0x04,
+                (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc,
+
+                // 1 -> null - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x00,
+                // 2 -> { } - default value, written when repeated
+                (byte)0x12,
+                (byte)0x00,
+                // 3 -> { 0, 1, 2, 3, 4, 5 }
+                (byte)0x1a,
+                (byte)0x06,
+                (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05,
+                // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
+                (byte)0x22,
+                (byte)0x04,
+                (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new byte[0][]);
+        testRepeatedCompat(new byte[][] {
+                    new byte[0],
+                    new byte[] { 0 },
+                    new byte[] { 1 },
+                    makeData(),
+                });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(byte[][] val) throws Exception {
+        final int fieldId = 151;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BYTES;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.bytesFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.bytesFieldRepeated);
+        assertEquals(val.length, readback.bytesFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            Assert.assertArrayEquals(val[i], readback.bytesFieldRepeated[i]);
+        }
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeBytes(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new byte[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeBytes(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BYTES),
+                    new byte[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new byte[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BYTES),
+                    new byte[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamDoubleTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamDoubleTest.java
new file mode 100644
index 0000000..31a3adf
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamDoubleTest.java
@@ -0,0 +1,519 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the double methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamDoubleTest extends TestCase {
+    /**
+     * Compare if the values are identical (including handling for matching isNaN).
+     */
+    public void assertEquals(double expected, double actual) {
+        if (Double.isNaN(expected)) {
+            if (!Double.isNaN(actual)) {
+                throw new RuntimeException("expected NaN, actual " + actual);
+            }
+        } else {
+            if (expected != actual) {
+                throw new RuntimeException("expected " + expected + ", actual " + actual);
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeDouble
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeDouble.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+
+        po.writeDouble(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeDouble(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeDouble(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432);
+        po.writeDouble(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42);
+        po.writeDouble(ProtoOutputStream.makeFieldId(5, fieldFlags), Double.MIN_NORMAL);
+        po.writeDouble(ProtoOutputStream.makeFieldId(6, fieldFlags), Double.MIN_VALUE);
+        po.writeDouble(ProtoOutputStream.makeFieldId(7, fieldFlags), Double.NEGATIVE_INFINITY);
+        po.writeDouble(ProtoOutputStream.makeFieldId(8, fieldFlags), Double.NaN);
+        po.writeDouble(ProtoOutputStream.makeFieldId(9, fieldFlags), Double.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x19,
+                (byte)0x7d, (byte)0x3f, (byte)0x35, (byte)0x5e,
+                (byte)0xba, (byte)0x49, (byte)0x93, (byte)0xc0,
+                // 4 -> 42.42
+                (byte)0x21,
+                (byte)0xf6, (byte)0x28, (byte)0x5c, (byte)0x8f,
+                (byte)0xc2, (byte)0x35, (byte)0x45, (byte)0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte)0x29,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x31,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte)0x39,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0xff,
+                // 8 -> Double.NaN
+                (byte)0x41,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf8, (byte)0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte)0x49,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1234.432);
+        testWriteCompat(42.42);
+        testWriteCompat(Double.MIN_NORMAL);
+        testWriteCompat(Double.MIN_VALUE);
+        testWriteCompat(Double.NEGATIVE_INFINITY);
+        testWriteCompat(Double.NaN);
+        testWriteCompat(Double.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(double val) throws Exception {
+        final int fieldId = 10;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.doubleField = val;
+        po.writeDouble(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.doubleField);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedDouble
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeDouble.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(5, fieldFlags), Double.MIN_NORMAL);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(6, fieldFlags), Double.MIN_VALUE);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(7, fieldFlags), Double.NEGATIVE_INFINITY);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(8, fieldFlags), Double.NaN);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(9, fieldFlags), Double.POSITIVE_INFINITY);
+
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(5, fieldFlags), Double.MIN_NORMAL);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(6, fieldFlags), Double.MIN_VALUE);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(7, fieldFlags), Double.NEGATIVE_INFINITY);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(8, fieldFlags), Double.NaN);
+        po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(9, fieldFlags), Double.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x19,
+                (byte)0x7d, (byte)0x3f, (byte)0x35, (byte)0x5e,
+                (byte)0xba, (byte)0x49, (byte)0x93, (byte)0xc0,
+                // 4 -> 42.42
+                (byte)0x21,
+                (byte)0xf6, (byte)0x28, (byte)0x5c, (byte)0x8f,
+                (byte)0xc2, (byte)0x35, (byte)0x45, (byte)0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte)0x29,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x31,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte)0x39,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0xff,
+                // 8 -> Double.NaN
+                (byte)0x41,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf8, (byte)0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte)0x49,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x19,
+                (byte)0x7d, (byte)0x3f, (byte)0x35, (byte)0x5e,
+                (byte)0xba, (byte)0x49, (byte)0x93, (byte)0xc0,
+                // 4 -> 42.42
+                (byte)0x21,
+                (byte)0xf6, (byte)0x28, (byte)0x5c, (byte)0x8f,
+                (byte)0xc2, (byte)0x35, (byte)0x45, (byte)0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte)0x29,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x31,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte)0x39,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0xff,
+                // 8 -> Double.NaN
+                (byte)0x41,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf8, (byte)0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte)0x49,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new double[0]);
+        testRepeatedCompat(new double[] { 0, 1, -1234.432, 42.42,
+                    Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                    Double.POSITIVE_INFINITY,
+                });
+        }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(double[] val) throws Exception {
+        final int fieldId = 11;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.doubleFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.doubleFieldRepeated);
+        assertEquals(val.length, readback.doubleFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.doubleFieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedDouble
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeDouble.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedDouble(ProtoOutputStream po, int fieldId, double val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+        po.writePackedDouble(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new double[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        writePackedDouble(po, 1, 0);
+        writePackedDouble(po, 2, 1);
+        writePackedDouble(po, 3, -1234.432);
+        writePackedDouble(po, 4, 42.42);
+        writePackedDouble(po, 5, Double.MIN_NORMAL);
+        writePackedDouble(po, 6, Double.MIN_VALUE);
+        writePackedDouble(po, 7, Double.NEGATIVE_INFINITY);
+        writePackedDouble(po, 8, Double.NaN);
+        writePackedDouble(po, 9, Double.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x3f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x1a,
+                (byte)0x10,
+                (byte)0x7d, (byte)0x3f, (byte)0x35, (byte)0x5e,
+                (byte)0xba, (byte)0x49, (byte)0x93, (byte)0xc0,
+                (byte)0x7d, (byte)0x3f, (byte)0x35, (byte)0x5e,
+                (byte)0xba, (byte)0x49, (byte)0x93, (byte)0xc0,
+                // 4 -> 42.42
+                (byte)0x22,
+                (byte)0x10,
+                (byte)0xf6, (byte)0x28, (byte)0x5c, (byte)0x8f,
+                (byte)0xc2, (byte)0x35, (byte)0x45, (byte)0x40,
+                (byte)0xf6, (byte)0x28, (byte)0x5c, (byte)0x8f,
+                (byte)0xc2, (byte)0x35, (byte)0x45, (byte)0x40,
+                // 5 -> Double.MIN_NORMAL
+                (byte)0x2a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x32,
+                (byte)0x10,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Double.NEGATIVE_INFINITY
+                (byte)0x3a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0xff,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0xff,
+                // 8 -> Double.NaN
+                (byte)0x42,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf8, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf8, (byte)0x7f,
+                // 9 -> Double.POSITIVE_INFINITY
+                (byte)0x4a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new double[] {});
+        testPackedCompat(new double[] { 0, 1, -1234.432, 42.42,
+                    Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
+                    Double.POSITIVE_INFINITY,
+                });
+    }
+
+    /**
+     * Implementation of testPackedDoubleCompat with a given value.
+     */
+    public void testPackedCompat(double[] val) throws Exception {
+        final int fieldId = 12;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.doubleFieldPacked = val;
+        po.writePackedDouble(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.doubleFieldPacked);
+        assertEquals(val.length, readback.doubleFieldPacked.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.doubleFieldPacked[i]);
+        }
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_INT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32),
+                    new double[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedDouble(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new double[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamEnumTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamEnumTest.java
new file mode 100644
index 0000000..c924ab0
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamEnumTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the enum methods on the ProtoOutputStream class.
+ *
+ * Nano proto CodedOutputByteBufferNano has writeEnum that writes a raw varint,
+ * but the generated code uses writeInt32.  So we will follow that implementation.
+ */
+public class ProtoOutputStreamEnumTest extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeEnum
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeEnum.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        po.writeEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 160;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.outsideField = val;
+        po.writeEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        // The generated code filters the values, so only check those.
+        if (val == Test.OUTSIDE_0 || val == Test.OUTSIDE_1) {
+            assertEquals(val, readback.outsideField);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedEnum
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeEnum.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 161;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.outsideFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        // Nano proto drops values that are outside the range, so disable
+        // this test.
+        /*
+        assertNotNull(readback.outsideFieldRepeated);
+        assertEquals(val.length, readback.outsideFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.outsideFieldRepeated[i]);
+        }
+        */
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedEnum
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeEnum.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedEnum(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM;
+        po.writePackedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        po.writePackedEnum(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedEnum(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedEnum(po, 1, 0);
+        writePackedEnum(po, 2, 1);
+        writePackedEnum(po, 3, -1);
+        writePackedEnum(po, 4, Integer.MIN_VALUE);
+        writePackedEnum(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x14,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 4 -> MIN_VALUE
+                (byte)0x22,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 5 -> MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1 });
+
+        // Nano proto has a bug.  It gets the size with computeInt32SizeNoTag (correctly)
+        // but incorrectly uses writeRawVarint32 to write the value for negative numbers.
+        //testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedEnumCompat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 162;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.outsideFieldPacked = val;
+        po.writePackedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.outsideFieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedEnum(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
+
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed32Test.java
new file mode 100644
index 0000000..dcc50d4
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed32Test.java
@@ -0,0 +1,377 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the fixed32 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamFixed32Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed32.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        po.writeFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 90;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed32Field = val;
+        po.writeFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.fixed32Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed32.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 91;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed32FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.fixed32FieldRepeated);
+        assertEquals(val.length, readback.fixed32FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.fixed32FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed32.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedFixed32(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED32;
+        po.writePackedFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        po.writePackedFixed32(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedFixed32(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedFixed32(po, 1, 0);
+        writePackedFixed32(po, 2, 1);
+        writePackedFixed32(po, 3, -1);
+        writePackedFixed32(po, 4, Integer.MIN_VALUE);
+        writePackedFixed32(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x08,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x08,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, });
+    }
+
+    /**
+     * Implementation of testPackedFixed32Compat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 92;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed32FieldPacked = val;
+        po.writePackedFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.fixed32FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED32),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed64Test.java
new file mode 100644
index 0000000..4545359
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFixed64Test.java
@@ -0,0 +1,454 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the fixed64 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamFixed64Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed64.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        po.writeFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+        testWriteCompat(Long.MIN_VALUE);
+        testWriteCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(long val) throws Exception {
+        final int fieldId = 100;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed64Field = val;
+        po.writeFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.fixed64Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed64.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(long[] val) throws Exception {
+        final int fieldId = 101;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed64FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.fixed64FieldRepeated);
+        assertEquals(val.length, readback.fixed64FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.fixed64FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFixed64.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedFixed64(ProtoOutputStream po, int fieldId, long val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED64;
+        po.writePackedFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new long[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        po.writePackedFixed64(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedFixed64(ProtoOutputStream.makeFieldId(1001, fieldFlags), new long[0]);
+        writePackedFixed64(po, 1, 0);
+        writePackedFixed64(po, 2, 1);
+        writePackedFixed64(po, 3, -1);
+        writePackedFixed64(po, 4, Integer.MIN_VALUE);
+        writePackedFixed64(po, 5, Integer.MAX_VALUE);
+        writePackedFixed64(po, 6, Long.MIN_VALUE);
+        writePackedFixed64(po, 7, Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x10,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x32,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x3a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[] {});
+        testPackedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedFixed64Compat with a given value.
+     */
+    public void testPackedCompat(long[] val) throws Exception {
+        final int fieldId = 102;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.fixed64FieldPacked = val;
+        po.writePackedFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.fixed64FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FIXED64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FIXED64),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFloatTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFloatTest.java
new file mode 100644
index 0000000..99a720d
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamFloatTest.java
@@ -0,0 +1,479 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the float methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamFloatTest extends TestCase {
+
+    /**
+     * Compare if the values are identical (including handling for matching isNaN).
+     */
+    public void assertEquals(float expected, float actual) {
+        if (Float.isNaN(expected)) {
+            if (!Float.isNaN(actual)) {
+                throw new RuntimeException("expected NaN, actual " + actual);
+            }
+        } else {
+            if (expected != actual) {
+                throw new RuntimeException("expected " + expected + ", actual " + actual);
+            }
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeFloat
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFloat.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        po.writeFloat(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeFloat(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeFloat(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432f);
+        po.writeFloat(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42f);
+        po.writeFloat(ProtoOutputStream.makeFieldId(5, fieldFlags), Float.MIN_NORMAL);
+        po.writeFloat(ProtoOutputStream.makeFieldId(6, fieldFlags), Float.MIN_VALUE);
+        po.writeFloat(ProtoOutputStream.makeFieldId(7, fieldFlags), Float.NEGATIVE_INFINITY);
+        po.writeFloat(ProtoOutputStream.makeFieldId(8, fieldFlags), Float.NaN);
+        po.writeFloat(ProtoOutputStream.makeFieldId(9, fieldFlags), Float.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x1d,
+                (byte)0xd3, (byte)0x4d, (byte)0x9a, (byte)0xc4,
+                // 4 -> 42.42
+                (byte)0x25,
+                (byte)0x14, (byte)0xae, (byte)0x29, (byte)0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte)0x2d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x35,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte)0x3d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0xff,
+                // 8 -> Float.NaN
+                (byte)0x45,
+                (byte)0x00, (byte)0x00, (byte)0xc0, (byte)0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte)0x4d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x7f,
+
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1234.432f);
+        testWriteCompat(42.42f);
+        testWriteCompat(Float.MIN_NORMAL);
+        testWriteCompat(Float.MIN_VALUE);
+        testWriteCompat(Float.NEGATIVE_INFINITY);
+        testWriteCompat(Float.NaN);
+        testWriteCompat(Float.POSITIVE_INFINITY);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(float val) throws Exception {
+        final int fieldId = 20;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.floatField = val;
+        po.writeFloat(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.floatField);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedFloat
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFloat.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432f);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42f);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(5, fieldFlags), Float.MIN_NORMAL);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(6, fieldFlags), Float.MIN_VALUE);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(7, fieldFlags), Float.NEGATIVE_INFINITY);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(8, fieldFlags), Float.NaN);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(9, fieldFlags), Float.POSITIVE_INFINITY);
+
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(3, fieldFlags), -1234.432f);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(4, fieldFlags), 42.42f);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(5, fieldFlags), Float.MIN_NORMAL);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(6, fieldFlags), Float.MIN_VALUE);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(7, fieldFlags), Float.NEGATIVE_INFINITY);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(8, fieldFlags), Float.NaN);
+        po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(9, fieldFlags), Float.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x1d,
+                (byte)0xd3, (byte)0x4d, (byte)0x9a, (byte)0xc4,
+                // 4 -> 42.42
+                (byte)0x25,
+                (byte)0x14, (byte)0xae, (byte)0x29, (byte)0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte)0x2d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x35,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte)0x3d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0xff,
+                // 8 -> Float.NaN
+                (byte)0x45,
+                (byte)0x00, (byte)0x00, (byte)0xc0, (byte)0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte)0x4d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x1d,
+                (byte)0xd3, (byte)0x4d, (byte)0x9a, (byte)0xc4,
+                // 4 -> 42.42
+                (byte)0x25,
+                (byte)0x14, (byte)0xae, (byte)0x29, (byte)0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte)0x2d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x35,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte)0x3d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0xff,
+                // 8 -> Float.NaN
+                (byte)0x45,
+                (byte)0x00, (byte)0x00, (byte)0xc0, (byte)0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte)0x4d,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new float[0]);
+        testRepeatedCompat(new float[] { 0, 1, -1234.432f, 42.42f,
+                    Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                    Float.POSITIVE_INFINITY,
+                });
+        }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(float[] val) throws Exception {
+        final int fieldId = 21;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.floatFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.floatFieldRepeated);
+        assertEquals(val.length, readback.floatFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.floatFieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedFloat
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeFloat.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedFloat(ProtoOutputStream po, int fieldId, float val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FLOAT;
+        po.writePackedFloat(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new float[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        po.writePackedFloat(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedFloat(ProtoOutputStream.makeFieldId(1001, fieldFlags), new float[0]);
+        writePackedFloat(po, 1, 0);
+        writePackedFloat(po, 2, 1);
+        writePackedFloat(po, 3, -1234.432f);
+        writePackedFloat(po, 4, 42.42f);
+        writePackedFloat(po, 5, Float.MIN_NORMAL);
+        writePackedFloat(po, 6, Float.MIN_VALUE);
+        writePackedFloat(po, 7, Float.NEGATIVE_INFINITY);
+        writePackedFloat(po, 8, Float.NaN);
+        writePackedFloat(po, 9, Float.POSITIVE_INFINITY);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,
+                // 3 -> -1234.432
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0xd3, (byte)0x4d, (byte)0x9a, (byte)0xc4,
+                (byte)0xd3, (byte)0x4d, (byte)0x9a, (byte)0xc4,
+                // 4 -> 42.42
+                (byte)0x22,
+                (byte)0x08,
+                (byte)0x14, (byte)0xae, (byte)0x29, (byte)0x42,
+                (byte)0x14, (byte)0xae, (byte)0x29, (byte)0x42,
+                // 5 -> Float.MIN_NORMAL
+                (byte)0x2a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00,
+                // 6 -> DOUBLE.MIN_VALUE
+                (byte)0x32,
+                (byte)0x08,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 7 -> Float.NEGATIVE_INFINITY
+                (byte)0x3a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0xff,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0xff,
+                // 8 -> Float.NaN
+                (byte)0x42,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0xc0, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0xc0, (byte)0x7f,
+                // 9 -> Float.POSITIVE_INFINITY
+                (byte)0x4a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new float[] {});
+        testPackedCompat(new float[] { 0, 1, -1234.432f, 42.42f,
+                    Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
+                    Float.POSITIVE_INFINITY,
+                });
+        }
+
+    /**
+     * Implementation of testPackedFloatCompat with a given value.
+     */
+    public void testPackedCompat(float[] val) throws Exception {
+        final int fieldId = 22;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FLOAT;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.floatFieldPacked = val;
+        po.writePackedFloat(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.floatFieldPacked);
+        assertEquals(val.length, readback.floatFieldPacked.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.floatFieldPacked[i]);
+        }
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FLOAT), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_FLOAT), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new float[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedFloat(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_FLOAT),
+                    new float[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt32Test.java
new file mode 100644
index 0000000..e2b000f
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt32Test.java
@@ -0,0 +1,393 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamInt32Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt32.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        po.writeInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 30;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int32Field = val;
+        po.writeInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.int32Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt32.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 31;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int32FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.int32FieldRepeated);
+        assertEquals(val.length, readback.int32FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.int32FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt32.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedInt32(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32;
+        po.writePackedInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        po.writePackedInt32(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedInt32(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedInt32(po, 1, 0);
+        writePackedInt32(po, 2, 1);
+        writePackedInt32(po, 3, -1);
+        writePackedInt32(po, 4, Integer.MIN_VALUE);
+        writePackedInt32(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x14,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 4 -> MIN_VALUE
+                (byte)0x22,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 5 -> MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedInt32Compat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 32;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int32FieldPacked = val;
+        po.writePackedInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.int32FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt64Test.java
new file mode 100644
index 0000000..91638e0
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamInt64Test.java
@@ -0,0 +1,446 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the int64 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamInt64Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt64.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        po.writeInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+        testWriteCompat(Long.MIN_VALUE);
+        testWriteCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(long val) throws Exception {
+        final int fieldId = 40;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int64Field = val;
+        po.writeInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.int64Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt64.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(long[] val) throws Exception {
+        final int fieldId = 41;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int64FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.int64FieldRepeated);
+        assertEquals(val.length, readback.int64FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.int64FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeInt64.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedInt64(ProtoOutputStream po, int fieldId, long val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT64;
+        po.writePackedInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new long[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        po.writePackedInt64(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedInt64(ProtoOutputStream.makeFieldId(1001, fieldFlags), new long[0]);
+        writePackedInt64(po, 1, 0);
+        writePackedInt64(po, 2, 1);
+        writePackedInt64(po, 3, -1);
+        writePackedInt64(po, 4, Integer.MIN_VALUE);
+        writePackedInt64(po, 5, Integer.MAX_VALUE);
+        writePackedInt64(po, 6, Long.MIN_VALUE);
+        writePackedInt64(po, 7, Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x14,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte)0x32,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte)0x3a,
+                (byte)0x12,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[] {});
+        testPackedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedInt64Compat with a given value.
+     */
+    public void testPackedCompat(long[] val) throws Exception {
+        final int fieldId = 42;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.int64FieldPacked = val;
+        po.writePackedInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.int64FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_INT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT64),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java
new file mode 100644
index 0000000..fb23607
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamObjectTest.java
@@ -0,0 +1,893 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the object methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamObjectTest extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  Tokens
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test making the tokens for startObject.
+     */
+    public void testMakeToken() throws Exception {
+        assertEquals(0xe000000000000000L, ProtoOutputStream.makeToken(0xffffffff, false, 0, 0, 0));
+        assertEquals(0x1000000000000000L, ProtoOutputStream.makeToken(0, true, 0, 0, 0));
+        assertEquals(0x0ff8000000000000L, ProtoOutputStream.makeToken(0, false, 0xffffffff, 0, 0));
+        assertEquals(0x0007ffff00000000L, ProtoOutputStream.makeToken(0, false, 0, 0xffffffff, 0));
+        assertEquals(0x00000000ffffffffL, ProtoOutputStream.makeToken(0, false, 0, 0, 0xffffffff));
+    }
+
+    /**
+     * Test decoding the tokens.
+     */
+    public void testDecodeToken() throws Exception {
+        assertEquals(0x07, ProtoOutputStream.getTagSizeFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoOutputStream.getTagSizeFromToken(0x1fffffffffffffffL));
+
+        assertEquals(true, ProtoOutputStream.getRepeatedFromToken(0xffffffffffffffffL));
+        assertEquals(false, ProtoOutputStream.getRepeatedFromToken(0xefffffffffffffffL));
+
+        assertEquals(0x01ff, ProtoOutputStream.getDepthFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoOutputStream.getDepthFromToken(0xf005ffffffffffffL));
+
+        assertEquals(0x07ffff, ProtoOutputStream.getObjectIdFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoOutputStream.getObjectIdFromToken(0xfff80000ffffffffL));
+
+        assertEquals(0xffffffff, ProtoOutputStream.getSizePosFromToken(0xffffffffffffffffL));
+        assertEquals(0, ProtoOutputStream.getSizePosFromToken(0xffffffff00000000L));
+    }
+
+    /**
+     * Test writing an object with one char in it.
+     */
+    public void testObjectOneChar() {
+        testObjectOneChar(0);
+        testObjectOneChar(1);
+        testObjectOneChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneChar for a given chunkSize.
+     */
+    public void testObjectOneChar(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+        po.endObject(token);
+
+        Assert.assertArrayEquals(new byte[] {
+                (byte)0x0a, (byte)0x02, (byte)0x10, (byte)0x62,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test writing an object with one multibyte unicode char in it.
+     */
+    public void testObjectOneLargeChar() {
+        testObjectOneLargeChar(0);
+        testObjectOneLargeChar(1);
+        testObjectOneLargeChar(5);
+    }
+
+    /**
+     * Implementation of testObjectOneLargeChar for a given chunkSize.
+     */
+    public void testObjectOneLargeChar(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(5000,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                '\u3110');
+        po.endObject(token);
+
+        Assert.assertArrayEquals(new byte[] {
+                (byte)0x0a, (byte)0x05, (byte)0xc0, (byte)0xb8,
+                (byte)0x02, (byte)0x90, (byte)0x62,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test writing a char, then an object, then a char.
+     */
+    public void testObjectAndTwoChars() {
+        testObjectAndTwoChars(0);
+        testObjectAndTwoChars(1);
+        testObjectAndTwoChars(5);
+    }
+
+    /**
+     * Implementation of testObjectAndTwoChars for a given chunkSize.
+     */
+    public void testObjectAndTwoChars(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+        po.endObject(token);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'c');
+
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 'a'
+                (byte)0x08, (byte)0x61,
+                // begin object 1
+                (byte)0x12, (byte)0x02,
+                    // 3 -> 'b'
+                    (byte)0x18, (byte)0x62,
+                // 4 -> 'c'
+                (byte)0x20, (byte)0x63,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test writing an object with nothing in it.
+     */
+    public void testEmptyObject() {
+        testEmptyObject(0);
+        testEmptyObject(1);
+        testEmptyObject(5);
+    }
+
+    /**
+     * Implementation of testEmptyObject for a given chunkSize.
+     * Nothing should be written.
+     */
+    public void testEmptyObject(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(token);
+
+        Assert.assertArrayEquals(new byte[0], po.getBytes());
+    }
+
+    /**
+     * Test writing 3 levels deep of objects with nothing in them.
+     */
+    public void testDeepEmptyObjects() {
+        testDeepEmptyObjects(0);
+        testDeepEmptyObjects(1);
+        testDeepEmptyObjects(5);
+    }
+
+    /**
+     * Implementation of testDeepEmptyObjects for a given chunkSize.
+     */
+    public void testDeepEmptyObjects(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        long token3 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(token3);
+        po.endObject(token2);
+        po.endObject(token1);
+
+        Assert.assertArrayEquals(new byte[0], po.getBytes());
+    }
+
+    /**
+     * Test writing a char, then an object with nothing in it, then a char.
+     */
+    public void testEmptyObjectAndTwoChars() {
+        testEmptyObjectAndTwoChars(0);
+        testEmptyObjectAndTwoChars(1);
+        testEmptyObjectAndTwoChars(5);
+    }
+
+    /**
+     * Implementation of testEmptyObjectAndTwoChars for a given chunkSize.
+     */
+    public void testEmptyObjectAndTwoChars(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(token);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'c');
+
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 'a'
+                (byte)0x08, (byte)0x61,
+                // 4 -> 'c'
+                (byte)0x20, (byte)0x63,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test empty repeated objects.  For repeated objects, we write an empty header.
+     */
+    public void testEmptyRepeatedObject() {
+        testEmptyRepeatedObject(0);
+        testEmptyRepeatedObject(1);
+        testEmptyRepeatedObject(5);
+    }
+
+    /**
+     * Implementation of testEmptyRepeatedObject for a given chunkSize.
+     */
+    public void testEmptyRepeatedObject(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        long token;
+
+        token = po.startRepeatedObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endRepeatedObject(token);
+
+        token = po.startRepeatedObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endRepeatedObject(token);
+
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> empty (tag, size)
+                (byte)0x0a, (byte)0x00,
+                // 1 -> empty (tag, size)
+                (byte)0x0a, (byte)0x00,
+            }, po.getBytes());
+    }
+
+
+    /**
+     * Test writing a char, then an object with an int and a string in it, then a char.
+     */
+    public void testComplexObject() {
+        testComplexObject(0);
+        testComplexObject(1);
+        testComplexObject(5);
+    }
+
+    /**
+     * Implementation of testComplexObject for a given chunkSize.
+     */
+    public void testComplexObject(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'x');
+
+        long token = po.startObject(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'y');
+        po.writeString(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING),
+                "abcdefghijkl");
+
+        long tokenEmpty = po.startObject(ProtoOutputStream.makeFieldId(500,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(tokenEmpty);
+
+        po.endObject(token);
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(5,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'z');
+
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 'x'
+                (byte)0x08, (byte)0x78,
+                // begin object 1
+                (byte)0x12, (byte)0x10,
+                    // 3 -> 'y'
+                    (byte)0x18, (byte)0x79,
+                    // 4 -> "abcdefghijkl"
+                    (byte)0x22, (byte)0x0c,
+                        (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, (byte)0x65, (byte)0x66,
+                        (byte)0x67, (byte)0x68, (byte)0x69, (byte)0x6a, (byte)0x6b, (byte)0x6c,
+                // 4 -> 'z'
+                (byte)0x28, (byte)0x7a,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test writing 3 levels deep of objects.
+     */
+    public void testDeepObjects() {
+        testDeepObjects(0);
+        testDeepObjects(1);
+        testDeepObjects(5);
+    }
+
+    /**
+     * Implementation of testDeepObjects for a given chunkSize.
+     */
+    public void testDeepObjects(int chunkSize) {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+
+        long token3 = po.startObject(ProtoOutputStream.makeFieldId(5,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(6,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'c');
+
+        po.endObject(token3);
+        po.endObject(token2);
+        po.endObject(token1);
+
+        Assert.assertArrayEquals(new byte[] {
+                // begin object 1
+                (byte)0x0a, (byte)0x0a,
+                    // 2 -> 'a'
+                    (byte)0x10, (byte)0x61,
+                    // begin object 3
+                    (byte)0x1a, (byte)0x06,
+                        // 4 -> 'b'
+                        (byte)0x20, (byte)0x62,
+                        // begin object 5
+                        (byte)0x2a, (byte)0x02,
+                            // 6 -> 'c'
+                            (byte)0x30, (byte)0x63,
+            }, po.getBytes());
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: too many endObject
+     * with objects that have data.
+     */
+    public void testTooManyEndObjectsWithData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+
+        po.endObject(token2);
+        try {
+            po.endObject(token2);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: too many endObject
+     * with empty objects
+     */
+    public void testTooManyEndObjectsWithoutData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        po.endObject(token2);
+        try {
+            po.endObject(token2);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Trailing startObject
+     * with objects that have data.
+     */
+    public void testTrailingStartObjectWithData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+
+        po.endObject(token2);
+        try {
+            po.getBytes();
+            throw new Exception("getBytes didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Trailing startObject
+     * with empty objects
+     */
+    public void testTrailingStartObjectWithoutData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        po.endObject(token2);
+        try {
+            po.getBytes();
+            throw new Exception("getBytes didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Extra startObject in the middle.
+     * with objects that have data.
+     */
+    public void testExtraStartObjectInMiddleWithData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+
+        try {
+            po.endObject(token1);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Extra startObject in the middle.
+     * with empty objects
+     */
+    public void testExtraStartObjectInMiddleWithoutData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        try {
+            po.endObject(token1);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Two deep with swapped endObject.
+     * with objects that have data.
+     */
+    public void testSwappedEndObjectWithData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'a');
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+        po.endObject(token2);
+
+        long token3 = po.startObject(ProtoOutputStream.makeFieldId(5,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                'b');
+
+        try {
+            po.endObject(token2);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Two deep with swapped endObject.
+     * with empty objects
+     */
+    public void testSwappedEndObjectWithoutData() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(token2);
+
+        long token3 = po.startObject(ProtoOutputStream.makeFieldId(5,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        try {
+            po.endObject(token2);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Good
+        }
+    }
+
+    /**
+     * Test mismatched startObject / endObject calls: Two deep with swapped endObject.
+     * with empty objects
+     */
+    public void testEndObjectMismatchError() throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream();
+
+        long token1 = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        long token2 = po.startObject(ProtoOutputStream.makeFieldId(3,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.endObject(token2);
+
+        long token3 = po.startObject(ProtoOutputStream.makeFieldId(5,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        try {
+            po.endObject(token2);
+            throw new Exception("endObject didn't throw");
+        } catch (RuntimeException ex) {
+            // Check this, because it's really useful, and if we lose the message it'll be
+            // harder to debug typos.
+            assertEquals("Mismatched startObject/endObject calls. Current depth 2"
+                    + " token=Token(val=0x2017fffd0000000a depth=2 object=2 tagSize=1 sizePos=10)"
+                    + " expectedToken=Token(val=0x2017fffc0000000a depth=2 object=3 tagSize=1"
+                    + " sizePos=10)", ex.getMessage());
+        }
+    }
+
+    /**
+     * Test compatibility of nested objects.
+     */
+    public void testNestedCompat() throws Exception {
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.nestedField = new Test.Nested();
+        all.nestedField.data = 1;
+        all.nestedField.nested = new Test.Nested();
+        all.nestedField.nested.data = 2;
+        all.nestedField.nested.nested = new Test.Nested();
+        all.nestedField.nested.nested.data = 3;
+
+        final long token1 = po.startObject(ProtoOutputStream.makeFieldId(170,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                1);
+        final long token2 = po.startObject(ProtoOutputStream.makeFieldId(10002,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                2);
+        final long token3 = po.startObject(ProtoOutputStream.makeFieldId(10002,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                3);
+        po.endObject(token3);
+        po.endObject(token2);
+        po.endObject(token1);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+    }
+
+    /**
+     * Test compatibility of repeated nested objects.
+     */
+    public void testRepeatedNestedCompat() throws Exception {
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        final int N = 3;
+        all.nestedFieldRepeated = new Test.Nested[N];
+        for (int i=0; i<N; i++) {
+            all.nestedFieldRepeated[i] = new Test.Nested();
+            all.nestedFieldRepeated[i].data = 1;
+            all.nestedFieldRepeated[i].nested = new Test.Nested();
+            all.nestedFieldRepeated[i].nested.data = 2;
+            all.nestedFieldRepeated[i].nested.nested = new Test.Nested();
+            all.nestedFieldRepeated[i].nested.nested.data = 3;
+
+            final long token1 = po.startObject(ProtoOutputStream.makeFieldId(171,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+            po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                    1);
+            final long token2 = po.startObject(ProtoOutputStream.makeFieldId(10002,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+            po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                    2);
+            final long token3 = po.startObject(ProtoOutputStream.makeFieldId(10002,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+            po.writeInt32(ProtoOutputStream.makeFieldId(10001,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_INT32),
+                    3);
+            po.endObject(token3);
+            po.endObject(token2);
+            po.endObject(token1);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.startObject(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE));
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.startObject(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.startRepeatedObject(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE));
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.startRepeatedObject(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_OBJECT));
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+
+    /**
+     * Test that if endRepeatedObject is called with a token from startObject that it fails.
+     */
+    public void testMismatchedEndObject() {
+        final ProtoOutputStream po = new ProtoOutputStream();
+        final long token = po.startObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        try {
+            po.endRepeatedObject(token);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+
+    /**
+     * Test that if endRepeatedObject is called with a token from startObject that it fails.
+     */
+    public void testMismatchedEndRepeatedObject() {
+        final ProtoOutputStream po = new ProtoOutputStream();
+        final long token = po.startRepeatedObject(ProtoOutputStream.makeFieldId(1,
+                    ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_OBJECT));
+
+        try {
+            po.endObject(token);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+
+    /**
+     * Test writeObject, which takes a pre-encoded and compacted protobuf object and writes it into
+     * a field.
+     */
+    public void testWriteObject() {
+        byte[] innerRaw = new byte[] {
+            // varint 1 -> 42
+            (byte)0x08,
+            (byte)0xd0, (byte)0x02,
+            // string 2 -> "ab"
+            (byte)0x12,
+            (byte)0x02,
+            (byte)0x62, (byte)0x63,
+            // object 3 -> ...
+            (byte)0x1a,
+            (byte)0x4,
+                // varint 4 -> 0
+                (byte)0x20,
+                (byte)0x00,
+                // varint 4 --> 1
+                (byte)0x20,
+                (byte)0x01,
+        };
+
+        final ProtoOutputStream po = new ProtoOutputStream();
+        po.writeObject(ProtoOutputStream.makeFieldId(10,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT),
+                innerRaw);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = new byte[2 + innerRaw.length];
+        expected[0] = (byte)0x52;
+        expected[1] = (byte)0x0d;
+        System.arraycopy(innerRaw, 0, expected, 2, innerRaw.length);
+
+        Assert.assertArrayEquals(expected, result);
+    }
+
+    /**
+     * Test writeObject, which takes a pre-encoded and compacted protobuf object and writes it into
+     * a field.
+     */
+    public void testWriteObjectEmpty() {
+        byte[] innerRaw = new byte[0];
+
+        final ProtoOutputStream po = new ProtoOutputStream();
+        po.writeObject(ProtoOutputStream.makeFieldId(10,
+                    ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_OBJECT),
+                innerRaw);
+
+        final byte[] result = po.getBytes();
+
+        Assert.assertEquals(0, result.length);
+    }
+
+    /**
+     * Test writeObject, which takes a pre-encoded and compacted protobuf object and writes it into
+     * a field.
+     */
+    public void testWriteObjectRepeated() {
+        byte[] innerRaw = new byte[] {
+            // varint 1 -> 42
+            (byte)0x08,
+            (byte)0xd0, (byte)0x02,
+            // string 2 -> "ab"
+            (byte)0x12,
+            (byte)0x02,
+            (byte)0x62, (byte)0x63,
+            // object 3 -> ...
+            (byte)0x1a,
+            (byte)0x4,
+                // varint 4 -> 0
+                (byte)0x20,
+                (byte)0x00,
+                // varint 4 --> 1
+                (byte)0x20,
+                (byte)0x01,
+        };
+
+        final ProtoOutputStream po = new ProtoOutputStream();
+        po.writeRepeatedObject(ProtoOutputStream.makeFieldId(10,
+                    ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_OBJECT),
+                innerRaw);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = new byte[2 + innerRaw.length];
+        expected[0] = (byte)0x52;
+        expected[1] = (byte)0x0d;
+        System.arraycopy(innerRaw, 0, expected, 2, innerRaw.length);
+
+        Assert.assertArrayEquals(expected, result);
+    }
+
+    /**
+     * Test writeObject, which takes a pre-encoded and compacted protobuf object and writes it into
+     * a field.
+     */
+    public void testWriteObjectRepeatedEmpty() {
+        byte[] innerRaw = new byte[0];
+
+        final ProtoOutputStream po = new ProtoOutputStream();
+        po.writeRepeatedObject(ProtoOutputStream.makeFieldId(10,
+                    ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_OBJECT),
+                innerRaw);
+
+        Assert.assertArrayEquals(new byte[] {
+            (byte)0x52,
+            (byte)0x00
+        }, po.getBytes());
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed32Test.java
new file mode 100644
index 0000000..dbc9f49
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed32Test.java
@@ -0,0 +1,378 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the sfixed32 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamSFixed32Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeSFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed32.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 110;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed32Field = val;
+        po.writeSFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.sfixed32Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedSFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed32.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0d,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x15,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x25,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2d,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 111;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed32FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.sfixed32FieldRepeated);
+        assertEquals(val.length, readback.sfixed32FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.sfixed32FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedSFixed32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed32.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedSFixed32(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+        po.writePackedSFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        po.writePackedSFixed32(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedSFixed32(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedSFixed32(po, 1, 0);
+        writePackedSFixed32(po, 2, 1);
+        writePackedSFixed32(po, 3, -1);
+        writePackedSFixed32(po, 4, Integer.MIN_VALUE);
+        writePackedSFixed32(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x08,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x08,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x08,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, });
+    }
+
+    /**
+     * Implementation of testPackedSFixed32Compat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 112;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed32FieldPacked = val;
+        po.writePackedSFixed32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.sfixed32FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSFixed32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED32),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed64Test.java
new file mode 100644
index 0000000..c205987
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSFixed64Test.java
@@ -0,0 +1,453 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the sfixed64 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamSFixed64Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeSFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed64.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+        testWriteCompat(Long.MIN_VALUE);
+        testWriteCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(long val) throws Exception {
+        final int fieldId = 120;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed64Field = val;
+        po.writeSFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.sfixed64Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedSFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed64.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x09,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x11,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x19,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x21,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x29,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x31,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x39,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(long[] val) throws Exception {
+        final int fieldId = 121;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed64FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.sfixed64FieldRepeated);
+        assertEquals(val.length, readback.sfixed64FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.sfixed64FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedSFixed64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSFixed64.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedSFixed64(ProtoOutputStream po, int fieldId, long val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+        po.writePackedSFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags),
+                new long[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        po.writePackedSFixed64(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedSFixed64(ProtoOutputStream.makeFieldId(1001, fieldFlags), new long[0]);
+        writePackedSFixed64(po, 1, 0);
+        writePackedSFixed64(po, 2, 1);
+        writePackedSFixed64(po, 3, -1);
+        writePackedSFixed64(po, 4, Integer.MIN_VALUE);
+        writePackedSFixed64(po, 5, Integer.MAX_VALUE);
+        writePackedSFixed64(po, 6, Long.MIN_VALUE);
+        writePackedSFixed64(po, 7, Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x10,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x32,
+                (byte)0x10,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x3a,
+                (byte)0x10,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[] {});
+        testPackedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedSFixed64Compat with a given value.
+     */
+    public void testPackedCompat(long[] val) throws Exception {
+        final int fieldId = 122;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sfixed64FieldPacked = val;
+        po.writePackedSFixed64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.sfixed64FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SFIXED64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSFixed64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SFIXED64),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt32Test.java
new file mode 100644
index 0000000..7487e3a
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt32Test.java
@@ -0,0 +1,377 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the sint32 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamSInt32Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeSInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt32.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        po.writeSInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeSInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeSInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeSInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeSInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 70;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint32Field = val;
+        po.writeSInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.sint32Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedSInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt32.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 71;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint32FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.sint32FieldRepeated);
+        assertEquals(val.length, readback.sint32FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.sint32FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedSInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt32.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedSInt32(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT32;
+        po.writePackedSInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        po.writePackedSInt32(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedSInt32(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedSInt32(po, 1, 0);
+        writePackedSInt32(po, 2, 1);
+        writePackedSInt32(po, 3, -1);
+        writePackedSInt32(po, 4, Integer.MIN_VALUE);
+        writePackedSInt32(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x02,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 4 -> MIN_VALUE
+                (byte)0x22,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedSInt32Compat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 72;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint32FieldPacked = val;
+        po.writePackedSInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.sint32FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT32),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt64Test.java
new file mode 100644
index 0000000..33d4ab0
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSInt64Test.java
@@ -0,0 +1,432 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the sint64 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamSInt64Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeSInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt64.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        po.writeSInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeSInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+        testWriteCompat(Long.MIN_VALUE);
+        testWriteCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(long val) throws Exception {
+        final int fieldId = 80;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint64Field = val;
+        po.writeSInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.sint64Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedSInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt64.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(long[] val) throws Exception {
+        final int fieldId = 81;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint64FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.sint64FieldRepeated);
+        assertEquals(val.length, readback.sint64FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.sint64FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedSInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeSInt64.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedSInt64(ProtoOutputStream po, int fieldId, long val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT64;
+        po.writePackedSInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new long[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        po.writePackedSInt64(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedSInt64(ProtoOutputStream.makeFieldId(1001, fieldFlags), new long[0]);
+        writePackedSInt64(po, 1, 0);
+        writePackedSInt64(po, 2, 1);
+        writePackedSInt64(po, 3, -1);
+        writePackedSInt64(po, 4, Integer.MIN_VALUE);
+        writePackedSInt64(po, 5, Integer.MAX_VALUE);
+        writePackedSInt64(po, 6, Long.MIN_VALUE);
+        writePackedSInt64(po, 7, Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x02,
+                (byte)0x02,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x32,
+                (byte)0x14,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x3a,
+                (byte)0x14,
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xfe, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[] {});
+        testPackedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedSInt64Compat with a given value.
+     */
+    public void testPackedCompat(long[] val) throws Exception {
+        final int fieldId = 82;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.sint64FieldPacked = val;
+        po.writePackedSInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.sint64FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_SINT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedSInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_SINT64),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+    
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamStringTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamStringTest.java
new file mode 100644
index 0000000..7b0debb
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamStringTest.java
@@ -0,0 +1,295 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the string methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamStringTest extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeString
+    // ----------------------------------------------------------------------
+
+    private static String makeLongString() {
+        final StringBuilder sb = new StringBuilder(0x9fff-0x4E00);
+        // All of the unicode unified CJK characters
+        for (int i=0x4E00; i<=0x9fff; i++) {
+            sb.append((char)(0x4E00 + i));
+        }
+        return sb.toString();
+    }
+
+    private static final String LONG_STRING = makeLongString();
+
+    public void testWriteLongString() throws Exception {
+        testWriteLongString(0);
+        testWriteLongString(1);
+        testWriteLongString(5);
+        testWriteLongString(1024 * 1024);
+    }
+
+    public void testWriteLongString(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING;
+
+        final String string = LONG_STRING;
+
+        po.writeString(ProtoOutputStream.makeFieldId(1, fieldFlags), string);
+
+        final byte[] utf8 = string.getBytes("UTF-8");
+        byte[] expected = new byte[utf8.length + 4];
+
+        // tag
+        expected[0] = (byte)0x0a;
+        // size
+        expected[1] = (byte)0x82;
+        expected[2] = (byte)0xcc;
+        expected[3] = (byte)0x03;
+        // data
+        System.arraycopy(utf8, 0, expected, 4, utf8.length);
+
+        Assert.assertArrayEquals(expected, po.getBytes());
+    }
+
+    /**
+     * Test writeString.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING;
+
+        po.writeString(ProtoOutputStream.makeFieldId(1, fieldFlags), null);
+        po.writeString(ProtoOutputStream.makeFieldId(2, fieldFlags), "");
+        po.writeString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!");
+        po.writeString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi");
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> null - default value, not written
+                // 2 -> "" - default value, not written
+                // 3 -> "abcd\u3110!"
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64,
+                (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21,
+                // 4 -> "Hi"
+                (byte)0x22,
+                (byte)0x02,
+                (byte)0x48, (byte)0x69,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        // Nano doesn't work with null.
+        // testWriteCompat(null);
+
+        testWriteCompat("");
+        testWriteCompat("abcd\u3110!");
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(String val) throws Exception {
+        final int fieldId = 140;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.stringField = val;
+        po.writeString(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.stringField);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedString
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeString.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_STRING;
+
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, fieldFlags), null);
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(2, fieldFlags), "");
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!");
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi");
+
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, fieldFlags), null);
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(2, fieldFlags), "");
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!");
+        po.writeRepeatedString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi");
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> null - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte)0x12,
+                (byte)0x00,
+                // 3 -> "abcd\u3110!"
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64,
+                (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21,
+                // 4 -> "Hi"
+                (byte)0x22,
+                (byte)0x02,
+                (byte)0x48, (byte)0x69,
+
+                // 1 -> null - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x00,
+                // 2 -> "" - default value, written when repeated
+                (byte)0x12,
+                (byte)0x00,
+                // 3 -> "abcd\u3110!"
+                (byte)0x1a,
+                (byte)0x08,
+                (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64,
+                (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21,
+                // 4 -> "Hi"
+                (byte)0x22,
+                (byte)0x02,
+                (byte)0x48, (byte)0x69,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        // Nano doesn't work with null.
+        testRepeatedCompat(new String[0]);
+        testRepeatedCompat(new String[] { "", "abcd\u3110!", "Hi", });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(String[] val) throws Exception {
+        final int fieldId = 141;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_STRING;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.stringFieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedString(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.stringFieldRepeated);
+        assertEquals(val.length, readback.stringFieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.stringFieldRepeated[i]);
+        }
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeString(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), "");
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeString(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_STRING), "");
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedString(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), "");
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedString(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_STRING), "");
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSwitchedWriteTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSwitchedWriteTest.java
new file mode 100644
index 0000000..9052755
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamSwitchedWriteTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.proto.cts;
+
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import static android.util.proto.ProtoOutputStream.*;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+
+/**
+ * Tests that the write() functions produce the same values as their typed counterparts.
+ */
+public class ProtoOutputStreamSwitchedWriteTest extends TestCase {
+    private static final String TAG = "ProtoOutputStreamSwitchedWriteTest";
+
+    public static abstract class WriteTester {
+        public final String name;
+
+        public WriteTester(String n) {
+            name = n;
+        }
+
+        abstract void write(Number val, long fieldId, ProtoOutputStream po);
+    }
+
+    private static final HashMap<Long,WriteTester> TYPED = new HashMap<Long,WriteTester>();
+    private static final ArrayList<WriteTester> SWITCHED = new ArrayList<WriteTester>();
+
+    static {
+        TYPED.put(FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeDouble(fieldId, val.doubleValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeFloat(fieldId, val.floatValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeInt32(fieldId, val.intValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeInt64(fieldId, val.longValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeUInt32(fieldId, val.intValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeUInt64(fieldId, val.longValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeSInt32(fieldId, val.intValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeSInt64(fieldId, val.longValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeFixed32(fieldId, val.intValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeFixed64(fieldId, val.longValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeSFixed32(fieldId, val.intValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeSFixed64(fieldId, val.longValue());
+                    }
+                });
+        TYPED.put(FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeBool(fieldId, val.longValue() != 0);
+                    }
+                });
+        TYPED.put(FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE,
+                new WriteTester("FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.writeEnum(fieldId, val.intValue());
+                    }
+                });
+
+        SWITCHED.add(new WriteTester("write(long, double)") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.write(fieldId, val.doubleValue());
+                    }
+                });
+        SWITCHED.add(new WriteTester("write(long, float)") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.write(fieldId, val.floatValue());
+                    }
+                });
+        SWITCHED.add(new WriteTester("write(long, int)") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.write(fieldId, val.intValue());
+                    }
+                });
+        SWITCHED.add(new WriteTester("write(long, long)") {
+                    @Override
+                    public void write(Number val, long fieldId, ProtoOutputStream po) {
+                        po.write(fieldId, val.longValue());
+                    }
+                });
+    }
+
+    private static void testAWrite(Number val, long fieldId,
+            WriteTester typed, WriteTester switched) {
+        final ProtoOutputStream switchedPo = new ProtoOutputStream();
+        final ProtoOutputStream typedPo = new ProtoOutputStream();
+
+        typed.write(val, fieldId, typedPo);
+        switched.write(val, fieldId, switchedPo);
+
+        final byte[] switchedResult = switchedPo.getBytes();
+        final byte[] typedResult = typedPo.getBytes();
+
+        try {
+            Assert.assertArrayEquals(typedResult, switchedResult);
+        } catch (Throwable ex) {
+            throw new RuntimeException("Test for " + typed.name + " and "
+                    + switched.name + " value=" + val + " (" + val.getClass().getSimpleName()
+                    + ") failed: " + ex.getMessage(), ex);
+        }
+    }
+
+    public static void testWrites(Number val) {
+        for (HashMap.Entry<Long,WriteTester> entry: TYPED.entrySet()) {
+            final long fieldId = ((long)entry.getKey()) | 1;
+            final WriteTester typed = entry.getValue();
+
+            for (WriteTester switched: SWITCHED) {
+                testAWrite(val, fieldId, typed, switched);
+            }
+        }
+    }
+/**
+     * Test double
+     */
+    public void testWriteDouble() {
+        testWrites(new Double(0));
+        testWrites(new Double(-1));
+        testWrites(new Double(1));
+        testWrites(new Double(100));
+    }
+
+    /**
+     * Test float
+     */
+    public void testWriteFloat() {
+        testWrites(new Float(0));
+        testWrites(new Float(-1));
+        testWrites(new Float(1));
+        testWrites(new Float(100));
+    }
+
+    /**
+     * Test int
+     */
+    public void testWriteInteger() {
+        testWrites(new Integer(0));
+        testWrites(new Integer(-1));
+        testWrites(new Integer(1));
+        testWrites(new Integer(100));
+    }
+
+    /**
+     * Test long
+     */
+    public void testWriteLong() {
+        testWrites(new Long(0));
+        testWrites(new Long(-1));
+        testWrites(new Long(1));
+        testWrites(new Long(100));
+    }
+
+    /**
+     * Test single strings
+     */
+    public void testWriteString() {
+        final ProtoOutputStream typedPo = new ProtoOutputStream();
+        final ProtoOutputStream switchedPo = new ProtoOutputStream();
+
+        testString(1, "", typedPo, switchedPo);
+        testString(2, null, typedPo, switchedPo);
+        testString(3, "ABCD", typedPo, switchedPo);
+
+        final byte[] typedResult = typedPo.getBytes();
+        final byte[] switchedResult = switchedPo.getBytes();
+
+        Assert.assertArrayEquals(typedResult, switchedResult);
+    }
+
+    private void testString(int id, String val,
+            ProtoOutputStream typed, ProtoOutputStream switched) {
+        switched.write(FIELD_TYPE_STRING | FIELD_COUNT_SINGLE | id, val);
+        typed.writeString(FIELD_TYPE_STRING | FIELD_COUNT_SINGLE | id, val);
+    }
+
+    /**
+     * Test repeated strings
+     */
+    public void testWriteRepeatedString() {
+        final ProtoOutputStream typedPo = new ProtoOutputStream();
+        final ProtoOutputStream switchedPo = new ProtoOutputStream();
+
+        testRepeatedString(1, "", typedPo, switchedPo);
+        testRepeatedString(2, null, typedPo, switchedPo);
+        testRepeatedString(3, "ABCD", typedPo, switchedPo);
+
+        final byte[] typedResult = typedPo.getBytes();
+        final byte[] switchedResult = switchedPo.getBytes();
+
+        Assert.assertArrayEquals(typedResult, switchedResult);
+    }
+
+    private void testRepeatedString(int id, String val,
+            ProtoOutputStream typed, ProtoOutputStream switched) {
+        switched.write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | id, val);
+        typed.writeRepeatedString(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | id, val);
+    }
+
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
new file mode 100644
index 0000000..3b38aba
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test tag related methods on ProtoOutputStream.
+ */
+public class ProtoOutputStreamTagTest extends TestCase {
+    /**
+     * Test that check field ID matches exactly the field Id.
+     */
+    public void testCheckFieldIdTypes() throws Exception {
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_TYPE_DOUBLE, ProtoOutputStream.FIELD_TYPE_INT32);
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_TYPE_ENUM, ProtoOutputStream.FIELD_TYPE_ENUM);
+    }
+
+    /**
+     * Test that check field ID matches the table of count checks.
+     */
+    public void testCheckFieldIdCounts() throws Exception {
+        // UNKNOWN provided
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_COUNT_UNKNOWN,
+                ProtoOutputStream.FIELD_COUNT_UNKNOWN);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_UNKNOWN, ProtoOutputStream.FIELD_COUNT_SINGLE);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_UNKNOWN, ProtoOutputStream.FIELD_COUNT_REPEATED);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_UNKNOWN, ProtoOutputStream.FIELD_COUNT_PACKED);
+
+        // SINGLE provided
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_COUNT_SINGLE,
+                ProtoOutputStream.FIELD_COUNT_SINGLE);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_SINGLE, ProtoOutputStream.FIELD_COUNT_REPEATED);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_SINGLE, ProtoOutputStream.FIELD_COUNT_PACKED);
+
+        // REPEATED provided
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_REPEATED, ProtoOutputStream.FIELD_COUNT_SINGLE);
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_COUNT_REPEATED,
+                ProtoOutputStream.FIELD_COUNT_REPEATED);
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_REPEATED, ProtoOutputStream.FIELD_COUNT_PACKED);
+
+        // PACKED provided
+        assertCheckFieldIdThrows(ProtoOutputStream.FIELD_COUNT_PACKED, ProtoOutputStream.FIELD_COUNT_SINGLE);
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_COUNT_PACKED,
+                ProtoOutputStream.FIELD_COUNT_REPEATED);
+        ProtoOutputStream.checkFieldId(1 | ProtoOutputStream.FIELD_COUNT_PACKED,
+                ProtoOutputStream.FIELD_COUNT_PACKED);
+    }
+
+    /**
+     * Test that the error message for types works.
+     */
+    public void testCheckFieldIdErrorMessage() throws Exception {
+        checkMessageForType(ProtoOutputStream.FIELD_TYPE_DOUBLE, "Double");
+
+        checkMessageForCount(ProtoOutputStream.FIELD_COUNT_SINGLE, "");
+        checkMessageForCount(ProtoOutputStream.FIELD_COUNT_REPEATED, "Repeated");
+        checkMessageForCount(ProtoOutputStream.FIELD_COUNT_PACKED, "Packed");
+    }
+
+    /**
+     * Check that the exception message properly gets the type.
+     */
+    private void checkMessageForType(long fieldType, String string) {
+        final long badType = fieldType == ProtoOutputStream.FIELD_TYPE_DOUBLE
+                ? ProtoOutputStream.FIELD_TYPE_INT32
+                : ProtoOutputStream.FIELD_TYPE_DOUBLE;
+        final String badTypeString = badType == ProtoOutputStream.FIELD_TYPE_DOUBLE
+                ? "Double"
+                : "Int32";
+        final long goodCount = ProtoOutputStream.FIELD_COUNT_REPEATED;
+
+        // Try it in the provided name
+        try {
+            ProtoOutputStream.checkFieldId(42 | goodCount | badType, goodCount | fieldType);
+        } catch (IllegalArgumentException ex) {
+            assertEquals("writeRepeated" + string
+                        + " called for field 42 which should be used"
+                        + " with writeRepeated" + badTypeString + ".",
+                    ex.getMessage());
+        }
+
+        // Try it in the expected name
+        try {
+            ProtoOutputStream.checkFieldId(43 | goodCount | fieldType, goodCount | badType);
+        } catch (IllegalArgumentException ex) {
+            assertEquals("writeRepeated" + badTypeString
+                        + " called for field 43 which should be used"
+                        + " with writeRepeated" + string + ".",
+                    ex.getMessage());
+        }
+    }
+
+
+    /**
+     * Check that the exception message properly gets the count.
+     */
+    private void checkMessageForCount(long fieldCount, String string) {
+        final long badCount = fieldCount == ProtoOutputStream.FIELD_COUNT_SINGLE
+                ? ProtoOutputStream.FIELD_COUNT_REPEATED
+                : ProtoOutputStream.FIELD_COUNT_SINGLE;
+        final String badCountString = badCount == ProtoOutputStream.FIELD_COUNT_SINGLE
+                ? ""
+                : "Repeated";
+        final long goodType = ProtoOutputStream.FIELD_TYPE_FIXED32;
+
+        // Try it in the provided name
+        try {
+            ProtoOutputStream.checkFieldId(44 | badCount | goodType, fieldCount | goodType);
+        } catch (IllegalArgumentException ex) {
+            assertEquals("write" + string
+                    + "Fixed32 called for field 44 which should be used"
+                    + " with write" + badCountString + "Fixed32.",
+                    ex.getMessage());
+        }
+
+        // Try it in the expected name
+        try {
+            ProtoOutputStream.checkFieldId(45 | fieldCount | goodType, badCount | goodType);
+        } catch (IllegalArgumentException ex) {
+            String extraString = "";
+            if (fieldCount == ProtoOutputStream.FIELD_COUNT_PACKED) {
+                extraString = " or writeRepeatedFixed32";
+            }
+            assertEquals("write" + badCountString
+                    + "Fixed32 called for field 45 which should be used"
+                    + " with write" + string + "Fixed32" + extraString + ".",
+                    ex.getMessage());
+        }
+    }
+
+    /**
+     * Validate one call to checkFieldId that is expected to throw.
+     */
+    public void assertCheckFieldIdThrows(long fieldId, long expectedFlags) 
+            throws Exception {
+        try {
+            ProtoOutputStream.checkFieldId(fieldId, expectedFlags);
+            throw new Exception("checkFieldId(0x" + Long.toHexString(fieldId)
+                    + ", 0x" + Long.toHexString(expectedFlags) + ") did not throw.");
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt32Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt32Test.java
new file mode 100644
index 0000000..3afc971
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt32Test.java
@@ -0,0 +1,378 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the uint32 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamUInt32Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeUInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt32.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        po.writeUInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeUInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeUInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeUInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeUInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(int val) throws Exception {
+        final int fieldId = 50;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint32Field = val;
+        po.writeUInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.uint32Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedUInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt32.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 4 -> MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08,
+                // 5 -> MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new int[0]);
+        testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(int[] val) throws Exception {
+        final int fieldId = 51;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint32FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.uint32FieldRepeated);
+        assertEquals(val.length, readback.uint32FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.uint32FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedUInt32
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt32.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedUInt32(ProtoOutputStream po, int fieldId, int val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT32;
+        po.writePackedUInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new int[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        po.writePackedUInt32(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedUInt32(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]);
+        writePackedUInt32(po, 1, 0);
+        writePackedUInt32(po, 2, 1);
+        writePackedUInt32(po, 3, -1);
+        writePackedUInt32(po, 4, Integer.MIN_VALUE);
+        writePackedUInt32(po, 5, Integer.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0f,
+                // 4 -> MIN_VALUE
+                (byte)0x22,
+                (byte)0x0a,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x08,
+                // 5 -> MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new int[] {});
+        testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedUInt32Compat with a given value.
+     */
+    public void testPackedCompat(int[] val) throws Exception {
+        final int fieldId = 52;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT32;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint32FieldPacked = val;
+        po.writePackedUInt32(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.uint32FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT32), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedUInt32(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT32),
+                    new int[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt64Test.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt64Test.java
new file mode 100644
index 0000000..003a174
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamUInt64Test.java
@@ -0,0 +1,446 @@
+/*
+ * 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.proto.cts;
+
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.cts.nano.Test;
+
+import com.google.protobuf.nano.MessageNano;
+import junit.framework.TestCase;
+import org.junit.Assert;
+
+/**
+ * Test the uint64 methods on the ProtoOutputStream class.
+ */
+public class ProtoOutputStreamUInt64Test extends TestCase {
+
+    // ----------------------------------------------------------------------
+    //  writeUInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt64.
+     */
+    public void testWrite() throws Exception {
+        testWrite(0);
+        testWrite(1);
+        testWrite(5);
+    }
+
+    /**
+     * Implementation of testWrite with a given chunkSize.
+     */
+    public void testWrite(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        po.writeUInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeUInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, not written
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testWriteCompat() throws Exception {
+        testWriteCompat(0);
+        testWriteCompat(1);
+        testWriteCompat(-1);
+        testWriteCompat(Integer.MIN_VALUE);
+        testWriteCompat(Integer.MAX_VALUE);
+        testWriteCompat(Long.MIN_VALUE);
+        testWriteCompat(Long.MAX_VALUE);
+    }
+
+    /**
+     * Implementation of testWriteCompat with a given value.
+     */
+    public void testWriteCompat(long val) throws Exception {
+        final int fieldId = 60;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint64Field = val;
+        po.writeUInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertEquals(val, readback.uint64Field);
+    }
+
+    // ----------------------------------------------------------------------
+    //  writeRepeatedUInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt64.
+     */
+    public void testRepeated() throws Exception {
+        testRepeated(0);
+        testRepeated(1);
+        testRepeated(5);
+    }
+
+    /**
+     * Implementation of testRepeated with a given chunkSize.
+     */
+    public void testRepeated(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(1, fieldFlags), 0);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(2, fieldFlags), 1);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(3, fieldFlags), -1);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(6, fieldFlags), Long.MIN_VALUE);
+        po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(7, fieldFlags), Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x08,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x10,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x18,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x20,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x28,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+                // 6 -> Long.MIN_VALUE
+                (byte)0x30,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+                // 7 -> Long.MAX_VALUE
+                (byte)0x38,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testRepeatedCompat() throws Exception {
+        testRepeatedCompat(new long[0]);
+        testRepeatedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testRepeatedCompat with a given value.
+     */
+    public void testRepeatedCompat(long[] val) throws Exception {
+        final int fieldId = 61;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint64FieldRepeated = val;
+        for (int i=0; i<val.length; i++) {
+            po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]);
+        }
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        assertNotNull(readback.uint64FieldRepeated);
+        assertEquals(val.length, readback.uint64FieldRepeated.length);
+        for (int i=0; i<val.length; i++) {
+            assertEquals(val[i], readback.uint64FieldRepeated[i]);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    //  writePackedUInt64
+    // ----------------------------------------------------------------------
+
+    /**
+     * Test writeUInt64.
+     */
+    public void testPacked() throws Exception {
+        testPacked(0);
+        testPacked(1);
+        testPacked(5);
+    }
+
+    /**
+     * Create an array of the val, and write it.
+     */
+    private void writePackedUInt64(ProtoOutputStream po, int fieldId, long val) {
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT64;
+        po.writePackedUInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new long[] { val, val });
+    }
+
+    /**
+     * Implementation of testPacked with a given chunkSize.
+     */
+    public void testPacked(int chunkSize) throws Exception {
+        final ProtoOutputStream po = new ProtoOutputStream(chunkSize);
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        po.writePackedUInt64(ProtoOutputStream.makeFieldId(1000, fieldFlags), null);
+        po.writePackedUInt64(ProtoOutputStream.makeFieldId(1001, fieldFlags), new long[0]);
+        writePackedUInt64(po, 1, 0);
+        writePackedUInt64(po, 2, 1);
+        writePackedUInt64(po, 3, -1);
+        writePackedUInt64(po, 4, Integer.MIN_VALUE);
+        writePackedUInt64(po, 5, Integer.MAX_VALUE);
+        writePackedUInt64(po, 6, Long.MIN_VALUE);
+        writePackedUInt64(po, 7, Long.MAX_VALUE);
+
+        final byte[] result = po.getBytes();
+        Assert.assertArrayEquals(new byte[] {
+                // 1 -> 0 - default value, written when repeated
+                (byte)0x0a,
+                (byte)0x02,
+                (byte)0x00,
+                (byte)0x00,
+                // 2 -> 1
+                (byte)0x12,
+                (byte)0x02,
+                (byte)0x01,
+                (byte)0x01,
+                // 3 -> -1
+                (byte)0x1a,
+                (byte)0x14,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 4 -> Integer.MIN_VALUE
+                (byte)0x22,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01,
+
+                // 5 -> Integer.MAX_VALUE
+                (byte)0x2a,
+                (byte)0x0a,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07,
+
+                // 6 -> Long.MIN_VALUE
+                (byte)0x32,
+                (byte)0x14,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80,
+                (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x01,
+
+                // 7 -> Long.MAX_VALUE
+                (byte)0x3a,
+                (byte)0x12,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+                (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x7f,
+            }, result);
+    }
+
+    /**
+     * Test that writing a with ProtoOutputStream matches, and can be read by standard proto.
+     */
+    public void testPackedCompat() throws Exception {
+        testPackedCompat(new long[] {});
+        testPackedCompat(new long[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE,
+                Long.MIN_VALUE, Long.MAX_VALUE });
+    }
+
+    /**
+     * Implementation of testPackedUInt64Compat with a given value.
+     */
+    public void testPackedCompat(long[] val) throws Exception {
+        final int fieldId = 62;
+        final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT64;
+
+        final Test.All all = new Test.All();
+        final ProtoOutputStream po = new ProtoOutputStream(0);
+
+        all.uint64FieldPacked = val;
+        po.writePackedUInt64(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val);
+
+        final byte[] result = po.getBytes();
+        final byte[] expected = MessageNano.toByteArray(all);
+
+        Assert.assertArrayEquals(expected, result);
+
+        final Test.All readback = Test.All.parseFrom(result);
+
+        Assert.assertArrayEquals(val, readback.uint64FieldPacked);
+    }
+
+    /**
+     * Test that if you pass in the wrong type of fieldId, it throws.
+     */
+    public void testBadFieldIds() {
+        // Single
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Repeated
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writeRepeatedUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_UINT64), 0);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Packed
+
+        // Good Count / Bad Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+
+        // Bad Count / Good Type
+        try {
+            final ProtoOutputStream po = new ProtoOutputStream();
+            po.writePackedUInt64(ProtoOutputStream.makeFieldId(1,
+                        ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_UINT64),
+                    new long[0]);
+        } catch (IllegalArgumentException ex) {
+            // good
+        }
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java b/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java
new file mode 100644
index 0000000..1802fd0
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoTests.java
@@ -0,0 +1,47 @@
+/*
+ * 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.proto.cts;
+
+import junit.framework.TestSuite;
+
+public class ProtoTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ProtoTests.class.getName());
+
+        suite.addTestSuite(EncodedBufferTest.class);
+        suite.addTestSuite(ProtoOutputStreamTagTest.class);
+        suite.addTestSuite(ProtoOutputStreamDoubleTest.class);
+        suite.addTestSuite(ProtoOutputStreamFloatTest.class);
+        suite.addTestSuite(ProtoOutputStreamInt32Test.class);
+        suite.addTestSuite(ProtoOutputStreamInt64Test.class);
+        suite.addTestSuite(ProtoOutputStreamUInt32Test.class);
+        suite.addTestSuite(ProtoOutputStreamUInt64Test.class);
+        suite.addTestSuite(ProtoOutputStreamSInt32Test.class);
+        suite.addTestSuite(ProtoOutputStreamSInt64Test.class);
+        suite.addTestSuite(ProtoOutputStreamFixed32Test.class);
+        suite.addTestSuite(ProtoOutputStreamFixed64Test.class);
+        suite.addTestSuite(ProtoOutputStreamSFixed32Test.class);
+        suite.addTestSuite(ProtoOutputStreamSFixed64Test.class);
+        suite.addTestSuite(ProtoOutputStreamBoolTest.class);
+        suite.addTestSuite(ProtoOutputStreamStringTest.class);
+        suite.addTestSuite(ProtoOutputStreamBytesTest.class);
+        suite.addTestSuite(ProtoOutputStreamEnumTest.class);
+        suite.addTestSuite(ProtoOutputStreamObjectTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/tests/proto/src/android/util/proto/cts/test.proto b/tests/tests/proto/src/android/util/proto/cts/test.proto
new file mode 100644
index 0000000..7ea8d97
--- /dev/null
+++ b/tests/tests/proto/src/android/util/proto/cts/test.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+package android.util.proto.cts;
+
+/**
+ * Enum that outside the scope of any classes.
+ */
+enum Outside {
+    OUTSIDE_0 = 0;
+    OUTSIDE_1 = 1;
+};
+
+/**
+ * Message that is recursive.
+ */
+message Nested {
+    optional int32 data = 10001;
+    optional Nested nested = 10002;
+};
+
+/**
+ * Message with all of the field types.
+ */
+message All {
+    /**
+     * Enum that is inside the scope of a class.
+     */
+    enum Inside {
+        option allow_alias = true;
+        INSIDE_0 = 0;
+        INSIDE_1 = 1;
+        INSIDE_1A = 1;
+    };
+
+    optional double double_field = 10;
+    repeated double double_field_repeated = 11;
+    repeated double double_field_packed = 12 [packed=true];
+
+    optional float float_field = 20;
+    repeated float float_field_repeated = 21;
+    repeated float float_field_packed = 22 [packed=true];
+
+    optional int32 int32_field = 30;
+    repeated int32 int32_field_repeated = 31;
+    repeated int32 int32_field_packed = 32 [packed=true];
+
+    optional int64 int64_field = 40;
+    repeated int64 int64_field_repeated = 41;
+    repeated int64 int64_field_packed = 42 [packed=true];
+
+    optional uint32 uint32_field = 50;
+    repeated uint32 uint32_field_repeated = 51;
+    repeated uint32 uint32_field_packed = 52 [packed=true];
+
+    optional uint64 uint64_field = 60;
+    repeated uint64 uint64_field_repeated = 61;
+    repeated uint64 uint64_field_packed = 62 [packed=true];
+
+    optional sint32 sint32_field = 70;
+    repeated sint32 sint32_field_repeated = 71;
+    repeated sint32 sint32_field_packed = 72 [packed=true];
+
+    optional sint64 sint64_field = 80;
+    repeated sint64 sint64_field_repeated = 81;
+    repeated sint64 sint64_field_packed = 82 [packed=true];
+
+    optional fixed32 fixed32_field = 90;
+    repeated fixed32 fixed32_field_repeated = 91;
+    repeated fixed32 fixed32_field_packed = 92 [packed=true];
+
+    optional fixed64 fixed64_field = 100;
+    repeated fixed64 fixed64_field_repeated = 101;
+    repeated fixed64 fixed64_field_packed = 102 [packed=true];
+
+    optional sfixed32 sfixed32_field = 110;
+    repeated sfixed32 sfixed32_field_repeated = 111;
+    repeated sfixed32 sfixed32_field_packed = 112 [packed=true];
+
+    optional sfixed64 sfixed64_field = 120;
+    repeated sfixed64 sfixed64_field_repeated = 121;
+    repeated sfixed64 sfixed64_field_packed = 122 [packed=true];
+
+    optional bool bool_field = 130;
+    repeated bool bool_field_repeated = 131;
+    repeated bool bool_field_packed = 132 [packed=true];
+
+    optional string string_field = 140;
+    repeated string string_field_repeated = 141;
+
+    optional bytes bytes_field = 150;
+    repeated bytes bytes_field_repeated = 151;
+
+    optional Outside outside_field = 160;
+    repeated Outside outside_field_repeated = 161;
+    repeated Outside outside_field_packed = 162 [packed=true];
+
+    optional Nested nested_field = 170;
+    repeated Nested nested_field_repeated = 171;
+};
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index ee51fea..6a7d871 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil ctstestrunner
+    compatibility-device-util ctstestrunner ub-uiautomator
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index aadddb5..8c1c3cc 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -51,6 +51,8 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.provider.cts.GetResultActivity" />
+
         <service android:name="android.provider.cts.contacts.account.MockAccountService"
                  process="android.provider.cts"
                  android:exported="true">
@@ -71,6 +73,15 @@
             <meta-data android:name="android.view.im"
                        android:resource="@xml/method" />
         </service>
+
+        <provider
+            android:name=".contacts.DummyGalProvider"
+            android:authorities="android.provider.cts.contacts.dgp"
+            android:exported="true"
+            android:readPermission="android.permission.BIND_DIRECTORY_SEARCH" >
+            <meta-data android:name="android.content.ContactDirectory" android:value="true" />
+        </provider>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/provider/src/android/provider/cts/CalendarTest.java b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
index df31a19..8db5e45 100644
--- a/tests/tests/provider/src/android/provider/cts/CalendarTest.java
+++ b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
@@ -25,7 +25,6 @@
 import android.content.EntityIterator;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -48,6 +47,8 @@
 import android.text.format.Time;
 import android.util.Log;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java
new file mode 100644
index 0000000..24021a7
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java
@@ -0,0 +1,693 @@
+/*
+ * 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.provider.cts;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.SyncState;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import junit.framework.AssertionFailedError;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+@LargeTest
+public class ContactsContract_AllUriTest extends AndroidTestCase {
+    private static final String TAG = "AllUrlTest";
+
+    // "-" : Query not supported.
+    // "!" : Can't query because it requires the cross-user permission.
+    // The following markers are planned, but not implemented and the definition below is not all
+    // correct yet.
+    // "d" : supports delete.
+    // "u" : supports update.
+    // "i" : supports insert.
+    // "r" : supports read.
+    // "w" : supports write.
+    // "s" : has x_times_contacted and x_last_time_contacted.
+    // "t" : has x_times_used and x_last_time_used.
+    private static final String[][] URIs = {
+            {"content://com.android.contacts/contacts", "sud"},
+            {"content://com.android.contacts/contacts/1", "sud"},
+            {"content://com.android.contacts/contacts/1/data", "t"},
+            {"content://com.android.contacts/contacts/1/entities", "t"},
+            {"content://com.android.contacts/contacts/1/suggestions"},
+            {"content://com.android.contacts/contacts/1/suggestions/XXX"},
+            {"content://com.android.contacts/contacts/1/photo", "r"},
+            {"content://com.android.contacts/contacts/1/display_photo", "-r"},
+            {"content://com.android.contacts/contacts_corp/1/photo", "-r"},
+            {"content://com.android.contacts/contacts_corp/1/display_photo", "-r"},
+
+            {"content://com.android.contacts/contacts/filter", "s"},
+            {"content://com.android.contacts/contacts/filter/XXX", "s"},
+
+            {"content://com.android.contacts/contacts/lookup/nlookup", "sud"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/data", "t"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/photo", "tr"},
+
+            {"content://com.android.contacts/contacts/lookup/nlookup/1", "sud"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/data"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/photo", "r"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/display_photo", "-r"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/display_photo", "-r"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/entities"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/entities"},
+
+            {"content://com.android.contacts/contacts/as_vcard/nlookup", "r"},
+            {"content://com.android.contacts/contacts/as_multi_vcard/XXX"},
+
+            {"content://com.android.contacts/contacts/strequent/", "s"},
+            {"content://com.android.contacts/contacts/strequent/filter/XXX", "s"},
+
+            {"content://com.android.contacts/contacts/group/XXX"},
+
+            {"content://com.android.contacts/contacts/frequent", "s"},
+            {"content://com.android.contacts/contacts/delete_usage", "-d"},
+            {"content://com.android.contacts/contacts/filter_enterprise?directory=0", "s"},
+            {"content://com.android.contacts/contacts/filter_enterprise/XXX?directory=0", "s"},
+
+            {"content://com.android.contacts/raw_contacts", "siud"},
+            {"content://com.android.contacts/raw_contacts/1", "sud"},
+            {"content://com.android.contacts/raw_contacts/1/data", "tu"},
+            {"content://com.android.contacts/raw_contacts/1/display_photo", "-rw"},
+            {"content://com.android.contacts/raw_contacts/1/entity"},
+
+            {"content://com.android.contacts/raw_contact_entities"},
+            {"content://com.android.contacts/raw_contact_entities_corp", "!"},
+
+            {"content://com.android.contacts/data", "tud"},
+            {"content://com.android.contacts/data/1", "tudr"},
+            {"content://com.android.contacts/data/phones", "t"},
+            {"content://com.android.contacts/data_enterprise/phones", "!"},
+            {"content://com.android.contacts/data/phones/1", "tud"},
+            {"content://com.android.contacts/data/phones/filter", "t"},
+            {"content://com.android.contacts/data/phones/filter/XXX", "t"},
+
+            {"content://com.android.contacts/data/phones/filter_enterprise?directory=0", "t"},
+            {"content://com.android.contacts/data/phones/filter_enterprise/XXX?directory=0", "t"},
+
+            {"content://com.android.contacts/data/emails", "t"},
+            {"content://com.android.contacts/data/emails/1", "tud"},
+            {"content://com.android.contacts/data/emails/lookup", "t"},
+            {"content://com.android.contacts/data/emails/lookup/XXX", "t"},
+            {"content://com.android.contacts/data/emails/filter", "t"},
+            {"content://com.android.contacts/data/emails/filter/XXX", "t"},
+            {"content://com.android.contacts/data/emails/filter_enterprise?directory=0", "t"},
+            {"content://com.android.contacts/data/emails/filter_enterprise/XXX?directory=0", "t"},
+            {"content://com.android.contacts/data/emails/lookup_enterprise", "t"},
+            {"content://com.android.contacts/data/emails/lookup_enterprise/XXX", "t"},
+            {"content://com.android.contacts/data/postals", "t"},
+            {"content://com.android.contacts/data/postals/1", "tud"},
+            {"content://com.android.contacts/data/usagefeedback/1,2,3", "-u"},
+            {"content://com.android.contacts/data/callables/", "t"},
+            {"content://com.android.contacts/data/callables/1", "tud"},
+            {"content://com.android.contacts/data/callables/filter", "t"},
+            {"content://com.android.contacts/data/callables/filter/XXX", "t"},
+            {"content://com.android.contacts/data/callables/filter_enterprise?directory=0", "t"},
+            {"content://com.android.contacts/data/callables/filter_enterprise/XXX?directory=0",
+                    "t"},
+            {"content://com.android.contacts/data/contactables/", "t"},
+            {"content://com.android.contacts/data/contactables/filter", "t"},
+            {"content://com.android.contacts/data/contactables/filter/XXX", "t"},
+
+            {"content://com.android.contacts/groups", "iud"},
+            {"content://com.android.contacts/groups/1", "ud"},
+            {"content://com.android.contacts/groups_summary"},
+            {"content://com.android.contacts/syncstate", "iud"},
+            {"content://com.android.contacts/syncstate/1", "-ud"},
+            {"content://com.android.contacts/profile/syncstate", "iud"},
+            {"content://com.android.contacts/phone_lookup/XXX"},
+            {"content://com.android.contacts/phone_lookup_enterprise/XXX"},
+            {"content://com.android.contacts/aggregation_exceptions", "u"},
+            {"content://com.android.contacts/settings", "ud"},
+            {"content://com.android.contacts/status_updates", "ud"},
+            {"content://com.android.contacts/status_updates/1"},
+            {"content://com.android.contacts/search_suggest_query"},
+            {"content://com.android.contacts/search_suggest_query/XXX"},
+            {"content://com.android.contacts/search_suggest_shortcut/XXX"},
+            {"content://com.android.contacts/provider_status"},
+            {"content://com.android.contacts/directories", "u"},
+            {"content://com.android.contacts/directories/1"},
+            {"content://com.android.contacts/directories_enterprise"},
+            {"content://com.android.contacts/directories_enterprise/1"},
+            {"content://com.android.contacts/complete_name"},
+            {"content://com.android.contacts/profile", "su"},
+            {"content://com.android.contacts/profile/entities", "s"},
+            {"content://com.android.contacts/profile/data", "tud"},
+            {"content://com.android.contacts/profile/data/1", "td"},
+            {"content://com.android.contacts/profile/photo", "t"},
+            {"content://com.android.contacts/profile/display_photo", "-r"},
+            {"content://com.android.contacts/profile/as_vcard", "r"},
+            {"content://com.android.contacts/profile/raw_contacts", "siud"},
+
+            // Note this should have supported update... Too late to add.
+            {"content://com.android.contacts/profile/raw_contacts/1", "sd"},
+            {"content://com.android.contacts/profile/raw_contacts/1/data", "tu"},
+            {"content://com.android.contacts/profile/raw_contacts/1/entity"},
+            {"content://com.android.contacts/profile/status_updates", "ud"},
+            {"content://com.android.contacts/profile/raw_contact_entities"},
+            {"content://com.android.contacts/display_photo/1", "-r"},
+            {"content://com.android.contacts/photo_dimensions"},
+            {"content://com.android.contacts/deleted_contacts"},
+            {"content://com.android.contacts/deleted_contacts/1"},
+            {"content://com.android.contacts/directory_file_enterprise/XXX?directory=0", "-"},
+    };
+
+    private static final String[] ARG1 = {"-1"};
+
+    private ContentResolver mResolver;
+
+    private ArrayList<String> mFailures;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mFailures = new ArrayList<>();
+        mResolver = getContext().getContentResolver();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mFailures != null) {
+            fail("mFailures is not null.  Did you forget to call failIfFailed()?");
+        }
+
+        super.tearDown();
+    }
+
+    private void addFailure(String message, Throwable th) {
+        Log.e(TAG, "Failed: " + message, th);
+
+        final int MAX = 100;
+        if (mFailures.size() == MAX) {
+            mFailures.add("Too many failures.");
+        } else if (mFailures.size() > MAX) {
+            // Too many failures already...
+        } else {
+            mFailures.add(message);
+        }
+    }
+
+    private void failIfFailed() {
+        if (mFailures == null) {
+            fail("mFailures is null.  Maybe called failIfFailed() twice?");
+        }
+        if (mFailures.size() > 0) {
+            StringBuilder message = new StringBuilder();
+
+            if (mFailures.size() > 0) {
+                Log.e(TAG, "Something went wrong:");
+                for (String s : mFailures) {
+                    Log.e(TAG, s);
+                    if (message.length() > 0) {
+                        message.append("\n");
+                    }
+                    message.append(s);
+                }
+            }
+            mFailures = null;
+            fail("Following test(s) failed:\n" + message);
+        }
+        mFailures = null;
+    }
+
+    private static Uri getUri(String[] path) {
+        return Uri.parse(path[0]);
+    }
+
+    private static boolean supportsQuery(String[] path) {
+        if (path.length == 1) {
+            return true; // supports query by default.
+        }
+        return !(path[1].contains("-") || path[1].contains("!"));
+    }
+
+    private static boolean supportsInsert(String[] path) {
+        return (path.length) >= 2 && path[1].contains("i");
+    }
+
+    private static boolean supportsUpdate(String[] path) {
+        return (path.length) >= 2 && path[1].contains("u");
+    }
+
+    private static boolean supportsDelete(String[] path) {
+        return (path.length) >= 2 && path[1].contains("d");
+    }
+
+    private static boolean supportsRead(String[] path) {
+        return (path.length) >= 2 && path[1].contains("r");
+    }
+
+    private static boolean supportsWrite(String[] path) {
+        return (path.length) >= 2 && path[1].contains("w");
+    }
+
+    private String[] getColumns(Uri uri) {
+        try (Cursor c = mResolver.query(uri,
+                null, // projection
+                "1=2", // selection
+                null, // selection args
+                null // sort order
+        )) {
+            return c.getColumnNames();
+        }
+    }
+
+    private void checkQueryExecutable(Uri uri,
+            String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        try {
+            try (Cursor c = mResolver.query(uri, projection, selection,
+                    selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+        try {
+            // With CancellationSignal.
+            try (Cursor c = mResolver.query(uri, projection, selection,
+                    selectionArgs, sortOrder, new CancellationSignal())) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query with cancel failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+        try {
+            // With limit.
+            try (Cursor c = mResolver.query(
+                    uri.buildUpon().appendQueryParameter(
+                            ContactsContract.LIMIT_PARAM_KEY, "0").build(),
+                    projection, selection, selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query with limit failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+
+        try {
+            // With account.
+            try (Cursor c = mResolver.query(
+                    uri.buildUpon()
+                            .appendQueryParameter(RawContacts.ACCOUNT_NAME, "a")
+                            .appendQueryParameter(RawContacts.ACCOUNT_TYPE, "b")
+                            .appendQueryParameter(RawContacts.DATA_SET, "c")
+                            .build(),
+                    projection, selection, selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query with limit failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+    }
+
+    private void checkQueryNotExecutable(Uri uri,
+            String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        try {
+            try (Cursor c = mResolver.query(uri, projection, selection,
+                    selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            // pass.
+            return;
+        }
+        addFailure("Query on " + uri + " expected to fail, but succeeded.", null);
+    }
+
+    /**
+     * Make sure all URLs are accessible with all arguments = null.
+     */
+    public void testSelect() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            checkQueryExecutable(uri, // uri
+                    null, // projection
+                    null, // selection
+                    null, // selection args
+                    null // sort order
+            );
+        }
+        failIfFailed();
+    }
+
+    public void testNoHiddenColumns() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            for (String column : getColumns(uri)) {
+                if (column.toLowerCase().startsWith(ContactsContract.HIDDEN_COLUMN_PREFIX)) {
+                    addFailure("Uri " + uri + " returned hidden column " + column, null);
+                }
+            }
+        }
+        failIfFailed();
+    }
+
+    /**
+     * Make sure all URLs are accessible with a projection.
+     */
+    public void testSelectWithProjection() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            for (String column : getColumns(uri)) {
+                // Some columns are not selectable alone due to bugs, and we don't want to fix them
+                // in order to avoid expanding the differences between versions, so here're some
+                // hacks to make it work...
+
+                String[] projection = {column};
+
+                final String u = path[0];
+                if ((u.startsWith("content://com.android.contacts/status_updates")
+                        || u.startsWith("content://com.android.contacts/profile/status_updates"))
+                        && ("im_handle".equals(column)
+                        || "im_account".equals(column)
+                        || "protocol".equals(column)
+                        || "custom_protocol".equals(column)
+                        || "presence_raw_contact_id".equals(column)
+                )) {
+                    // These columns only show up when the projection contains certain columns.
+
+                    projection = new String[]{"mode", column};
+                } else if ((u.startsWith("content://com.android.contacts/search_suggest_query")
+                        || u.startsWith("content://contacts/search_suggest_query"))
+                        && "suggest_intent_action".equals(column)) {
+                    // Can't be included in the projection due to a bug in GlobalSearchSupport.
+                    continue;
+                } else if (RawContacts.BACKUP_ID.equals(column)) {
+                    // Some URIs don't support a projection with BAKCUP_ID only.
+                    projection = new String[]{RawContacts.BACKUP_ID, RawContacts.SOURCE_ID};
+                }
+
+                checkQueryExecutable(uri,
+                        projection, // projection
+                        null, // selection
+                        null, // selection args
+                        null // sort order
+                );
+            }
+        }
+        failIfFailed();
+    }
+
+    /**
+     * Make sure all URLs are accessible with a selection.
+     */
+    public void testSelectWithSelection() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            checkQueryExecutable(uri,
+                    null, // projection
+                    "1=?", // selection
+                    ARG1, // , // selection args
+                    null // sort order
+            );
+        }
+        failIfFailed();
+    }
+
+//    /**
+//     * Make sure all URLs are accessible with a selection.
+//     */
+//    public void testSelectWithSelectionUsingColumns() {
+//        for (String[] path : URIs) {
+//            if (!supportsQuery(path)) continue;
+//            final Uri uri = getUri(path);
+//
+//            for (String column : getColumns(uri)) {
+//                checkQueryExecutable(uri,
+//                        null, // projection
+//                        column + "=?", // selection
+//                        ARG1, // , // selection args
+//                        null // sort order
+//                );
+//            }
+//        }
+//        failIfFailed();
+//    }
+
+    /**
+     * Make sure all URLs are accessible with an order-by.
+     */
+    public void testSelectWithSortOrder() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            for (String column : getColumns(uri)) {
+                checkQueryExecutable(uri,
+                        null, // projection
+                        "1=2", // selection
+                        null, // , // selection args
+                        column // sort order
+                );
+            }
+        }
+        failIfFailed();
+    }
+
+    /**
+     * Make sure all URLs are accessible with all arguments.
+     */
+    public void testSelectWithAllArgs() {
+        for (String[] path : URIs) {
+            if (!supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            final String[] projection = {getColumns(uri)[0]};
+
+            checkQueryExecutable(uri,
+                    projection, // projection
+                    "1=?", // selection
+                    ARG1, // , // selection args
+                    getColumns(uri)[0] // sort order
+            );
+        }
+        failIfFailed();
+    }
+
+    public void testNonSelect() {
+        for (String[] path : URIs) {
+            if (supportsQuery(path)) continue;
+            final Uri uri = getUri(path);
+
+            checkQueryNotExecutable(uri, // uri
+                    null, // projection
+                    null, // selection
+                    null, // selection args
+                    null // sort order
+            );
+        }
+        failIfFailed();
+    }
+
+    private static boolean supportsTimesContacted(String[] path) {
+        return path.length > 1 && path[1].contains("s");
+    }
+
+    private static boolean supportsTimesUsed(String[] path) {
+        return path.length > 1 && path[1].contains("t");
+    }
+
+    private void checkColumnAccessible(Uri uri, String column) {
+        try {
+            try (Cursor c = mResolver.query(
+                    uri, new String[]{column}, column + "=0", null, column
+            )) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+    }
+
+    /** Test for {@link #checkColumnAccessible} */
+    public void testCheckColumnAccessible() {
+        checkColumnAccessible(Contacts.CONTENT_URI, "x_times_contacted");
+        try {
+            failIfFailed();
+        } catch (AssertionFailedError expected) {
+            return; // expected.
+        }
+        fail("Failed to detect issue.");
+    }
+
+    private void checkColumnNotAccessibleInner(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        try {
+            try (Cursor c = mResolver.query(uri, projection, selection,
+                    selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (IllegalArgumentException th) {
+            // pass.
+            return;
+        }
+        addFailure("Query on " + uri +
+                " expected to throw IllegalArgumentException, but succeeded.", null);
+    }
+
+    private void checkColumnNotAccessible(Uri uri, String column) {
+        checkColumnNotAccessibleInner(uri, new String[] {column}, null, null, null);
+        checkColumnNotAccessibleInner(uri, null, column + "=1", null, null);
+        checkColumnNotAccessibleInner(uri, null, null, null, /* order by */ column);
+    }
+
+    /** Test for {@link #checkColumnNotAccessible} */
+    public void testCheckColumnNotAccessible() {
+        checkColumnNotAccessible(Contacts.CONTENT_URI, "times_contacted");
+        try {
+            failIfFailed();
+        } catch (AssertionFailedError expected) {
+            return; // expected.
+        }
+        fail("Failed to detect issue.");
+    }
+
+    /**
+     * Make sure the x_ columns are not accessible.
+     */
+    public void testProhibitedColumns() {
+        for (String[] path : URIs) {
+            final Uri uri = getUri(path);
+            if (supportsTimesContacted(path)) {
+                checkColumnAccessible(uri, "times_contacted");
+                checkColumnAccessible(uri, "last_time_contacted");
+
+                checkColumnNotAccessible(uri, "X_times_contacted");
+                checkColumnNotAccessible(uri, "X_slast_time_contacted");
+            }
+            if (supportsTimesUsed(path)) {
+                checkColumnAccessible(uri, "times_used");
+                checkColumnAccessible(uri, "last_time_used");
+
+                checkColumnNotAccessible(uri, "X_times_used");
+                checkColumnNotAccessible(uri, "X_last_time_used");
+            }
+        }
+        failIfFailed();
+    }
+
+    private void checkExecutable(String operation, Uri uri, boolean shouldWork, Runnable r) {
+        if (shouldWork) {
+            try {
+                r.run();
+            } catch (Exception e) {
+                addFailure(operation + " for '" + uri + "' failed: " + e.getMessage(), e);
+            }
+        } else {
+            try {
+                r.run();
+                addFailure(operation + " for '" + uri + "' NOT failed.", null);
+            } catch (Exception expected) {
+            }
+        }
+    }
+
+    public void testAllOperations() {
+        final ContentValues cv = new ContentValues();
+
+        for (String[] path : URIs) {
+            final Uri uri = getUri(path);
+
+            cv.clear();
+            if (supportsQuery(path)) {
+                cv.put(getColumns(uri)[0], 1);
+            } else {
+                cv.put("_id", 1);
+            }
+            if (uri.toString().contains("syncstate")) {
+                cv.put(SyncState.ACCOUNT_NAME, "abc");
+                cv.put(SyncState.ACCOUNT_TYPE, "def");
+            }
+
+            checkExecutable("insert", uri, supportsInsert(path), () -> {
+                final Uri newUri = mResolver.insert(uri, cv);
+                if (newUri == null) {
+                    addFailure("Insert for '" + uri + "' returned null.", null);
+                } else {
+                    // "profile/raw_contacts/#" is missing update support.  too late to add, so
+                    // just skip.
+                    if (!newUri.toString().startsWith(
+                            "content://com.android.contacts/profile/raw_contacts/")) {
+                        checkExecutable("insert -> update", newUri, true, () -> {
+                            mResolver.update(newUri, cv, null, null);
+                        });
+                    }
+                    checkExecutable("insert -> delete", newUri, true, () -> {
+                        mResolver.delete(newUri, null, null);
+                    });
+                }
+            });
+            checkExecutable("update", uri, supportsUpdate(path), () -> {
+                mResolver.update(uri, cv, "1=2", null);
+            });
+            checkExecutable("delete", uri, supportsDelete(path), () -> {
+                mResolver.delete(uri, "1=2", null);
+            });
+        }
+        failIfFailed();
+    }
+
+    public void testAllFileOperations() {
+        for (String[] path : URIs) {
+            final Uri uri = getUri(path);
+
+            checkExecutable("openInputStream", uri, supportsRead(path), () -> {
+                try (InputStream st = mResolver.openInputStream(uri)) {
+                } catch (FileNotFoundException e) {
+                    // TODO This happens because we try to read nonexistent photos.  Ideally
+                    // we should actually check it's readable.
+                    if (e.getMessage().contains("Stream I/O not supported")) {
+                        throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                    }
+                } catch (Exception e) {
+                    throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                }
+            });
+            checkExecutable("openOutputStream", uri, supportsWrite(path), () -> {
+                try (OutputStream st = mResolver.openOutputStream(uri)) {
+                } catch (Exception e) {
+                    throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                }
+            });
+        }
+        failIfFailed();
+    }
+}
+
+
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..d625625 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,8 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
 import android.provider.cts.contacts.ContactUtil;
@@ -65,20 +67,54 @@
     public void testMarkAsContacted() throws Exception {
         TestRawContact rawContact = mBuilder.newRawContact().insert().load();
         TestContact contact = rawContact.getContact().load();
-        long oldLastContacted = contact.getLong(Contacts.LAST_TIME_CONTACTED);
 
-        Contacts.markAsContacted(mResolver, contact.getId());
-        contact.load(); // Reload
+        assertEquals(0, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+        assertEquals(0, contact.getLong(Contacts.TIMES_CONTACTED));
 
-        long lastContacted = contact.getLong(Contacts.LAST_TIME_CONTACTED);
-        assertTrue(oldLastContacted < lastContacted);
-        oldLastContacted = lastContacted;
+        assertEquals(0, rawContact.getLong(Contacts.LAST_TIME_CONTACTED));
+        assertEquals(0, rawContact.getLong(Contacts.TIMES_CONTACTED));
 
-        Contacts.markAsContacted(mResolver, contact.getId());
-        contact.load();
+        for (int i = 0; i < 9; i++) {
+            Contacts.markAsContacted(mResolver, contact.getId());
+            contact.load();
+            rawContact.load();
 
-        lastContacted = contact.getLong(Contacts.LAST_TIME_CONTACTED);
-        assertTrue(oldLastContacted < lastContacted);
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    contact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 1, contact.getLong(Contacts.TIMES_CONTACTED));
+
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    rawContact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 1, rawContact.getLong(Contacts.TIMES_CONTACTED));
+        }
+
+        for (int i = 0; i < 10; i++) {
+            Contacts.markAsContacted(mResolver, contact.getId());
+            contact.load();
+            rawContact.load();
+
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    contact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 10, contact.getLong(Contacts.TIMES_CONTACTED));
+
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    rawContact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 10, rawContact.getLong(Contacts.TIMES_CONTACTED));
+        }
+
+        for (int i = 0; i < 10; i++) {
+            Contacts.markAsContacted(mResolver, contact.getId());
+            contact.load();
+            rawContact.load();
+
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    contact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 20, contact.getLong(Contacts.TIMES_CONTACTED));
+
+            assertEquals(System.currentTimeMillis() / 86400 * 86400,
+                    rawContact.getLong(Contacts.LAST_TIME_CONTACTED));
+            assertEquals("#" + i, 20, rawContact.getLong(Contacts.TIMES_CONTACTED));
+        }
     }
 
     public void testContentUri() {
@@ -168,6 +204,94 @@
         RawContactUtil.delete(mResolver, ids.mRawContactId, true);
     }
 
+    public void testContactUpdate_usageStats() throws Exception {
+        final TestRawContact rawContact = mBuilder.newRawContact().insert().load();
+        final TestContact contact = rawContact.getContact().load();
+
+        contact.load();
+        assertEquals(0L, contact.getLong(Contacts.TIMES_CONTACTED));
+        assertEquals(0L, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+
+        final long now = System.currentTimeMillis();
+
+        // TIMES_CONTACTED will be ignored, so this will be the same thing as markAsContacted().
+        ContentValues values = new ContentValues();
+        values.clear();
+        values.put(Contacts.TIMES_CONTACTED, 99999);
+        values.put(Contacts.LAST_TIME_CONTACTED, now);
+        ContactUtil.update(mResolver, contact.getId(), values);
+
+        contact.load();
+        assertEquals(1L, contact.getLong(Contacts.TIMES_CONTACTED));
+        assertEquals(now / 86400 * 86400, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+
+        // This is also the same as markAsContacted().
+        values.clear();
+        values.put(Contacts.LAST_TIME_CONTACTED, now);
+        ContactUtil.update(mResolver, contact.getId(), values);
+
+        contact.load();
+        assertEquals(1L, contact.getLong(Contacts.TIMES_CONTACTED));
+        assertEquals(now / 86400 * 86400, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+
+        // This will just be ignored.
+        values.clear();
+        values.put(Contacts.TIMES_CONTACTED, 99999);
+
+        ContactUtil.update(mResolver, contact.getId(), values);
+
+        contact.load();
+        assertEquals(1L, contact.getLong(Contacts.TIMES_CONTACTED));
+        assertEquals(now / 86400 * 86400, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+    }
+
+    /**
+     * Make sure the rounded usage stats values are also what the callers would see in where
+     * clauses.
+     *
+     * This tests both contacts and raw_contacts.
+     */
+    public void testContactUpdateDelete_usageStats_visibilityInWhere() throws Exception {
+        final TestRawContact rawContact = mBuilder.newRawContact().insert().load();
+        final TestContact contact = rawContact.getContact().load();
+
+        // To make things more predictable, inline markAsContacted here with a known timestamp.
+        final long now = (System.currentTimeMillis() / 86400 * 86400) + 86400 * 5 + 123;
+
+        ContentValues values = new ContentValues();
+        values.put(Contacts.LAST_TIME_CONTACTED, now);
+
+        // This makes the internal TIMES_CONTACTED 35.  But the visible value is still 30.
+        for (int i = 0; i < 35; i++) {
+            ContactUtil.update(mResolver, contact.getId(), values);
+        }
+
+        contact.load();
+        rawContact.load();
+
+        assertEquals(now / 86400 * 86400, contact.getLong(Contacts.LAST_TIME_CONTACTED));
+        assertEquals(30, contact.getLong(Contacts.TIMES_CONTACTED));
+
+        assertEquals(now / 86400 * 86400, rawContact.getLong(Contacts.LAST_TIME_CONTACTED));
+        assertEquals(30, rawContact.getLong(Contacts.TIMES_CONTACTED));
+
+        final ContentValues cv = new ContentValues();
+            cv.put(Contacts.STARRED, 1);
+
+        final String where =
+                (Contacts.LAST_TIME_CONTACTED + "=P1 AND " + Contacts.TIMES_CONTACTED + "=P2")
+                        .replaceAll("P1", String.valueOf(now / 86400 * 86400))
+                        .replaceAll("P2", "30");
+        assertEquals(1, mResolver.update(Contacts.CONTENT_URI, cv, where, null));
+        assertEquals(1, mResolver.update(RawContacts.CONTENT_URI, cv, where, null));
+
+        // Also delete.  This will actually delete the row, so we can test it only for one of the
+        // contact or the raw contact.
+        assertEquals(1, mResolver.delete(RawContacts.CONTENT_URI, where, null));
+        rawContact.setAlreadyDeleted();
+        contact.setAlreadyDeleted();
+    }
+
     public void testProjection() throws Exception {
         final TestRawContact rawContact = mBuilder.newRawContact().insert().load();
         rawContact.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
@@ -228,6 +352,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_DataUsageTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataUsageTest.java
index d585ec2..367ac30 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_DataUsageTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataUsageTest.java
@@ -22,6 +22,7 @@
 import android.content.ContentValues;
 import android.net.Uri;
 import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
 import android.provider.cts.contacts.DataUtil;
 import android.provider.cts.contacts.DatabaseAsserts;
 import android.provider.cts.contacts.RawContactUtil;
@@ -45,14 +46,43 @@
 
         // Update just 1 data item at a time.
         updateDataUsageAndAssert(dataIds[1], 1);
-        updateDataUsageAndAssert(dataIds[1], 2);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 1);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 10);
 
         updateDataUsageAndAssert(dataIds[2], 1);
-        updateDataUsageAndAssert(dataIds[2], 2);
-        updateDataUsageAndAssert(dataIds[2], 3);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
 
         // Go back and update the previous data item again.
-        updateDataUsageAndAssert(dataIds[1], 3);
+        updateDataUsageAndAssert(dataIds[1], 10);
+        updateDataUsageAndAssert(dataIds[1], 20);
+
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 1);
+        updateDataUsageAndAssert(dataIds[2], 10);
+
+        updateDataUsageAndAssert(dataIds[1], 20);
+        updateDataUsageAndAssert(dataIds[1], 20);
+        updateDataUsageAndAssert(dataIds[1], 20);
 
         deleteDataUsage();
         RawContactUtil.delete(mResolver, ids.mRawContactId, true);
@@ -69,13 +99,15 @@
         assertDataUsageEquals(dataIds, 0, 1, 1, 0);
 
         updateMultipleAndAssertUpdateSuccess(new long[]{dataIds[1], dataIds[2]});
-        assertDataUsageEquals(dataIds, 0, 2, 2, 0);
+        assertDataUsageEquals(dataIds, 0, 1, 1, 0);
 
-        updateDataUsageAndAssert(dataIds[1], 3);
-        assertDataUsageEquals(dataIds, 0, 3, 2, 0);
+        for (int i = 0; i < 8; i++) {
+            updateMultipleAndAssertUpdateSuccess(new long[]{dataIds[1]});
+        }
+        assertDataUsageEquals(dataIds, 0, 10, 1, 0);
 
         updateMultipleAndAssertUpdateSuccess(new long[]{dataIds[0], dataIds[1]});
-        assertDataUsageEquals(dataIds, 1, 4, 2, 0);
+        assertDataUsageEquals(dataIds, 1, 10, 1, 0);
 
         deleteDataUsage();
         RawContactUtil.delete(mResolver, ids.mRawContactId, true);
@@ -147,6 +179,10 @@
             actual = Long.parseLong(record[0]);
         }
         assertEquals(expectedValue, actual);
+
+        // Also make sure the rounded value is used in 'where' too.
+        assertEquals("Query should match", 1, DataUtil.queryById(mResolver, dataId, projection,
+                "ifnull(" + Data.TIMES_USED + ",0)=" + expectedValue, null).length);
     }
 
     private void deleteDataUsage() {
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_DirectoryTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_DirectoryTest.java
new file mode 100644
index 0000000..a8bff00
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_DirectoryTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.provider.cts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
+import android.provider.cts.contacts.DummyGalProvider;
+import android.test.AndroidTestCase;
+
+import org.json.JSONObject;
+
+/**
+ * Note, this test creates an account in setUp() and removes it in tearDown(), which causes
+ * a churn in the contacts provider.  So this class should have only one test method and do all
+ * the check in there, so it won't create the account multiple times.
+ */
+public class ContactsContract_DirectoryTest extends AndroidTestCase {
+    private ContentResolver mResolver;
+    private AccountManager mAccountManager;
+    private Account mAccount;
+
+    private static final int DIRECTORY_WAIT_TIMEOUT_SEC = 60;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mResolver = getContext().getContentResolver();
+
+        mAccountManager = getContext().getSystemService(AccountManager.class);
+        mAccount = new Account(DummyGalProvider.ACCOUNT_NAME, DummyGalProvider.ACCOUNT_TYPE);
+
+        // The directory table is populated asynchronously.  Wait for it...
+        waitForDirectorySetup();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mAccountManager.removeAccountExplicitly(mAccount);
+
+        super.tearDown();
+    }
+
+    private static String getString(Cursor c, String column) {
+        return c.getString(c.getColumnIndex(column));
+    }
+
+    /**
+     * Wait until the directory row is populated in the directory table, and return its ID.
+     */
+    private long waitForDirectorySetup() throws Exception {
+        final long timeout = SystemClock.elapsedRealtime() + DIRECTORY_WAIT_TIMEOUT_SEC * 1000;
+
+        while (SystemClock.elapsedRealtime() < timeout) {
+            try (Cursor c = getContext().getContentResolver().query(Directory.CONTENT_URI,
+                    null, Directory.ACCOUNT_NAME + "=? and " + Directory.ACCOUNT_TYPE + "=?",
+                    new String[]{DummyGalProvider.ACCOUNT_NAME, DummyGalProvider.ACCOUNT_TYPE},
+                    null)) {
+                if (c.getCount() == 0) {
+                    Thread.sleep(1000);
+                    continue;
+                }
+                assertTrue(c.moveToPosition(0));
+                assertEquals(getContext().getPackageName(), getString(c, Directory.PACKAGE_NAME));
+                assertEquals(DummyGalProvider.AUTHORITY,
+                        getString(c, Directory.DIRECTORY_AUTHORITY));
+                assertEquals(DummyGalProvider.DISPLAY_NAME, getString(c, Directory.DISPLAY_NAME));
+                assertEquals(DummyGalProvider.ACCOUNT_NAME, getString(c, Directory.ACCOUNT_NAME));
+                assertEquals(DummyGalProvider.ACCOUNT_TYPE, getString(c, Directory.ACCOUNT_TYPE));
+                return c.getLong(c.getColumnIndex(Directory._ID));
+            }
+        }
+        fail("Directory didn't show up");
+        return -1;
+    }
+
+    public void testQueryParameters() throws Exception {
+        // Test for content types.
+        assertEquals(Directory.CONTENT_TYPE, mResolver.getType(Directory.CONTENT_URI));
+        assertEquals(Directory.CONTENT_ITEM_TYPE, mResolver.getType(
+                Directory.CONTENT_URI.buildUpon().appendPath("1").build()));
+
+
+        // Get the directory ID.
+        final long directoryId = waitForDirectorySetup();
+
+        final Uri queryUri = Contacts.CONTENT_FILTER_URI.buildUpon()
+                .appendPath("[QUERY]")
+                .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "12")
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, "" + directoryId)
+
+                // This should be ignored.
+                .appendQueryParameter(Directory.CALLER_PACKAGE_PARAM_KEY, "abcdef")
+                .build();
+
+        try (Cursor c = getContext().getContentResolver().query(
+                queryUri, null, null, null, null)) {
+
+            DatabaseUtils.dumpCursor(c);
+
+            assertNotNull(c);
+            assertEquals(1, c.getCount());
+
+            assertTrue(c.moveToPosition(0));
+
+            // The result is stored in the display_name column.
+            final JSONObject result = new JSONObject(getString(c, Contacts.DISPLAY_NAME));
+
+            if (result.has(DummyGalProvider.ERROR_MESSAGE_KEY)) {
+                fail(result.getString(DummyGalProvider.ERROR_MESSAGE_KEY));
+            }
+
+            assertEquals("12", result.getString(DummyGalProvider.LIMIT_KEY));
+            assertEquals("[QUERY]", result.getString(DummyGalProvider.QUERY_KEY));
+            assertEquals(getContext().getPackageName(),
+                    result.getString(DummyGalProvider.CALLER_PACKAGE_NAME_KEY));
+        }
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_PhotoTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_PhotoTest.java
index 8c97c22..b91022d 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_PhotoTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_PhotoTest.java
@@ -19,7 +19,6 @@
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.cts.util.FileUtils;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.Contacts;
@@ -28,6 +27,8 @@
 import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.FileUtils;
+
 import java.io.IOException;
 import java.io.InputStream;
 
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_RawContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_RawContactsTest.java
index 49b3ff5..35ced41 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_RawContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_RawContactsTest.java
@@ -23,7 +23,6 @@
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
 import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
@@ -236,4 +235,77 @@
                 new long[]{rawContact.getId()}
         );
     }
+
+    public void testInsertUsageStat() throws Exception {
+        final long now = System.currentTimeMillis();
+        {
+            TestRawContact rawContact = mBuilder.newRawContact()
+                    .with(RawContacts.ACCOUNT_TYPE, "test_type")
+                    .with(RawContacts.ACCOUNT_NAME, "test_name")
+                    .with(RawContacts.TIMES_CONTACTED, 12345) // should be ignored.
+                    .with(RawContacts.LAST_TIME_CONTACTED, now)
+                    .insert();
+
+            rawContact.load();
+            assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+            assertEquals(now / 86400 * 86400, rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+        }
+
+        {
+            TestRawContact rawContact = mBuilder.newRawContact()
+                    .with(RawContacts.ACCOUNT_TYPE, "test_type")
+                    .with(RawContacts.ACCOUNT_NAME, "test_name")
+                    .with(RawContacts.TIMES_CONTACTED, 12345) // should be ignored.
+                    .insert();
+
+            rawContact.load();
+            assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+            assertEquals(0, rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+        }
+        {
+            TestRawContact rawContact = mBuilder.newRawContact()
+                    .with(RawContacts.ACCOUNT_TYPE, "test_type")
+                    .with(RawContacts.ACCOUNT_NAME, "test_name")
+                    .with(RawContacts.LAST_TIME_CONTACTED, now)
+                    .insert();
+
+            rawContact.load();
+            assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+            assertEquals(now / 86400 * 86400, rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+        }
+    }
+
+    public void testUpdateUsageStat() throws Exception {
+        ContentValues values = new ContentValues();
+
+        final long now = System.currentTimeMillis();
+        TestRawContact rawContact = mBuilder.newRawContact()
+                .with(RawContacts.ACCOUNT_TYPE, "test_type")
+                .with(RawContacts.ACCOUNT_NAME, "test_name")
+                .with(RawContacts.TIMES_CONTACTED, 12345) // should be ignored.
+                .with(RawContacts.LAST_TIME_CONTACTED, now)
+                .insert();
+
+        rawContact.load();
+        assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+        assertEquals(now / 86400 * 86400, rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+
+        values.clear();
+        values.put(RawContacts.TIMES_CONTACTED, 99999);
+        RawContactUtil.update(mResolver, rawContact.getId(), values);
+
+        // Shouldn't change.
+        rawContact.load();
+        assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+        assertEquals(now / 86400 * 86400, rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+
+        values.clear();
+        values.put(RawContacts.LAST_TIME_CONTACTED, now + 86400);
+        RawContactUtil.update(mResolver, rawContact.getId(), values);
+
+        rawContact.load();
+        assertEquals(0L, rawContact.getLong(RawContacts.TIMES_CONTACTED));
+        assertEquals((now / 86400 * 86400) + 86400,
+                rawContact.getLong(RawContacts.LAST_TIME_CONTACTED));
+    }
 }
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/provider/src/android/provider/cts/ContactsContract_TestDataBuilder.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_TestDataBuilder.java
index 471f895..6384385 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_TestDataBuilder.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_TestDataBuilder.java
@@ -62,6 +62,7 @@
         private Uri mUri;
         private long mId = -1;
         private Cursor mCursor;
+        private boolean mAlreadyDeleted;
 
         protected abstract Uri getContentUri();
 
@@ -139,6 +140,9 @@
         }
 
         public void deletePermanently() throws Exception {
+            if (mAlreadyDeleted) {
+                return;
+            }
             Uri uri = getUri().buildUpon()
                     .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
                     .build();
@@ -194,6 +198,10 @@
             return (T)this;
         }
 
+        public boolean isNull(String columnName) {
+            return mCursor.isNull(mCursor.getColumnIndex(columnName));
+        }
+
         public long getLong(String columnName) {
             return mCursor.getLong(mCursor.getColumnIndex(columnName));
         }
@@ -250,6 +258,9 @@
             mLoadedRows.remove(this);
         }
 
+        public void setAlreadyDeleted() {
+            mAlreadyDeleted = true;
+        }
     }
 
     public class TestRawContact extends Builder<TestRawContact> {
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
index 3b71d49..36906ad 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsTest.java
@@ -125,10 +125,10 @@
             assertTrue(cursor.moveToNext());
             assertEquals(updatePeopleName, cursor.getString(NAME_INDEX));
             assertEquals(updatePeopleNotes, cursor.getString(NOTES_INDEX));
-            assertEquals((int) now, cursor.getInt(LAST_TIME_CONTACTED_INDEX));
+            assertEquals(0, cursor.getInt(LAST_TIME_CONTACTED_INDEX)); // Not supported by CP1
             assertNull(cursor.getString(CUSTOM_RINGTONE_INDEX));
-            assertEquals(1, cursor.getInt(SEND_TO_VOICEMAIL_INDEX));
-            assertEquals(1, cursor.getInt(TIMES_CONTACTED_INDEX));
+            assertEquals(1, cursor.getInt(SEND_TO_VOICEMAIL_INDEX)); // Not supported by CP1
+            assertEquals(0, cursor.getInt(TIMES_CONTACTED_INDEX));
             assertEquals(0, cursor.getInt(STARRED_INDEX));
             // TODO: Figure out what can be tested for the SYNC_* columns
             cursor.close();
diff --git a/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java b/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
index d887aa7..53dda2e 100644
--- a/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Contacts_PeopleTest.java
@@ -50,10 +50,12 @@
 
     private static final String[] PEOPLE_PROJECTION = new String[] {
             People._ID,
-            People.LAST_TIME_CONTACTED
+            People.LAST_TIME_CONTACTED,
+            People.TIMES_CONTACTED
         };
     private static final int PEOPLE_ID_INDEX = 0;
     private static final int PEOPLE_LAST_CONTACTED_INDEX = 1;
+    private static final int PEOPLE_TIMES_CONTACTED_INDEX = 1;
 
     private static final String[] GROUPS_PROJECTION = new String[] {
         Groups._ID,
@@ -230,23 +232,16 @@
                     null, null, null, null);
             cursor.moveToFirst();
             int personId = cursor.getInt(PEOPLE_ID_INDEX);
-            long oldLastContacted = cursor.getLong(PEOPLE_LAST_CONTACTED_INDEX);
-            cursor.close();
-            People.markAsContacted(mContentResolver, personId);
-            cursor = mProvider.query(mPeopleRowsAdded.get(0), PEOPLE_PROJECTION,
-                    null, null, null, null);
-            cursor.moveToFirst();
-            long lastContacted = cursor.getLong(PEOPLE_LAST_CONTACTED_INDEX);
-            assertTrue(oldLastContacted < lastContacted);
-            oldLastContacted = lastContacted;
+            assertEquals(0, cursor.getLong(PEOPLE_LAST_CONTACTED_INDEX));
+            assertEquals(0, cursor.getLong(PEOPLE_TIMES_CONTACTED_INDEX));
             cursor.close();
 
             People.markAsContacted(mContentResolver, personId);
             cursor = mProvider.query(mPeopleRowsAdded.get(0), PEOPLE_PROJECTION,
                     null, null, null, null);
             cursor.moveToFirst();
-            lastContacted = cursor.getLong(PEOPLE_LAST_CONTACTED_INDEX);
-            assertTrue(oldLastContacted < lastContacted);
+            assertEquals(0, cursor.getLong(PEOPLE_LAST_CONTACTED_INDEX));
+            assertEquals(0, cursor.getLong(PEOPLE_TIMES_CONTACTED_INDEX));
             cursor.close();
         } catch (RemoteException e) {
             fail("Unexpected RemoteException");
diff --git a/tests/tests/provider/src/android/provider/cts/GetResultActivity.java b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
new file mode 100644
index 0000000..382ca6f
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
@@ -0,0 +1,72 @@
+/*
+ * 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.provider.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+public class GetResultActivity extends Activity {
+    private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+
+    public static class Result {
+        public final int requestCode;
+        public final int resultCode;
+        public final Intent data;
+
+        public Result(int requestCode, int resultCode, Intent data) {
+            this.requestCode = requestCode;
+            this.resultCode = resultCode;
+            this.data = data;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        try {
+            mResult.offer(new Result(requestCode, resultCode, data), 5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Result getResult() {
+        final Result result;
+        try {
+            result = mResult.poll(30, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        if (result == null) {
+            throw new IllegalStateException("Activity didn't receive a Result in 30 seconds");
+        }
+        return result;
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
new file mode 100644
index 0000000..3ede99c
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.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.provider.cts;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriPermission;
+import android.content.pm.PackageManager;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.cts.GetResultActivity.Result;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MediaStoreUiTest extends InstrumentationTestCase {
+
+    private static final int REQUEST_CODE = 42;
+    private static final String CONTENT = "Test";
+
+    private UiDevice mDevice;
+    private GetResultActivity mActivity;
+
+    private File mFile;
+    private Uri mMediaStoreUri;
+
+    @Override
+    public void setUp() throws Exception {
+        mDevice = UiDevice.getInstance(getInstrumentation());
+
+        final Context context = getInstrumentation().getContext();
+        mActivity = launchActivity(context.getPackageName(), GetResultActivity.class, null);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (mFile != null) {
+            mFile.delete();
+        }
+
+        final ContentResolver resolver = mActivity.getContentResolver();
+        for (UriPermission permission : resolver.getPersistedUriPermissions()) {
+            mActivity.revokeUriPermission(
+                    permission.getUri(),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION
+                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        }
+
+        mActivity.finish();
+    }
+
+    public void testGetDocumentUri() throws Exception {
+        if (!supportsHardware()) return;
+
+        prepareFile();
+
+        final Uri treeUri = acquireAccess(mFile, Environment.DIRECTORY_DOCUMENTS);
+        assertNotNull(treeUri);
+
+        final Uri docUri = MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+        assertNotNull(docUri);
+
+        final ContentResolver resolver = mActivity.getContentResolver();
+        try (ParcelFileDescriptor fd = resolver.openFileDescriptor(docUri, "rw")) {
+            // Test reading
+            try (final BufferedReader reader =
+                         new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
+                assertEquals(CONTENT, reader.readLine());
+            }
+
+            // Test writing
+            try (final OutputStream out = new FileOutputStream(fd.getFileDescriptor())) {
+                out.write(CONTENT.getBytes());
+            }
+        }
+    }
+
+    public void testGetDocumentUri_ThrowsWithoutPermission() throws Exception {
+        if (!supportsHardware()) return;
+
+        prepareFile();
+
+        try {
+            MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+            fail("Expecting SecurityException.");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+
+    private boolean supportsHardware() {
+        final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        return !pm.hasSystemFeature("android.hardware.type.television")
+                && !pm.hasSystemFeature("android.hardware.type.watch");
+    }
+
+    private void prepareFile() throws Exception {
+        assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+
+        final File documents =
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
+        documents.mkdirs();
+        assertTrue(documents.isDirectory());
+
+        mFile = new File(documents, "test.txt");
+        try (OutputStream os = new FileOutputStream(mFile)) {
+            os.write(CONTENT.getBytes());
+        }
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        MediaScannerConnection.scanFile(
+                mActivity,
+                new String[]{ mFile.getAbsolutePath() },
+                new String[]{ "plain/text" },
+                (String path, Uri uri) -> onScanCompleted(uri, latch)
+        );
+        assertTrue(
+                "MediaScanner didn't finish scanning in 30s.", latch.await(30, TimeUnit.SECONDS));
+    }
+
+    private void onScanCompleted(Uri uri, CountDownLatch latch) {
+        mMediaStoreUri = uri;
+        latch.countDown();
+    }
+
+    private Uri acquireAccess(File file, String directoryName) {
+        StorageManager storageManager =
+                (StorageManager) mActivity.getSystemService(Context.STORAGE_SERVICE);
+
+        // Request access from DocumentsUI
+        final StorageVolume volume = storageManager.getStorageVolume(file);
+        final Intent intent = volume.createAccessIntent(directoryName);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+        // Granting the access
+        BySelector buttonPanelSelector = By.pkg("com.android.documentsui")
+                .res("android:id/buttonPanel");
+        mDevice.wait(Until.hasObject(buttonPanelSelector), 30 * DateUtils.SECOND_IN_MILLIS);
+        final UiObject2 buttonPanel = mDevice.findObject(buttonPanelSelector);
+        final UiObject2 allowButton = buttonPanel.findObject(By.res("android:id/button1"));
+        allowButton.click();
+
+        mDevice.waitForIdle();
+
+        // Check granting result and take persistent permission
+        final Result result = mActivity.getResult();
+        assertEquals(Activity.RESULT_OK, result.resultCode);
+
+        final Intent resultIntent = result.data;
+        final Uri resultUri = resultIntent.getData();
+        final int flags = resultIntent.getFlags()
+                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        mActivity.getContentResolver().takePersistableUriPermission(resultUri, flags);
+        return resultUri;
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
index 3bd81ce..9c9d9ca 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
@@ -21,7 +21,6 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.res.AssetFileDescriptor;
-import android.cts.util.FileCopyHelper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -32,6 +31,8 @@
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index 8fe95f5..d0db60d 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -22,7 +22,6 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -33,6 +32,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index 1c00aac..7a66c8c 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -21,8 +21,6 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
-import android.cts.util.FileUtils;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -34,6 +32,9 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+import com.android.compatibility.common.util.FileUtils;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.lang.Math;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
index db3db6b..62a041b 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
@@ -22,7 +22,6 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -34,6 +33,8 @@
 import android.provider.MediaStore.MediaColumns;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+
 import java.io.File;
 import java.util.ArrayList;
 import android.util.DisplayMetrics;
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
index e50f18a..8ba8c17 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
@@ -21,13 +21,14 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore.Video;
 import android.provider.MediaStore.Video.VideoColumns;
 import android.test.InstrumentationTestCase;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+
 import java.util.ArrayList;
 
 public class MediaStore_VideoTest extends InstrumentationTestCase {
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 485b39c..14e76bb 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -22,8 +22,6 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.FileCopyHelper;
-import android.cts.util.FileUtils;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -32,6 +30,9 @@
 import android.provider.MediaStore.Video.VideoColumns;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+import com.android.compatibility.common.util.FileUtils;
+
 import java.io.File;
 import java.io.IOException;
 
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
index 8e51cb8..26f353f 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
@@ -21,8 +21,6 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
-import android.cts.util.FileCopyHelper;
-import android.cts.util.MediaUtils;
 import android.database.Cursor;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
@@ -34,6 +32,9 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.FileCopyHelper;
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.IOException;
 
diff --git a/tests/tests/provider/src/android/provider/cts/PhotoUtil.java b/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
index 4debd8f..49d57a7 100644
--- a/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
+++ b/tests/tests/provider/src/android/provider/cts/PhotoUtil.java
@@ -19,7 +19,7 @@
 import android.provider.cts.R;
 
 import android.content.Context;
-import android.cts.util.FileUtils;
+import com.android.compatibility.common.util.FileUtils;
 
 import java.io.InputStream;
 
diff --git a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
index a17bcdd..ff79ae5 100644
--- a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
@@ -19,12 +19,13 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.SearchRecentSuggestions;
 import android.test.ProviderTestCase2;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 public class SearchRecentSuggestionsTest extends
         ProviderTestCase2<TestSearchRecentSuggestionsProvider> {
     private final static String AUTHORITY_HEAD = "content://"
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsTest.java b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
index 382f911..71de3bd 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
@@ -16,6 +16,8 @@
 
 package android.provider.cts;
 
+import com.android.compatibility.common.util.SystemUtil;
+
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -23,7 +25,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.cts.util.SystemUtil;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/DataUtil.java b/tests/tests/provider/src/android/provider/cts/contacts/DataUtil.java
index 1e07450..297a3b6 100644
--- a/tests/tests/provider/src/android/provider/cts/contacts/DataUtil.java
+++ b/tests/tests/provider/src/android/provider/cts/contacts/DataUtil.java
@@ -32,12 +32,17 @@
 
     private static final Uri URI = ContactsContract.Data.CONTENT_URI;
 
-    public static String[] queryById(ContentResolver resolver, long dataId, String[] projection) {
+    public static String[] queryById(ContentResolver resolver, long dataId, String[] projection,
+            String selection, String[] selectionArgs) {
         Uri uri = ContentUris.withAppendedId(URI, dataId);
-        Cursor cursor = resolver.query(uri, projection, null, null, null);
+        Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, null);
         return CommonDatabaseUtils.singleRecordToArray(cursor);
     }
 
+    public static String[] queryById(ContentResolver resolver, long dataId, String[] projection) {
+        return queryById(resolver, dataId, projection, null, null);
+    }
+
     public static void insertName(ContentResolver resolver, long rawContactId, String name) {
         ContentValues values = new ContentValues();
         values.put(ContactsContract.Data.MIMETYPE,
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/DummyGalProvider.java b/tests/tests/provider/src/android/provider/cts/contacts/DummyGalProvider.java
new file mode 100644
index 0000000..7609143
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/contacts/DummyGalProvider.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.provider.cts.contacts;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.cts.contacts.account.StaticAccountAuthenticator;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * GAL provider for CTS.
+ */
+public class DummyGalProvider extends ContentProvider {
+    private static final String TAG = "DummyGalProvider";
+
+    public static final String AUTHORITY = "android.provider.cts.contacts.dgp";
+
+    public static final String ACCOUNT_NAME = "dummygal";
+    public static final String ACCOUNT_TYPE = StaticAccountAuthenticator.TYPE;
+
+    public static final String DISPLAY_NAME = "dummy-gal";
+
+    public static final String ERROR_MESSAGE_KEY = "error";
+    public static final String QUERY_KEY = "query";
+    public static final String CALLER_PACKAGE_NAME_KEY = "package_name";
+    public static final String LIMIT_KEY = "limit";
+
+
+    private static final int GAL_DIRECTORIES = 0;
+    private static final int GAL_FILTER = 1;
+    private static final int GAL_CONTACT = 2;
+    private static final int GAL_CONTACT_WITH_ID = 3;
+    private static final int GAL_EMAIL_FILTER = 4;
+    private static final int GAL_PHONE_FILTER = 5;
+    private static final int GAL_PHONE_LOOKUP = 6;
+
+    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+    static {
+        sURIMatcher.addURI(AUTHORITY, "directories", GAL_DIRECTORIES);
+        sURIMatcher.addURI(AUTHORITY, "contacts/filter/*", GAL_FILTER);
+        // The following URIs are not supported by this class.
+//        sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT);
+//        sURIMatcher.addURI(AUTHORITY, "contacts/lookup/*/#/entities", GAL_CONTACT_WITH_ID);
+//        sURIMatcher.addURI(AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER);
+//        sURIMatcher.addURI(AUTHORITY, "data/phones/filter/*", GAL_PHONE_FILTER);
+//        sURIMatcher.addURI(AUTHORITY, "phone_lookup/*", GAL_PHONE_LOOKUP);
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        Log.d(TAG, "uri: " + uri);
+        final int match = sURIMatcher.match(uri);
+
+        switch (match) {
+            case GAL_DIRECTORIES: {
+                return handleDirectories(projection);
+            }
+            case GAL_FILTER: {
+                try {
+                    return handleFilter(uri, projection);
+                } catch (JSONException e) {
+                    Log.e(TAG, "Caught exception", e);
+                    return null;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    /**
+     * Build a cursor containing the directory information.
+     *
+     * See com.android.providers.contacts.ContactDirectoryManager.
+     */
+    private Cursor handleDirectories(String[] projection) {
+        MatrixCursor cursor;
+        Object[] row;
+        cursor = new MatrixCursor(projection);
+
+        row = new Object[projection.length];
+
+        for (int i = 0; i < projection.length; i++) {
+            String column = projection[i];
+            if (column.equals(Directory.ACCOUNT_NAME)) {
+                row[i] = ACCOUNT_NAME;
+            } else if (column.equals(Directory.ACCOUNT_TYPE)) {
+                row[i] = ACCOUNT_TYPE;
+            } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
+                row[i] = "";
+            } else if (column.equals(Directory.DISPLAY_NAME)) {
+                row[i] = DISPLAY_NAME;
+            } else if (column.equals(Directory.EXPORT_SUPPORT)) {
+                row[i] = Directory.EXPORT_SUPPORT_NONE;
+            } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
+                row[i] = Directory.SHORTCUT_SUPPORT_NONE;
+            } else if (column.equals(Directory.PHOTO_SUPPORT)) {
+                row[i] = Directory.PHOTO_SUPPORT_NONE;
+            }
+        }
+        cursor.addRow(row);
+        return cursor;
+    }
+
+    /**
+     * Build a cursor to return from the {@link #GAL_FILTER} URI, which returns the following
+     * information in the display_name column as json.
+     *
+     * - It checks whether the incoming account name/type match the values returned by {@link
+     * #handleDirectories(String[])}, and if not, set a error message to the result.
+     * - If above check succeeds, then sets the query parameters in the result.  The caller
+     * checks the returned values.
+     */
+    private Cursor handleFilter(Uri uri, String[] projection) throws JSONException {
+        final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
+        final String accountType = uri.getQueryParameter(RawContacts.ACCOUNT_TYPE);
+        final String limit = uri.getQueryParameter(ContactsContract.LIMIT_PARAM_KEY);
+        final String callerPackage = uri.getQueryParameter(Directory.CALLER_PACKAGE_PARAM_KEY);
+
+        final JSONObject result = new JSONObject();
+
+        final StringBuilder error = new StringBuilder();
+        if (!ACCOUNT_NAME.equals(accountName)) {
+            error.append(String.format("Account name expected=%s but was %s\n",
+                    ACCOUNT_NAME, accountName));
+        }
+        if (!ACCOUNT_TYPE.equals(accountType)) {
+            error.append(String.format("Account type expected=%s but was %s\n",
+                    ACCOUNT_TYPE, accountType));
+        }
+
+        if (error.length() > 0) {
+            result.put(ERROR_MESSAGE_KEY, error.toString());
+        } else {
+            if (!TextUtils.isEmpty(limit)) {
+                result.put(LIMIT_KEY, limit);
+            }
+            if (!TextUtils.isEmpty(callerPackage)) {
+                result.put(CALLER_PACKAGE_NAME_KEY, callerPackage);
+            }
+            result.put(QUERY_KEY, uri.getLastPathSegment());
+        }
+        if (projection == null) {
+            projection = new String[]{Contacts.DISPLAY_NAME};
+        }
+
+        final MatrixCursor c = new MatrixCursor(projection);
+
+        Object[] row = new Object[projection.length];
+        for (int i = 0; i < projection.length; i++) {
+            String column = projection[i];
+            if (Contacts.DISPLAY_NAME.equals(column)) {
+                row[i] = result.toString();
+                continue;
+            }
+            // All other fields are null.
+        }
+
+        c.addRow(row);
+        return c;
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/account/StaticAccountAuthenticator.java b/tests/tests/provider/src/android/provider/cts/contacts/account/StaticAccountAuthenticator.java
index 01db2a1..705a535 100644
--- a/tests/tests/provider/src/android/provider/cts/contacts/account/StaticAccountAuthenticator.java
+++ b/tests/tests/provider/src/android/provider/cts/contacts/account/StaticAccountAuthenticator.java
@@ -25,9 +25,7 @@
 import android.os.Bundle;
 
 /**
- * Account authenticator with 1 hard coded account.
- *
- * Also adds the account to the account manager on instantiation.
+ * Account authenticator with for CTS.
  */
 public class StaticAccountAuthenticator extends AbstractAccountAuthenticator {
 
diff --git a/tests/tests/renderscript/AndroidTest.xml b/tests/tests/renderscript/AndroidTest.xml
index 2e69534..63bcd88 100644
--- a/tests/tests/renderscript/AndroidTest.xml
+++ b/tests/tests/renderscript/AndroidTest.xml
@@ -20,6 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.renderscript.cts" />
-        <option name="runtime-hint" value="9m35s" />
+        <option name="runtime-hint" value="8m15s" />
     </test>
 </configuration>
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/rscpp/AndroidTest.xml b/tests/tests/rscpp/AndroidTest.xml
index 1e7c41f..d412054 100644
--- a/tests/tests/rscpp/AndroidTest.xml
+++ b/tests/tests/rscpp/AndroidTest.xml
@@ -21,6 +21,6 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.rscpp.cts" />
-        <option name="runtime-hint" value="2m" />
+        <option name="runtime-hint" value="20m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/sax/AndroidTest.xml b/tests/tests/sax/AndroidTest.xml
index 14ec1c3..84280de 100644
--- a/tests/tests/sax/AndroidTest.xml
+++ b/tests/tests/sax/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.sax.cts" />
+        <option name="runtime-hint" value="8m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index a8593e1..b335065 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -21,38 +21,18 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctstestrunner ctsdeviceutil compatibility-device-util guava
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestserver ctstestrunner compatibility-device-util guava
 
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
 LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni libnativehelper_compat_libc++ \
-		libnativehelper \
-		libbinder \
-		libutils \
-		libmedia \
-		libselinux \
-		libcutils \
-		libcrypto \
-		libc++ \
-		libbacktrace \
-		libui \
-		libsonivox \
-		libexpat \
-		libcamera_client \
-		libgui \
-		libaudioutils \
-		libnbaio \
-		libpcre2 \
-		libpackagelistparser \
-		libpowermanager \
-		libbase \
-		libunwind \
-		libhardware \
-		libsync \
-		libcamera_metadata \
-		libspeexresampler \
-		liblzma \
-		libstagefright_foundation
+                      libnativehelper \
+                      libcutils \
+                      libcrypto \
+                      libselinux \
+                      libc++ \
+                      libpcre2 \
+                      libpackagelistparser
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)\
                    src/android/security/cts/activity/ISecureRandomService.aidl\
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 7b87851..757d719 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -24,8 +24,8 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -42,6 +42,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/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 22420f8..5b8b49e 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,37 +31,16 @@
 		android_security_cts_MMapExecutableTest.cpp \
 		android_security_cts_EncryptionTest.cpp \
 
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
-										$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := libnativehelper \
+LOCAL_SHARED_LIBRARIES := \
+		libnativehelper \
 		liblog \
-		libutils \
-		libmedia \
-		libselinux \
-		libdl \
 		libcutils \
 		libcrypto \
+		libselinux \
 		libc++ \
-		libbacktrace \
-		libui \
-		libsonivox \
-		libexpat \
-		libcamera_client \
-		libgui \
-		libaudioutils \
-		libnbaio \
 		libpcre2 \
 		libpackagelistparser \
-		libpowermanager \
-		libbase \
-		libunwind \
-		libhardware \
-		libsync \
-		libcamera_metadata \
-		libspeexresampler \
-		liblzma \
-		libstagefright_foundation
+
 
 LOCAL_C_INCLUDES += ndk/sources/cpufeatures
 LOCAL_STATIC_LIBRARIES := cpufeatures
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/media/res/raw/on_input_buffer_filled_sigsegv.mp4 b/tests/tests/security/res/raw/bug_19779574.mp4
similarity index 100%
rename from tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
rename to tests/tests/security/res/raw/bug_19779574.mp4
Binary files differ
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/AslrTest.java b/tests/tests/security/src/android/security/cts/AslrTest.java
index 774df87..2cc4825 100644
--- a/tests/tests/security/src/android/security/cts/AslrTest.java
+++ b/tests/tests/security/src/android/security/cts/AslrTest.java
@@ -32,7 +32,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import android.cts.util.ReadElf;
+import com.android.compatibility.common.util.ReadElf;
 
 /**
  * Verify that ASLR is properly enabled on Android Compatible devices.
diff --git a/tests/tests/security/src/android/security/cts/BannedFilesTest.java b/tests/tests/security/src/android/security/cts/BannedFilesTest.java
index 02c4128..d4ae7d9 100644
--- a/tests/tests/security/src/android/security/cts/BannedFilesTest.java
+++ b/tests/tests/security/src/android/security/cts/BannedFilesTest.java
@@ -16,9 +16,10 @@
 
 package android.security.cts;
 
-import android.cts.util.FileUtils;
 import android.platform.test.annotations.RestrictedBuildTest;
 
+import com.android.compatibility.common.util.FileUtils;
+
 import junit.framework.TestCase;
 
 import java.io.DataInputStream;
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/tests/tests/security/src/android/security/cts/DeviceIdleControllerTest.java b/tests/tests/security/src/android/security/cts/DeviceIdleControllerTest.java
index 0b183aa..67abed3 100644
--- a/tests/tests/security/src/android/security/cts/DeviceIdleControllerTest.java
+++ b/tests/tests/security/src/android/security/cts/DeviceIdleControllerTest.java
@@ -43,6 +43,7 @@
         try {
             service.shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
                     new String[]{"whitelist", "+" + mContext.getPackageName()},
+                    null,
                     new ResultReceiver(null) {
                         @Override
                         protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -65,4 +66,3 @@
         assertFalse(pm.isIgnoringBatteryOptimizations(mContext.getPackageName()));
     }
 }
-
diff --git a/tests/tests/security/src/android/security/cts/DisplayDriverActivity.java b/tests/tests/security/src/android/security/cts/DisplayDriverActivity.java
new file mode 100755
index 0000000..ca6c898
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/DisplayDriverActivity.java
@@ -0,0 +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.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/security/src/android/security/cts/HwRngTest.java b/tests/tests/security/src/android/security/cts/HwRngTest.java
index e654f9d..f8c4684 100644
--- a/tests/tests/security/src/android/security/cts/HwRngTest.java
+++ b/tests/tests/security/src/android/security/cts/HwRngTest.java
@@ -16,7 +16,7 @@
 
 package android.security.cts;
 
-import android.cts.util.CtsAndroidTestCase;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.ResultType;
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
index 147a5cd..e454e2c 100644
--- a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -26,6 +26,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -120,11 +122,16 @@
     }
 
     private void checkIfMediaServerDiedForDrm(int res) throws Exception {
-        if (!convertDmToFl(res, mFlFilePath)) {
+        AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(res);
+        FileInputStream dmStream = afd.createInputStream();
+        RandomAccessFile flFile = new RandomAccessFile(mFlFilePath, "rw");
+        if (!MediaUtils.convertDmToFl(mContext, dmStream, flFile)) {
             Log.w(TAG, "Can not convert dm to fl, skip checkIfMediaServerDiedForDrm");
             mMediaPlayer.release();
             return;
         }
+        dmStream.close();
+        flFile.close();
         Log.d(TAG, "intermediate fl file is " + mFlFilePath);
 
         ParcelFileDescriptor flFd = null;
@@ -154,124 +161,4 @@
             mMediaPlayer.release();
         }
     }
-
-    private boolean convertDmToFl(int res, String flFilePath) throws Exception {
-        AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
-        FileInputStream inputStream = afd.createInputStream();
-        int inputLength = (int)afd.getLength();
-        byte[] fileData = new byte[inputLength];
-        int readSize = inputStream.read(fileData, 0, inputLength);
-        assertEquals("can not pull in all data", readSize, inputLength);
-        inputStream.close();
-        afd.close();
-
-        FileOutputStream flStream = new FileOutputStream(new File(flFilePath));
-
-        DrmManagerClient drmClient = null;
-        try {
-            drmClient = new DrmManagerClient(mContext);
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "DrmManagerClient instance could not be created, context is Illegal.");
-            return false;
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "DrmManagerClient didn't initialize properly.");
-            return false;
-        }
-
-        if (drmClient == null) {
-            Log.w(TAG, "Failed to create DrmManagerClient.");
-            return false;
-        }
-
-        int convertSessionId = -1;
-        try {
-            convertSessionId = drmClient.openConvertSession(MIMETYPE_DRM_MESSAGE);
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "Conversion of Mimetype: " + MIMETYPE_DRM_MESSAGE
-                    + " is not supported.", e);
-            return false;
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Could not access Open DrmFramework.", e);
-            return false;
-        }
-
-        if (convertSessionId < 0) {
-            Log.w(TAG, "Failed to open session.");
-            return false;
-        }
-
-        DrmConvertedStatus convertedStatus = null;
-        try {
-            convertedStatus = drmClient.convertData(convertSessionId, fileData);
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
-                    + convertSessionId, e);
-            return false;
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Could not convert data. Convertsession: " + convertSessionId, e);
-            return false;
-        }
-
-        if (convertedStatus == null ||
-                convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
-                convertedStatus.convertedData == null) {
-            Log.w(TAG, "Error in converting data. Convertsession: " + convertSessionId);
-            try {
-                drmClient.closeConvertSession(convertSessionId);
-            } catch (IllegalStateException e) {
-                Log.w(TAG, "Could not close session. Convertsession: " +
-                       convertSessionId, e);
-            }
-            return false;
-        }
-
-        flStream.write(convertedStatus.convertedData, 0, convertedStatus.convertedData.length);
-        flStream.close();
-
-        try {
-            convertedStatus = drmClient.closeConvertSession(convertSessionId);
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Could not close convertsession. Convertsession: " +
-                    convertSessionId, e);
-            return false;
-        }
-
-        if (convertedStatus == null ||
-                convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
-                convertedStatus.convertedData == null) {
-            Log.w(TAG, "Error in closing session. Convertsession: " + convertSessionId);
-            return false;
-        }
-
-        RandomAccessFile flRandomAccessFile = null;
-        try {
-            flRandomAccessFile = new RandomAccessFile(flFilePath, "rw");
-            flRandomAccessFile.seek(convertedStatus.offset);
-            flRandomAccessFile.write(convertedStatus.convertedData);
-        } catch (FileNotFoundException e) {
-            Log.w(TAG, "File: " + flFilePath + " could not be found.", e);
-            return false;
-        } catch (IOException e) {
-            Log.w(TAG, "Could not access File: " + flFilePath + " .", e);
-            return false;
-        } catch (IllegalArgumentException e) {
-            Log.w(TAG, "Could not open file in mode: rw", e);
-            return false;
-        } catch (SecurityException e) {
-            Log.w(TAG, "Access to File: " + flFilePath +
-                    " was denied denied by SecurityManager.", e);
-            return false;
-        } finally {
-            if (flRandomAccessFile != null) {
-                try {
-                    flRandomAccessFile.close();
-                } catch (IOException e) {
-                    Log.w(TAG, "Failed to close File:" + flFilePath + ".", e);
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
 }
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index a4b7b22..f3c1519 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -190,6 +190,10 @@
         doStagefrightTest(R.raw.cve_2016_3878_b_29493002);
     }
 
+    public void testStagefright_bug_19779574() throws Exception {
+        doStagefrightTest(R.raw.bug_19779574);
+    }
+
     public void testStagefright_cve_2016_2429_b_27211885() throws Exception {
         doStagefrightTest(R.raw.cve_2016_2429_b_27211885);
     }
@@ -405,6 +409,7 @@
                     MediaCodecInfo.CodecCapabilities caps = info.getCapabilitiesForType(mime);
                     if (caps != null && caps.isFormatSupported(format)) {
                         matchingCodecs.add(info.getName());
+                        Log.i(TAG, "Found matching codec " + info.getName() + " for track " + t);
                     }
                 } catch (IllegalArgumentException e) {
                     // type is not supported
@@ -415,7 +420,12 @@
                 Log.w(TAG, "no codecs for track " + t + ", type " + mime);
             }
             // decode this track once with each matching codec
-            ex.selectTrack(t);
+            try {
+                ex.selectTrack(t);
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "couldn't select track " + t);
+                // continue on with codec initialization anyway, since that might still crash
+            }
             for (String codecName: matchingCodecs) {
                 Log.i(TAG, "Decoding track " + t + " using codec " + codecName);
                 ex.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
@@ -424,8 +434,13 @@
                 if (mime.startsWith("video/")) {
                     surface = getDummySurface();
                 }
-                codec.configure(format, surface, null, 0);
-                codec.start();
+                try {
+                    codec.configure(format, surface, null, 0);
+                    codec.start();
+                    Log.i(TAG, "started codec " + codecName);
+                } catch (MediaCodec.CodecException e) {
+                    Log.i(TAG, "Failed to start/configure:", e);
+                }
                 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                 try {
                     while (true) {
diff --git a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
index a17bf96..fc98adc1 100644
--- a/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
+++ b/tests/tests/security/src/android/security/cts/VisualizerEffectTest.java
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.security.cts;
 
 import junit.framework.TestCase;
@@ -23,14 +22,13 @@
 import android.media.MediaPlayer;
 import android.media.audiofx.Visualizer;
 import android.test.AndroidTestCase;
-import android.test.InstrumentationTestCase;
 import android.util.Log;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.UUID;
 
-public class VisualizerEffectTest extends InstrumentationTestCase {
+public class VisualizerEffectTest extends AndroidTestCase {
     private String TAG = "VisualizerEffectTest";
     @Override
     protected void setUp() throws Exception {
@@ -52,7 +50,7 @@
                 AudioEffect ae = null;
                 MediaPlayer mp = null;
                 try {
-                    mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
+                    mp = MediaPlayer.create(getContext(), R.raw.good);
                     Constructor ct = AudioEffect.class.getConstructor(UUID.class, UUID.class,
                             int.class, int.class);
                     ae = (AudioEffect) ct.newInstance(descriptors[visualizerIndex].type,
@@ -79,4 +77,4 @@
             Log.w(TAG,"No visualizer found to test");
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/tests/shortcutmanager/Android.mk b/tests/tests/shortcutmanager/Android.mk
index 8c03be7..49a3b70 100755
--- a/tests/tests/shortcutmanager/Android.mk
+++ b/tests/tests/shortcutmanager/Android.mk
@@ -24,7 +24,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index 31b6b36..cbf35ea 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -29,5 +29,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.content.pm.cts.shortcutmanager" />
+        <option name="runtime-hint" value="22m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
index 177ce5e..b345b6f 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
@@ -252,7 +252,7 @@
                     "Launcher_manifest_2",
                     0,
                     list()))
-                    .haveIds("ms21", "ms22", "s1", "s5")
+                    .haveIds("ms21", "ms22", "s5")
                     .areAllNotWithKeyFieldsOnly();
 
             // With ids
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
index c711518..d81bbfd 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerNegativeTest.java
@@ -22,6 +22,7 @@
 import android.content.pm.ShortcutManager;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import java.io.BufferedReader;
@@ -137,6 +138,7 @@
     /**
      * Make sure cmd shortcut can't be called.
      */
+    @Suppress // calling "cmd shortcut" from this UID seems to hang now.
     public void testCommand() throws Exception {
         runWithCaller(mPackageContext1, () -> {
             assertTrue(getManager().setDynamicShortcuts(list(
diff --git a/tests/tests/shortcutmanager/throttling/Android.mk b/tests/tests/shortcutmanager/throttling/Android.mk
index 4af2d7c..7e6d869 100644
--- a/tests/tests/shortcutmanager/throttling/Android.mk
+++ b/tests/tests/shortcutmanager/throttling/Android.mk
@@ -32,7 +32,7 @@
     android-support-test \
     android-support-v4 \
     mockito-target-minus-junit4 \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctstestrunner \
     ub-uiautomator \
     ShortcutManagerTestUtils
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/speech/AndroidTest.xml b/tests/tests/speech/AndroidTest.xml
index 08df58e..be6d08f 100644
--- a/tests/tests/speech/AndroidTest.xml
+++ b/tests/tests/speech/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.speech.tts.cts" />
+        <option name="runtime-hint" value="11m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
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/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index 2cdb36f..fc0d841 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -21,7 +21,7 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <application>
-        <activity android:name=".LightStatusBarActivity"
+        <activity android:name=".LightBarActivity"
                 android:theme="@android:style/Theme.Material.NoActionBar"></activity>
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightBarActivity.java
new file mode 100644
index 0000000..6a1e0d7
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarActivity.java
@@ -0,0 +1,71 @@
+/*
+ * 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.systemui.cts;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+
+/**
+ * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR and
+ * SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
+ */
+public class LightBarActivity extends Activity {
+
+    private View mContent;
+
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+
+        mContent = new View(this);
+        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+        setContentView(mContent);
+    }
+
+    public void setLightStatusBar(boolean lightStatusBar) {
+        setLightBar(lightStatusBar, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+    }
+
+    public void setLightNavigationBar(boolean lightNavigationBar) {
+        setLightBar(lightNavigationBar, View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+    }
+
+    private void setLightBar(boolean light, int systemUiFlag) {
+        int vis = getWindow().getDecorView().getSystemUiVisibility();
+        if (light) {
+            vis |= systemUiFlag;
+        } else {
+            vis &= ~systemUiFlag;
+        }
+        getWindow().getDecorView().setSystemUiVisibility(vis);
+    }
+
+    public int getTop() {
+        return mContent.getLocationOnScreen()[1];
+    }
+
+    public int getBottom() {
+        return mContent.getLocationOnScreen()[1] + mContent.getHeight();
+    }
+
+    public int getWidth() {
+        return mContent.getWidth();
+    }
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
new file mode 100644
index 0000000..4ba28cb
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -0,0 +1,281 @@
+/*
+ * 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.systemui.cts;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Test for light status bar.
+ *
+ * mmma cts/tests/tests/systemui
+ * cts-tradefed run commandAndExit cts-dev --module CtsSystemUiTestCases --test android.systemui.cts.LightBarTests --disable-reboot --skip-device-info --skip-all-system-status-check --skip-preconditions
+ */
+public class LightBarTests extends ActivityInstrumentationTestCase2<LightBarActivity> {
+
+    public static final String TAG = "LightStatusBarTests";
+
+    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
+
+    public LightBarTests() {
+        super(LightBarActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+    }
+
+    public void testLightStatusBarIcons() throws Throwable {
+        PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // No status bar on TVs and watches.
+            return;
+        }
+
+        if (!ActivityManager.isHighEndGfx()) {
+            // non-highEndGfx devices don't do colored system bars.
+            return;
+        }
+
+        requestLightBars(Color.RED /* background */);
+        Thread.sleep(1000);
+
+        Bitmap bitmap = takeStatusBarScreenshot();
+        Stats s = evaluateLightBarBitmap(bitmap, Color.RED /* background */);
+        assertLightStats(bitmap, s);
+    }
+
+    public void testLightNavigationBar() throws Throwable {
+        PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // No navigation bar on TVs and watches.
+            return;
+        }
+
+        if (!ActivityManager.isHighEndGfx()) {
+            // non-highEndGfx devices don't do colored system bars.
+            return;
+        }
+
+        if (!hasVirtualNavigationBar()) {
+            // No virtual navigation bar, so no effect.
+            return;
+        }
+
+        requestLightBars(Color.RED /* background */);
+        Thread.sleep(1000);
+
+        Bitmap bitmap = takeNavigationBarScreenshot();
+        Stats s = evaluateLightBarBitmap(bitmap, Color.RED /* background */);
+        assertLightStats(bitmap, s);
+    }
+
+    private boolean hasVirtualNavigationBar() {
+        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
+        boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);
+        return !hasBackKey || !hasHomeKey;
+    }
+
+    private void assertLightStats(Bitmap bitmap, Stats s) {
+        boolean success = false;
+        try {
+            assertMoreThan("Not enough background pixels", 0.3f,
+                    (float) s.backgroundPixels / s.totalPixels(),
+                    "Is the bar background showing correctly (solid red)?");
+
+            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
+                    (float) s.iconPixels / s.foregroundPixels(),
+                    "Are the bar icons colored according to the spec "
+                            + "(60% black and 24% black)?");
+
+            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
+                    (float) s.sameHueLightPixels / s.foregroundPixels(),
+                    "Are the bar icons dark?");
+
+            assertLessThan("Too many pixels with a changed hue", 0.05f,
+                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
+                    "Are the bar icons color-free?");
+
+            success = true;
+        } finally {
+            if (!success) {
+                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
+                dumpBitmap(bitmap);
+            }
+        }
+    }
+
+    private void assertMoreThan(String what, float expected, float actual, String hint) {
+        if (!(actual > expected)) {
+            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void assertLessThan(String what, float expected, float actual, String hint) {
+        if (!(actual < expected)) {
+            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void requestLightBars(final int background) throws Throwable {
+        final LightBarActivity activity = getActivity();
+        runTestOnUiThread(() -> {
+            activity.getWindow().setStatusBarColor(background);
+            activity.getWindow().setNavigationBarColor(background);
+            activity.setLightStatusBar(true);
+            activity.setLightNavigationBar(true);
+        });
+    }
+
+    private static class Stats {
+        int backgroundPixels;
+        int iconPixels;
+        int sameHueDarkPixels;
+        int sameHueLightPixels;
+        int unexpectedHuePixels;
+
+        int totalPixels() {
+            return backgroundPixels + iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        int foregroundPixels() {
+            return iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
+                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
+                    unexpectedHuePixels);
+        }
+    }
+
+    private Stats evaluateLightBarBitmap(Bitmap bitmap, int background) {
+        int iconColor = 0x99000000;
+        int iconPartialColor = 0x3d000000;
+
+        int mixedIconColor = mixSrcOver(background, iconColor);
+        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+
+        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
+        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        Stats s = new Stats();
+        float eps = 0.005f;
+
+        for (int c : pixels) {
+            if (c == background) {
+                s.backgroundPixels++;
+                continue;
+            }
+
+            // What we expect the icons to be colored according to the spec.
+            if (c == mixedIconColor || c == mixedIconPartialColor) {
+                s.iconPixels++;
+                continue;
+            }
+
+            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
+            // should still be mostly the same hue.
+            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
+            if (hueDiff < eps || hueDiff > 1 - eps) {
+                // .. it shouldn't be lighter than the original background though.
+                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
+                    s.sameHueLightPixels++;
+                } else {
+                    s.sameHueDarkPixels++;
+                }
+                continue;
+            }
+
+            s.unexpectedHuePixels++;
+        }
+
+        return s;
+    }
+
+    private void dumpBitmap(Bitmap bitmap) {
+        FileOutputStream fileStream = null;
+        try {
+            fileStream = new FileOutputStream(DUMP_PATH);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+            fileStream.flush();
+        } catch (Exception e) {
+            Log.e(TAG, "Dumping bitmap failed.", e);
+        } finally {
+            if (fileStream != null) {
+                try {
+                    fileStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private int mixSrcOver(int background, int foreground) {
+        int bgAlpha = Color.alpha(background);
+        int bgRed = Color.red(background);
+        int bgGreen = Color.green(background);
+        int bgBlue = Color.blue(background);
+
+        int fgAlpha = Color.alpha(foreground);
+        int fgRed = Color.red(foreground);
+        int fgGreen = Color.green(foreground);
+        int fgBlue = Color.blue(foreground);
+
+        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
+                    fgRed + (255 - fgAlpha) * bgRed / 255,
+                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
+                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
+    }
+
+    private Bitmap takeStatusBarScreenshot() {
+        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, 0, 0,
+                getActivity().getWidth(), getActivity().getTop());
+    }
+
+    private Bitmap takeNavigationBarScreenshot() {
+        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, 0, getActivity().getBottom(),
+                getActivity().getWidth(), fullBitmap.getHeight() - getActivity().getBottom());
+    }
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java
deleted file mode 100644
index b33cc77..0000000
--- a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarActivity.java
+++ /dev/null
@@ -1,58 +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 android.systemui.cts;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-
-
-/**
- * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
- */
-public class LightStatusBarActivity extends Activity {
-
-    private View mContent;
-
-    public void onCreate(Bundle bundle){
-        super.onCreate(bundle);
-
-        mContent = new View(this);
-        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        setContentView(mContent);
-    }
-
-    public void setLightStatusBar(boolean lightStatusBar) {
-        int vis = getWindow().getDecorView().getSystemUiVisibility();
-        if (lightStatusBar) {
-            vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-        } else {
-            vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-        }
-        getWindow().getDecorView().setSystemUiVisibility(vis);
-    }
-
-    public int getTop() {
-        return mContent.getLocationOnScreen()[1];
-    }
-
-    public int getWidth() {
-        return mContent.getWidth();
-    }
-}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java
deleted file mode 100644
index 879eac5..0000000
--- a/tests/tests/systemui/src/android/systemui/cts/LightStatusBarTests.java
+++ /dev/null
@@ -1,235 +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 android.systemui.cts;
-
-import android.app.ActivityManager;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.support.test.InstrumentationRegistry;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Test for light status bar.
- */
-public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
-
-    public static final String TAG = "LightStatusBarTests";
-
-    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
-
-    public LightStatusBarTests() {
-        super(LightStatusBarActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        // As the way to access Instrumentation is changed in the new runner, we need to inject it
-        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
-        // be marked as deprecated and replaced with ActivityTestRule.
-        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
-    }
-
-    public void testLightStatusBarIcons() throws Throwable {
-        PackageManager pm = getInstrumentation().getContext().getPackageManager();
-        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
-                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
-                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
-            // No status bar on TVs and watches.
-            return;
-        }
-
-        if (!ActivityManager.isHighEndGfx()) {
-            // non-highEndGfx devices don't do colored system bars.
-            return;
-        }
-
-        requestLightStatusBar(Color.RED /* background */);
-        Thread.sleep(1000);
-
-        Bitmap bitmap = takeStatusBarScreenshot();
-        Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
-        boolean success = false;
-
-        try {
-            assertMoreThan("Not enough background pixels", 0.3f,
-                    (float) s.backgroundPixels / s.totalPixels(),
-                    "Is the status bar background showing correctly (solid red)?");
-
-            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
-                    (float) s.iconPixels / s.foregroundPixels(),
-                    "Are the status bar icons colored according to the spec "
-                            + "(60% black and 24% black)?");
-
-            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
-                    (float) s.sameHueLightPixels / s.foregroundPixels(),
-                    "Are the status bar icons dark?");
-
-            assertLessThan("Too many pixels with a changed hue", 0.05f,
-                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
-                    "Are the status bar icons color-free?");
-
-            success = true;
-        } finally {
-            if (!success) {
-                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
-                dumpBitmap(bitmap);
-            }
-        }
-    }
-
-    private void assertMoreThan(String what, float expected, float actual, String hint) {
-        if (!(actual > expected)) {
-            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
-                    + "%; " + hint);
-        }
-    }
-
-    private void assertLessThan(String what, float expected, float actual, String hint) {
-        if (!(actual < expected)) {
-            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
-                    + "%; " + hint);
-        }
-    }
-
-    private void requestLightStatusBar(final int background) throws Throwable {
-        final LightStatusBarActivity activity = getActivity();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.getWindow().setStatusBarColor(background);
-                activity.setLightStatusBar(true);
-            }
-        });
-    }
-
-    private static class Stats {
-        int backgroundPixels;
-        int iconPixels;
-        int sameHueDarkPixels;
-        int sameHueLightPixels;
-        int unexpectedHuePixels;
-
-        int totalPixels() {
-            return backgroundPixels + iconPixels + sameHueDarkPixels
-                    + sameHueLightPixels + unexpectedHuePixels;
-        }
-
-        int foregroundPixels() {
-            return iconPixels + sameHueDarkPixels
-                    + sameHueLightPixels + unexpectedHuePixels;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
-                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
-                    unexpectedHuePixels);
-        }
-    }
-
-    private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
-        int iconColor = 0x99000000;
-        int iconPartialColor = 0x3d000000;
-
-        int mixedIconColor = mixSrcOver(background, iconColor);
-        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
-
-        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
-        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
-
-        Stats s = new Stats();
-        float eps = 0.005f;
-
-        for (int c : pixels) {
-            if (c == background) {
-                s.backgroundPixels++;
-                continue;
-            }
-
-            // What we expect the icons to be colored according to the spec.
-            if (c == mixedIconColor || c == mixedIconPartialColor) {
-                s.iconPixels++;
-                continue;
-            }
-
-            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
-            // should still be mostly the same hue.
-            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
-            if (hueDiff < eps || hueDiff > 1 - eps) {
-                // .. it shouldn't be lighter than the original background though.
-                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
-                    s.sameHueLightPixels++;
-                } else {
-                    s.sameHueDarkPixels++;
-                }
-                continue;
-            }
-
-            s.unexpectedHuePixels++;
-        }
-
-        return s;
-    }
-
-    private void dumpBitmap(Bitmap bitmap) {
-        FileOutputStream fileStream = null;
-        try {
-            fileStream = new FileOutputStream(DUMP_PATH);
-            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
-            fileStream.flush();
-        } catch (Exception e) {
-            Log.e(TAG, "Dumping bitmap failed.", e);
-        } finally {
-            if (fileStream != null) {
-                try {
-                    fileStream.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    private int mixSrcOver(int background, int foreground) {
-        int bgAlpha = Color.alpha(background);
-        int bgRed = Color.red(background);
-        int bgGreen = Color.green(background);
-        int bgBlue = Color.blue(background);
-
-        int fgAlpha = Color.alpha(foreground);
-        int fgRed = Color.red(foreground);
-        int fgGreen = Color.green(foreground);
-        int fgBlue = Color.blue(foreground);
-
-        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
-                    fgRed + (255 - fgAlpha) * bgRed / 255,
-                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
-                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
-    }
-
-    private Bitmap takeStatusBarScreenshot() {
-        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(fullBitmap, 0, 0,
-                getActivity().getWidth(), getActivity().getTop());
-    }
-}
diff --git a/tests/tests/telecom/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/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 7231954..73ba945 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -17,7 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.telecom.cts">
     <uses-sdk android:minSdkVersion="21" />
-    <uses-permission android:name="android.permission.CALL_PHONE" />>
+    <uses-permission android:name="android.permission.CALL_PHONE" />
+    <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index e7130ba..f4eee35 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -69,7 +69,7 @@
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
 
-    public void testInCallShortPress_togglesMute() throws Exception {
+    public void testInCallLongPress_togglesMute() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -83,15 +83,15 @@
         // Before the audio state is changed for the first time, the connection might not
         // know about its audio state yet.
         assertMuteState(incallService, false);
-        sendMediaButtonShortPress();
+        sendMediaButtonLongPress();
         assertMuteState(connection, true);
         assertMuteState(incallService, true);
-        sendMediaButtonShortPress();
+        sendMediaButtonLongPress();
         assertMuteState(connection, false);
         assertMuteState(incallService, false);
     }
 
-    public void testInCallLongPress_hangupCall() throws Exception {
+    public void testInCallShortPress_hangupCall() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -105,7 +105,7 @@
         connection.setActive();
         assertCallState(call, Call.STATE_ACTIVE);
 
-        sendMediaButtonLongPress();
+        sendMediaButtonShortPress();
         assertCallState(call, Call.STATE_DISCONNECTED);
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
diff --git a/tests/tests/telephony/Android.mk b/tests/tests/telephony/Android.mk
index d8f152e..75da56e 100644
--- a/tests/tests/telephony/Android.mk
+++ b/tests/tests/telephony/Android.mk
@@ -24,7 +24,9 @@
 
 LOCAL_JAVA_LIBRARIES := telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
+
+LOCAL_HOST_SHARED_LIBRARIES := compatibility-device-telephony-preconditions
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -38,3 +40,4 @@
 LOCAL_JAVA_LIBRARIES += android.test.runner
 
 include $(BUILD_CTS_PACKAGE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/telephony/AndroidTest.xml b/tests/tests/telephony/AndroidTest.xml
index 2e6011b..f02f896 100644
--- a/tests/tests/telephony/AndroidTest.xml
+++ b/tests/tests/telephony/AndroidTest.xml
@@ -14,6 +14,9 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Telephony test cases">
+    <target_preparer class="android.telephony.cts.preconditions.TelephonyPreparer" />
+        <option name="apk" value="CtsTelephonyPreparerApp.apk"/>
+        <option name="package" value="android.telephony.cts.preconditions.app"/>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
         <option name="token" value="sim-card" />
     </target_preparer>
diff --git a/tests/tests/telephony/preconditions/Android.mk b/tests/tests/telephony/preconditions/Android.mk
new file mode 100644
index 0000000..6577932
--- /dev/null
+++ b/tests/tests/telephony/preconditions/Android.mk
@@ -0,0 +1,34 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := compatibility-host-telephony-preconditions
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/telephony/preconditions/app/Android.mk b/tests/tests/telephony/preconditions/app/Android.mk
new file mode 100644
index 0000000..349daed
--- /dev/null
+++ b/tests/tests/telephony/preconditions/app/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctstestrunner \
+                                compatibility-device-util \
+                                compatibility-device-preconditions
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsTelephonyPreparerApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telephony/preconditions/app/AndroidManifest.xml b/tests/tests/telephony/preconditions/app/AndroidManifest.xml
new file mode 100644
index 0000000..5e19c20
--- /dev/null
+++ b/tests/tests/telephony/preconditions/app/AndroidManifest.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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.telephony.cts.preconditions.app">
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.telephony.cts.preconditions.app"
+                     android:label="Device-side CTS telephony preparation" />
+</manifest>
\ No newline at end of file
diff --git a/tests/tests/telephony/preconditions/app/src/android/telephony/cts/preconditions/app/TelephonyPreparerAppTest.java b/tests/tests/telephony/preconditions/app/src/android/telephony/cts/preconditions/app/TelephonyPreparerAppTest.java
new file mode 100644
index 0000000..8f53f7d
--- /dev/null
+++ b/tests/tests/telephony/preconditions/app/src/android/telephony/cts/preconditions/app/TelephonyPreparerAppTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.telephony.cts.preconditions.app;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+import com.android.compatibility.common.preconditions.TelephonyHelper;
+
+/**
+ * A test to verify that device-side preconditions are met for CTS
+ */
+public class TelephonyPreparerAppTest extends AndroidTestCase {
+    private static final String TAG = "TelephonyPreparerAppTest";
+
+    /**
+     * Test if device has a valid phone number
+     * @throws Exception
+     */
+    public void testPhoneNumberPresent() throws Exception {
+        PackageManager pm = this.getContext().getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return; // do not test for phone number on devices without telephony feature
+        }
+
+        assertTrue("Device must have a SIM card with phone number in order to run CTS",
+                TelephonyHelper.hasPhoneNumber(this.getContext()));
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/telephony/preconditions/src/android/telephony/cts/preconditions/TelephonyPreparer.java b/tests/tests/telephony/preconditions/src/android/telephony/cts/preconditions/TelephonyPreparer.java
new file mode 100644
index 0000000..965c752
--- /dev/null
+++ b/tests/tests/telephony/preconditions/src/android/telephony/cts/preconditions/TelephonyPreparer.java
@@ -0,0 +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.telephony.cts.preconditions;
+
+import com.android.compatibility.common.tradefed.targetprep.ApkInstrumentationPreparer;
+import com.android.tradefed.config.OptionClass;
+
+/**
+ * Ensures that the appropriate telephony service is available on the device
+ */
+@OptionClass(alias="telephony-preparer")
+public class TelephonyPreparer extends ApkInstrumentationPreparer {
+
+    public TelephonyPreparer() {
+        mWhen = When.BEFORE;
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java b/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
index 9205f0e..6c180b4 100644
--- a/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/CellLocationTest.java
@@ -17,8 +17,6 @@
 
 
 import android.content.Context;
-import android.cts.util.ReadElf;
-import android.cts.util.TestThread;
 import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.telephony.CellLocation;
@@ -29,6 +27,9 @@
 import android.content.pm.PackageManager;
 import android.util.Log;
 
+import com.android.compatibility.common.util.ReadElf;
+import com.android.compatibility.common.util.TestThread;
+
 public class CellLocationTest extends AndroidTestCase{
     private boolean mOnCellLocationChangedCalled;
     private final Object mLock = new Object();
diff --git a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
index 18aa23f..d18a9f5 100644
--- a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -16,8 +16,6 @@
 package android.telephony.cts;
 
 import android.content.Context;
-import android.cts.util.ReadElf;
-import android.cts.util.TestThread;
 import android.os.Looper;
 import android.telephony.CellLocation;
 import android.telephony.PhoneStateListener;
@@ -29,6 +27,9 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.ReadElf;
+import com.android.compatibility.common.util.TestThread;
+
 public class PhoneStateListenerTest extends  AndroidTestCase{
 
     public static final long WAIT_TIME = 1000;
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/telephony/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
index 9b08397..f7ec3b7 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -17,7 +17,6 @@
 package android.telephony.cts;
 
 import android.content.Context;
-import android.cts.util.TestThread;
 import android.net.ConnectivityManager;
 import android.os.Looper;
 import android.telephony.SubscriptionInfo;
@@ -25,6 +24,8 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.compatibility.common.util.TestThread;
+
 import java.util.List;
 
 public class SubscriptionManagerTest extends AndroidTestCase {
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 50820b2..b4d1e9b 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -27,7 +27,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.TestThread;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -44,6 +43,7 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.compatibility.common.util.TestThread;
 import com.android.internal.telephony.PhoneConstants;
 
 import org.junit.After;
diff --git a/tests/tests/telephony2/Android.mk b/tests/tests/telephony2/Android.mk
index dbd2559..08a7df3 100644
--- a/tests/tests/telephony2/Android.mk
+++ b/tests/tests/telephony2/Android.mk
@@ -22,7 +22,7 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/telephony2/AndroidTest.xml b/tests/tests/telephony2/AndroidTest.xml
index 45ee5fa..fd07d10 100644
--- a/tests/tests/telephony2/AndroidTest.xml
+++ b/tests/tests/telephony2/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.telephony2.cts" />
+        <option name="runtime-hint" value="7m30s" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index 65a93fb..2210cbd 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 += \
+    compatibility-device-util \
+    ctsdeviceutillegacy \
+    ctstestrunner \
+    android-support-test \
+    mockito-target-minus-junit4 \
 
 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/AndroidTest.xml b/tests/tests/text/AndroidTest.xml
index 5fef3cb..3266582 100644
--- a/tests/tests/text/AndroidTest.xml
+++ b/tests/tests/text/AndroidTest.xml
@@ -20,6 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.text.cts" />
-        <option name="runtime-hint" value="3m8s" />
+        <option name="runtime-hint" value="22m" />
     </test>
 </configuration>
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/AlteredCharSequenceTest.java b/tests/tests/text/src/android/text/cts/AlteredCharSequenceTest.java
index 609370f..e80d233 100644
--- a/tests/tests/text/src/android/text/cts/AlteredCharSequenceTest.java
+++ b/tests/tests/text/src/android/text/cts/AlteredCharSequenceTest.java
@@ -16,44 +16,53 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.AlteredCharSequence;
 import android.text.Spanned;
 
-public class AlteredCharSequenceTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlteredCharSequenceTest {
     private static final String SOURCE_STR = "This is a char sequence.";
+
     private AlteredCharSequence mAlteredCharSequence;
 
+    @Test
     public void testCharAt() {
-        mAlteredCharSequence = null;
-        char[] sub = { 'i', 's' };
-        CharSequence source = "abcdefgh";
-        mAlteredCharSequence = AlteredCharSequence.make(source, sub, 0, sub.length);
+        mAlteredCharSequence = AlteredCharSequence.make("abcdefgh", new char[] {'i', 's'}, 0, 2);
         // chars in sub.
         assertEquals('i', mAlteredCharSequence.charAt(0));
         assertEquals('s', mAlteredCharSequence.charAt(1));
         // chars in source.
         assertEquals('c', mAlteredCharSequence.charAt(2));
         assertEquals('d', mAlteredCharSequence.charAt(3));
-
-        try {
-            mAlteredCharSequence.charAt(-1);
-            fail("should raise a StringIndexOutOfBoundsException.");
-        } catch (StringIndexOutOfBoundsException e) {
-            // expected.
-        }
-
-        try {
-            mAlteredCharSequence.charAt(mAlteredCharSequence.length() + 1);
-            fail("should raise a StringIndexOutOfBoundsException.");
-        } catch (StringIndexOutOfBoundsException e) {
-            // expected.
-        }
     }
 
+    @Test(expected=StringIndexOutOfBoundsException.class)
+    public void testCharAtTooLow() {
+        mAlteredCharSequence = AlteredCharSequence.make("abcdefgh", new char[] {'i', 's'}, 0, 2);
+
+        mAlteredCharSequence.charAt(-1);
+    }
+
+    @Test(expected=StringIndexOutOfBoundsException.class)
+    public void testCharAtTooHigh() {
+        mAlteredCharSequence = AlteredCharSequence.make("abcdefgh", new char[] {'i', 's'}, 0, 2);
+
+        mAlteredCharSequence.charAt(mAlteredCharSequence.length() + 1);
+    }
+
+    @Test
     public void testGetChars() {
-        mAlteredCharSequence = null;
         char[] sub = { 'i', 's' };
         int start = 0;
         int end = 2;
@@ -84,6 +93,7 @@
         }
     }
 
+    @Test
     public void testLength() {
         char[] sub = { 'i', 's' };
 
@@ -95,8 +105,8 @@
         }
     }
 
+    @Test
     public void testMake() {
-        mAlteredCharSequence = null;
         char[] sub = { 'i', 's' };
 
         CharSequence source = SOURCE_STR;
@@ -113,8 +123,8 @@
         assertFalse(0 == acsClassName.compareTo(spanClassName));
     }
 
+    @Test
     public void testSubSequence() {
-        mAlteredCharSequence = null;
         char[] sub = { 'i', 's' };
 
         CharSequence source = SOURCE_STR;
@@ -129,8 +139,8 @@
         }
     }
 
+    @Test
     public void testToString() {
-        mAlteredCharSequence = null;
         char[] sub = { 'i', 's' };
         CharSequence source = SOURCE_STR;
         mAlteredCharSequence = AlteredCharSequence.make(source, sub, 0, sub.length);
@@ -140,28 +150,35 @@
     class MockSpanned implements Spanned {
         public MockSpanned(String sequence) {
         }
+
         public int getSpanEnd(Object tag) {
             return 0;
         }
+
         public int getSpanFlags(Object tag) {
             return 0;
         }
+
         public int getSpanStart(Object tag) {
             return 0;
         }
+
         public <T> T[] getSpans(int start, int end, Class<T> type) {
             return null;
         }
-        @SuppressWarnings("unchecked")
+
         public int nextSpanTransition(int start, int limit, Class type) {
             return 0;
         }
+
         public char charAt(int index) {
             return 0;
         }
+
         public int length() {
             return 0;
         }
+
         public CharSequence subSequence(int start, int end) {
             return null;
         }
diff --git a/tests/tests/text/src/android/text/cts/AndroidCharacterTest.java b/tests/tests/text/src/android/text/cts/AndroidCharacterTest.java
index 7eaa092..16a8344 100644
--- a/tests/tests/text/src/android/text/cts/AndroidCharacterTest.java
+++ b/tests/tests/text/src/android/text/cts/AndroidCharacterTest.java
@@ -16,15 +16,27 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.AndroidCharacter;
 
-public class AndroidCharacterTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AndroidCharacterTest {
+    @Test
     public void testConstructor() {
         new AndroidCharacter();
     }
 
+    @Test
     public void testGetDirectionalities() {
         char[] src = new char[128];
         for (int i = 0; i < src.length; i++) {
@@ -45,6 +57,7 @@
         }
     }
 
+    @Test
     public void testGetEastAsianWidth() {
         // LATIN CAPITAL LETTER U WITH CARON (U+01D3)
         assertEquals(AndroidCharacter.EAST_ASIAN_WIDTH_NEUTRAL,
@@ -71,6 +84,7 @@
                 AndroidCharacter.getEastAsianWidth((char)0x319F));
     }
 
+    @Test
     public void testGetEastAsianWidths() {
         char[] src = {
                 0x01D3, 0xFFFD, 0xFF86, 0xFF41, 0x0041, 0x319f,
@@ -104,6 +118,7 @@
         }
     }
 
+    @Test
     public void testGetMirror() {
         assertEquals('A', AndroidCharacter.getMirror('A'));
         assertEquals('B', AndroidCharacter.getMirror('B'));
@@ -113,6 +128,7 @@
         assertEquals('<', AndroidCharacter.getMirror('>'));
     }
 
+    @Test
     public void testMirror() {
         char[] src = new char[64];
         for (int i = 0; i < src.length; i++) {
diff --git a/tests/tests/text/src/android/text/cts/AnnotationTest.java b/tests/tests/text/src/android/text/cts/AnnotationTest.java
index a0d597a..a74bc62 100644
--- a/tests/tests/text/src/android/text/cts/AnnotationTest.java
+++ b/tests/tests/text/src/android/text/cts/AnnotationTest.java
@@ -16,31 +16,36 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Annotation;
 
-public class AnnotationTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AnnotationTest {
 
     private static final String KEY1 = "name";
     private static final String KEY2 = "family name";
     private static final String VALUE1 = "John";
     private static final String VALUE2 = "Smith";
     private static final int NOFLAG = 0;
+
     private Annotation mAnnotation;
 
-    @Override
-    protected void setUp() throws Exception {
-
-        super.setUp();
-        mAnnotation = null;
-    }
-
+    @Test
     public void testConstructor() {
         // new the Annotation instance
         new Annotation(KEY1, VALUE1);
     }
 
+    @Test
     public void testGetValue() {
         // new the Annotation instance
         mAnnotation = new Annotation(KEY1, VALUE1);
@@ -49,6 +54,7 @@
         assertEquals(VALUE2, mAnnotation.getValue());
     }
 
+    @Test
     public void testGetKey() {
         // new the Annotation instance
         mAnnotation = new Annotation(KEY1, VALUE1);
@@ -57,12 +63,14 @@
         assertEquals(KEY2, mAnnotation.getKey());
     }
 
+    @Test
     public void testGetSpanTypeId() {
         mAnnotation = new Annotation(KEY1, VALUE1);
         // Because of the return value is a hide value, we only can assert the return value isn't 0.
         assertTrue(mAnnotation.getSpanTypeId() != 0);
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel dest = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/cts/AutoTextTest.java b/tests/tests/text/src/android/text/cts/AutoTextTest.java
index cbea4d9..e3d1b52 100644
--- a/tests/tests/text/src/android/text/cts/AutoTextTest.java
+++ b/tests/tests/text/src/android/text/cts/AutoTextTest.java
@@ -16,28 +16,52 @@
 
 package android.text.cts;
 
-import java.util.Locale;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.AutoText;
 import android.view.View;
-import android.content.res.Configuration;
 
-public class AutoTextTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AutoTextTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+
+        // set locale as English.
+        Locale.setDefault(Locale.ENGLISH);
+        Configuration config = mContext.getResources().getConfiguration();
+        if (!config.locale.equals(Locale.getDefault())) {
+            config.locale = Locale.getDefault();
+            mContext.getResources().updateConfiguration(config, null);
+        }
+    }
+
+    @UiThreadTest
+    @Test
     public void testGet() {
         // Define the necessary sources.
         CharSequence src;
         String actual;
-
-        // set local as English.
-        Locale.setDefault(Locale.ENGLISH);
-        Configuration config = getContext().getResources().getConfiguration();
-        if (!config.locale.equals(Locale.getDefault())) {
-                config.locale = Locale.getDefault();
-                getContext().getResources().updateConfiguration(config, null);
-        }
         // New a View instance.
-        View view = new View(getContext());
+        View view = new View(mContext);
 
         // Test a word key not in the autotext.xml.
         src = "can";
@@ -75,14 +99,10 @@
         assertEquals("can", actual);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetSize() {
-        Locale.setDefault(Locale.ENGLISH);
-        Configuration config = getContext().getResources().getConfiguration();
-        if (!config.locale.equals(Locale.getDefault())) {
-                config.locale = Locale.getDefault();
-                getContext().getResources().updateConfiguration(config, null);
-        }
-        View view = new View(getContext());
+        View view = new View(mContext);
         // Returns the size of the auto text dictionary. Just make sure it is bigger than 0.
         assertTrue(AutoText.getSize(view) > 0);
     }
diff --git a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
index 3e5db4d..bf0d14e 100644
--- a/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
+++ b/tests/tests/text/src/android/text/cts/BidiFormatterTest.java
@@ -16,13 +16,28 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+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 android.icu.util.ULocale;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.BidiFormatter;
+import android.text.SpannableString;
+import android.text.Spanned;
 import android.text.TextDirectionHeuristics;
+import android.text.style.RelativeSizeSpan;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Locale;
 
-public class BidiFormatterTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BidiFormatterTest {
 
     private static final BidiFormatter LTR_FMT = BidiFormatter.getInstance(false /* LTR context */);
     private static final BidiFormatter RTL_FMT = BidiFormatter.getInstance(true /* RTL context */);
@@ -41,6 +56,7 @@
     private static final String RLE = "\u202B";
     private static final String PDF = "\u202C";
 
+    @Test
     public void testIsRtlContext() {
         assertEquals(false, LTR_FMT.isRtlContext());
         assertEquals(true, RTL_FMT.isRtlContext());
@@ -49,6 +65,7 @@
         assertEquals(true, BidiFormatter.getInstance(true).isRtlContext());
     }
 
+    @Test
     public void testCachedInstances() {
         // Test that we get the same cached static instances for simple cases
         BidiFormatter defaultFormatterInstance = BidiFormatter.getInstance();
@@ -61,11 +78,13 @@
         assertEquals(RTL_FMT, BidiFormatter.getInstance(Locale.forLanguageTag("ar")));
     }
 
+    @Test
     public void testBuilderIsRtlContext() {
         assertEquals(false, new BidiFormatter.Builder(false).build().isRtlContext());
         assertEquals(true, new BidiFormatter.Builder(true).build().isRtlContext());
     }
 
+    @Test
     public void testIsRtl() {
         assertEquals(true, BidiFormatter.getInstance(true).isRtl(HE));
         assertEquals(true, BidiFormatter.getInstance(false).isRtl(HE));
@@ -74,6 +93,7 @@
         assertEquals(false, BidiFormatter.getInstance(false).isRtl(EN));
     }
 
+    @Test
     public void testMarkAfter() {
         assertEquals("uniform dir matches LTR context",
                 "", LTR_FMT.markAfter(EN, TextDirectionHeuristics.LTR));
@@ -96,6 +116,7 @@
                 "", RTL_FMT.markAfter(".", TextDirectionHeuristics.RTL));
     }
 
+    @Test
     public void testMarkBefore() {
         assertEquals("uniform dir matches LTR context",
                 "", LTR_FMT.markBefore(EN, TextDirectionHeuristics.LTR));
@@ -118,6 +139,7 @@
                 "", RTL_FMT.markBefore(".", TextDirectionHeuristics.RTL));
     }
 
+    @Test
     public void testUnicodeWrap() {
         // Make sure an input of null doesn't crash anything.
         assertNull(LTR_FMT.unicodeWrap(null));
@@ -233,4 +255,87 @@
                 LRE + HE + EN + HE + PDF,
                 RTL_FMT_EXIT_RESET.unicodeWrap(HE + EN + HE, TextDirectionHeuristics.LTR, false));
     }
+
+    @Test
+    public void testGetStereoReset() {
+        assertTrue(LTR_FMT.getStereoReset());
+        assertTrue(RTL_FMT.getStereoReset());
+        assertFalse(LTR_FMT_EXIT_RESET.getStereoReset());
+        assertFalse(RTL_FMT_EXIT_RESET.getStereoReset());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
+    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..e78fb3e 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -16,19 +16,42 @@
 
 package android.text.cts;
 
+import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
+
+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.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+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.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.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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 {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BoringLayoutTest {
     private static final float SPACING_MULT_NO_SCALE = 1.0f;
     private static final float SPACING_ADD_NO_SCALE = 0.0f;
     private static final int DEFAULT_OUTER_WIDTH = 100;
@@ -52,12 +75,12 @@
 
     private BoringLayout mBoringLayout;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mBoringLayout = makeDefaultBoringLayout();
     }
 
+    @Test
     public void testConstructors() {
         new BoringLayout(DEFAULT_CHAR_SEQUENCE,
                 DEFAULT_PAINT,
@@ -88,6 +111,7 @@
         assertEquals(height + METRICS_TOP, boringLayout.getLineDescent(0));
     }
 
+    @Test
     public void testScale() {
         // no scale
         verifyMultAddScale(1.0f, 0.0f);
@@ -105,6 +129,7 @@
         verifyMultAddScale(1.0f, -3.0f);
     }
 
+    @Test
     public void testPreconditions() {
         assertEquals(1, mBoringLayout.getLineCount());
         assertEquals(0, mBoringLayout.getLineTop(0));
@@ -115,7 +140,7 @@
         assertEquals(DEFAULT_CHAR_SEQUENCE.length(), mBoringLayout.getLineStart(10));
         assertEquals(Layout.DIR_LEFT_TO_RIGHT, mBoringLayout.getParagraphDirection(0));
         assertFalse(mBoringLayout.getLineContainsTab(0));
-        assertEquals((float) METRICS_WIDTH, mBoringLayout.getLineMax(0));
+        assertEquals((float) METRICS_WIDTH, mBoringLayout.getLineMax(0), 0.0f);
         assertEquals(Layout.DIR_LEFT_TO_RIGHT, mBoringLayout.getParagraphDirection(0));
         assertEquals(0, mBoringLayout.getEllipsisCount(0));
         mBoringLayout.ellipsized(0, 1);
@@ -124,6 +149,7 @@
         assertEquals(1, mBoringLayout.getEllipsisStart(0));
     }
 
+    @Test
     public void testReplaceOrMake() {
         String source = "This is a SpannableString.";
         BoringLayout layout_1 = mBoringLayout.replaceOrMake(
@@ -153,28 +179,31 @@
     }
 
 
+    @Test
     public void testAlignment() {
         BoringLayout boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_NORMAL);
-        assertEquals(0.0f, boringLayout.getLineLeft(0));
-        assertEquals((float) DEFAULT_METRICS.width, boringLayout.getLineRight(0));
+        assertEquals(0.0f, boringLayout.getLineLeft(0), 0.0f);
+        assertEquals((float) DEFAULT_METRICS.width, boringLayout.getLineRight(0), 0.0f);
 
         boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_CENTER);
         int expectedWidth = DEFAULT_OUTER_WIDTH - METRICS_WIDTH;
-        assertEquals((float) expectedWidth / 2, boringLayout.getLineLeft(0));
+        assertEquals((float) expectedWidth / 2, boringLayout.getLineLeft(0), 0.0f);
         expectedWidth = DEFAULT_OUTER_WIDTH + METRICS_WIDTH;
-        assertEquals((float) expectedWidth / 2, boringLayout.getLineRight(0));
+        assertEquals((float) expectedWidth / 2, boringLayout.getLineRight(0), 0.0f);
 
         boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_OPPOSITE);
         expectedWidth = DEFAULT_OUTER_WIDTH - METRICS_WIDTH;
-        assertEquals((float) expectedWidth, boringLayout.getLineLeft(0));
-        assertEquals((float) DEFAULT_OUTER_WIDTH, boringLayout.getLineRight(0));
+        assertEquals((float) expectedWidth, boringLayout.getLineLeft(0), 0.0f);
+        assertEquals((float) DEFAULT_OUTER_WIDTH, boringLayout.getLineRight(0), 0.0f);
     }
 
+    @Test
     public void testGetLineDescent_withIncludePadding() {
         final int height = METRICS_BOTTOM - METRICS_TOP;
         assertEquals(height + METRICS_TOP, mBoringLayout.getLineDescent(0));
     }
 
+    @Test
     public void testGetLineDescent_withoutIncludePadding() {
         BoringLayout boringLayout = new BoringLayout(
                 DEFAULT_CHAR_SEQUENCE,
@@ -190,6 +219,7 @@
         assertEquals(height + METRICS_ASCENT, boringLayout.getLineDescent(0));
     }
 
+    @Test
     public void testIncludePadding() {
         assertEquals(METRICS_TOP - METRICS_ASCENT, mBoringLayout.getTopPadding());
         assertEquals(METRICS_BOTTOM - METRICS_DESCENT, mBoringLayout.getBottomPadding());
@@ -210,6 +240,7 @@
         assertEquals(METRICS_DESCENT - METRICS_ASCENT, boringLayout.getHeight());
     }
 
+    @Test
     public void testIsBoringString() {
         TextPaint paint = new TextPaint();
         assertNotNull(BoringLayout.isBoring("hello android", paint));
@@ -226,6 +257,7 @@
         assertNull(BoringLayout.isBoring("hello android\n\n\n", paint));
     }
 
+    @Test
     public void testIsBoring_resetsFontMetrics() {
         int someInt = 100;
         String text = "some text";
@@ -251,11 +283,13 @@
         assertEquals(expectedMetrics.leading, actualMetrics.leading);
     }
 
+    @Test
     public void testGetLineDirections() {
         assertNotNull(mBoringLayout.getLineDirections(0));
         assertNotNull(mBoringLayout.getLineDirections(2));
     }
 
+    @Test
     public void testMake() {
         BoringLayout boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
                 DEFAULT_PAINT,
@@ -267,7 +301,6 @@
                 true);
         assertNotNull(boringLayout);
 
-        boringLayout = null;
         boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
                 DEFAULT_PAINT,
                 DEFAULT_OUTER_WIDTH,
@@ -281,8 +314,9 @@
         assertNotNull(boringLayout);
     }
 
+    @Test
     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 +325,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(
@@ -331,7 +365,7 @@
         return metrics;
     }
 
-    private BoringLayout makeDefaultBoringLayout(){
+    private static BoringLayout makeDefaultBoringLayout() {
         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
                                 DEFAULT_PAINT,
                                 DEFAULT_OUTER_WIDTH,
@@ -342,7 +376,7 @@
                                 true);
     }
 
-    private BoringLayout makeBoringLayout(float spacingMult,float spacingAdd){
+    private static BoringLayout makeBoringLayout(float spacingMult,float spacingAdd) {
         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
                                 DEFAULT_PAINT,
                                 DEFAULT_OUTER_WIDTH,
@@ -353,7 +387,7 @@
                                 true);
     }
 
-    private BoringLayout makeBoringLayoutAlign(Alignment align){
+    private static BoringLayout makeBoringLayoutAlign(Alignment align) {
         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
                                 DEFAULT_PAINT,
                                 DEFAULT_OUTER_WIDTH,
diff --git a/tests/tests/text/src/android/text/cts/BoringLayout_MetricsTest.java b/tests/tests/text/src/android/text/cts/BoringLayout_MetricsTest.java
index 141ff023..3dc4b73 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayout_MetricsTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayout_MetricsTest.java
@@ -16,11 +16,19 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertNotNull;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.BoringLayout;
 
-public class BoringLayout_MetricsTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BoringLayout_MetricsTest {
+    @Test
     public void testMetrics() {
         BoringLayout.Metrics bm = new BoringLayout.Metrics();
         assertNotNull(bm.toString());
diff --git a/tests/tests/text/src/android/text/cts/ClipboardManagerTest.java b/tests/tests/text/src/android/text/cts/ClipboardManagerTest.java
index f0fc0fa..0073c42 100644
--- a/tests/tests/text/src/android/text/cts/ClipboardManagerTest.java
+++ b/tests/tests/text/src/android/text/cts/ClipboardManagerTest.java
@@ -16,47 +16,55 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.ClipboardManager;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ClipboardManager}.
  */
-public class ClipboardManagerTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClipboardManagerTest {
+    private ClipboardManager mClipboardManager;
 
-    private Context mContext;
-
-    @Override
-    public void setUp() {
-        mContext = getInstrumentation().getContext();
+    @UiThreadTest
+    @Before
+    public void setup() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
     }
 
     @UiThreadTest
+    @Test
     public void testAccessText() {
-        ClipboardManager clipboardManager =
-                (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
-
         // set the expected value
         CharSequence expected = "test";
-        clipboardManager.setText(expected);
-        assertEquals(expected, clipboardManager.getText());
+        mClipboardManager.setText(expected);
+        assertEquals(expected, mClipboardManager.getText());
     }
 
     @UiThreadTest
+    @Test
     public void testHasText() {
-        ClipboardManager clipboardManager =
-                (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
+        mClipboardManager.setText("");
+        assertFalse(mClipboardManager.hasText());
 
-        clipboardManager.setText("");
-        assertFalse(clipboardManager.hasText());
+        mClipboardManager.setText("test");
+        assertTrue(mClipboardManager.hasText());
 
-        clipboardManager.setText("test");
-        assertTrue(clipboardManager.hasText());
-
-        clipboardManager.setText(null);
-        assertFalse(clipboardManager.hasText());
+        mClipboardManager.setText(null);
+        assertFalse(mClipboardManager.hasText());
     }
 }
diff --git a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
index 6ef1299..426200b 100644
--- a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
@@ -16,23 +16,36 @@
 
 package android.text.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.junit.Assert.fail;
+
 import android.graphics.Paint.FontMetricsInt;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.DynamicLayout;
 import android.text.Layout;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
-public class DynamicLayoutTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    protected static final float SPACING_MULT_NO_SCALE = 1.0f;
-    protected static final float SPACING_ADD_NO_SCALE = 0.0f;
-    protected static final int DEFAULT_OUTER_WIDTH = 150;
-    protected static final CharSequence SINGLELINE_CHAR_SEQUENCE = "......";
-    protected static final String[] TEXT = {"CharSequence\n", "Char\tSequence\n", "CharSequence"};
-    protected static final CharSequence MULTLINE_CHAR_SEQUENCE = TEXT[0] + TEXT[1] + TEXT[2];
-    protected static final Layout.Alignment DEFAULT_ALIGN = Layout.Alignment.ALIGN_CENTER;
-    protected TextPaint mDefaultPaint;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DynamicLayoutTest {
+
+    private static final float SPACING_MULT_NO_SCALE = 1.0f;
+    private static final float SPACING_ADD_NO_SCALE = 0.0f;
+    private static final int DEFAULT_OUTER_WIDTH = 150;
+    private static final CharSequence SINGLELINE_CHAR_SEQUENCE = "......";
+    private static final String[] TEXT = {"CharSequence\n", "Char\tSequence\n", "CharSequence"};
+    private static final CharSequence MULTLINE_CHAR_SEQUENCE = TEXT[0] + TEXT[1] + TEXT[2];
+    private static final Layout.Alignment DEFAULT_ALIGN = Layout.Alignment.ALIGN_CENTER;
+    private TextPaint mDefaultPaint;
 
     private static final int LINE0 = 0;
     private static final int LINE0_TOP = 0;
@@ -44,9 +57,8 @@
 
     private DynamicLayout mDynamicLayout;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mDefaultPaint = new TextPaint();
         mDynamicLayout = new DynamicLayout(MULTLINE_CHAR_SEQUENCE,
                 mDefaultPaint,
@@ -57,6 +69,7 @@
                 true);
     }
 
+    @Test
     public void testConstructors() {
         new DynamicLayout(SINGLELINE_CHAR_SEQUENCE,
                 MULTLINE_CHAR_SEQUENCE,
@@ -85,6 +98,7 @@
                 true);
     }
 
+    @Test
     public void testEllipsis() {
         final DynamicLayout dynamicLayout = new DynamicLayout(SINGLELINE_CHAR_SEQUENCE,
                 MULTLINE_CHAR_SEQUENCE,
@@ -106,6 +120,7 @@
      * 1. Include padding while calculate the layout.
      * 2. Don't include padding while calculate the layout.
      */
+    @Test
     public void testIncludePadding() {
         final FontMetricsInt fontMetricsInt = mDefaultPaint.getFontMetricsInt();
 
@@ -137,6 +152,7 @@
      * Test the line top
      * 1. the Y-coordinate of line top.2. the Y-coordinate of baseline.
      */
+    @Test
     public void testLineLayout() {
         assertEquals(TEXT.length, mDynamicLayout.getLineCount());
         assertFalse(mDynamicLayout.getLineContainsTab(LINE0));
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..aa42505 100644
--- a/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java
+++ b/tests/tests/text/src/android/text/cts/Editable_FactoryTest.java
@@ -16,31 +16,37 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
-import android.text.SpannableStringBuilder;
 import android.text.Editable.Factory;
+import android.text.SpannableStringBuilder;
 
-public class Editable_FactoryTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    Factory mFactory;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Editable_FactoryTest {
+    private Factory mFactory;
 
+    @Test
     public void testNewEditable() {
-
         CharSequence source = "abc";
         // set the expected value
         Editable expected = new SpannableStringBuilder(source);
 
-        // new the Factory instance
         mFactory = new Editable.Factory();
         Editable actual = mFactory.newEditable(source);
         assertEquals(expected.toString(), actual.toString());
 
     }
 
+    @Test
     public void testGetInstance() {
-
-        // new the Factory instance
         mFactory = Factory.getInstance();
         assertTrue(mFactory instanceof Editable.Factory);
     }
diff --git a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
index cdbc867..fcbc510 100644
--- a/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
+++ b/tests/tests/text/src/android/text/cts/EmojiCtsActivity.java
@@ -16,13 +16,12 @@
 
 package android.text.cts;
 
-import android.text.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.cts.util.NullWebViewUtils;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+
 public class EmojiCtsActivity extends Activity {
     private WebView mWebView;
 
diff --git a/tests/tests/text/src/android/text/cts/EmojiTest.java b/tests/tests/text/src/android/text/cts/EmojiTest.java
index 4bc586e..2e5bbad 100644
--- a/tests/tests/text/src/android/text/cts/EmojiTest.java
+++ b/tests/tests/text/src/android/text/cts/EmojiTest.java
@@ -16,38 +16,54 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
-import android.cts.util.NullWebViewUtils;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Picture;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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> {
+import com.android.compatibility.common.util.NullWebViewUtils;
 
-    public EmojiTest() {
-        super("android.text.cts", EmojiCtsActivity.class);
-    }
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiTest {
+    private Context mContext;
+    private EditText mEditText;
 
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @Rule
+    public ActivityTestRule<EmojiCtsActivity> mActivityRule =
+            new ActivityTestRule<>(EmojiCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mContext = mActivityRule.getActivity();
     }
 
     /**
      * Tests all Emoji are defined in Character class
      */
+    @Test
     public void testEmojiCodePoints() {
         for (int i = 0; i < EmojiConstants.emojiCodePoints.length; i++) {
             assertTrue(Character.isDefined(EmojiConstants.emojiCodePoints[i]));
@@ -78,8 +94,10 @@
      * Tests Emoji has different glyph for different meaning characters.
      * Test on Canvas, TextView, EditText and WebView
      */
+    @UiThreadTest
+    @Test
     public void testEmojiGlyph() {
-        CaptureCanvas ccanvas = new CaptureCanvas(getInstrumentation().getContext());
+        CaptureCanvas ccanvas = new CaptureCanvas(mContext);
 
         Bitmap mBitmapA, mBitmapB;  // Emoji displayed Bitmaps to compare
 
@@ -103,17 +121,17 @@
             assertFalse(baseMessage + bmpDiffMessage, mBitmapA.sameAs(mBitmapB));
 
             // cannot reuse CaptureTextView as 2nd setText call throws NullPointerException
-            CaptureTextView cviewA = new CaptureTextView(getInstrumentation().getContext());
+            CaptureTextView cviewA = new CaptureTextView(mContext);
             mBitmapA = cviewA.capture(Character.toChars(comparedCodePoints[i][0]));
-            CaptureTextView cviewB = new CaptureTextView(getInstrumentation().getContext());
+            CaptureTextView cviewB = new CaptureTextView(mContext);
             mBitmapB = cviewB.capture(Character.toChars(comparedCodePoints[i][1]));
 
             bmpDiffMessage = describeBitmap(mBitmapA) + "vs" + describeBitmap(mBitmapB);
             assertFalse(baseMessage + bmpDiffMessage, mBitmapA.sameAs(mBitmapB));
 
-            CaptureEditText cedittextA = new CaptureEditText(getInstrumentation().getContext());
+            CaptureEditText cedittextA = new CaptureEditText(mContext);
             mBitmapA = cedittextA.capture(Character.toChars(comparedCodePoints[i][0]));
-            CaptureEditText cedittextB = new CaptureEditText(getInstrumentation().getContext());
+            CaptureEditText cedittextB = new CaptureEditText(mContext);
             mBitmapB = cedittextB.capture(Character.toChars(comparedCodePoints[i][1]));
 
             bmpDiffMessage = describeBitmap(mBitmapA) + "vs" + describeBitmap(mBitmapB);
@@ -121,9 +139,8 @@
 
             // Trigger activity bringup so we can determine if a WebView is available on this
             // device.
-            EmojiCtsActivity activity = getActivity();
             if (NullWebViewUtils.isWebViewAvailable()) {
-                CaptureWebView cwebview = new CaptureWebView(getInstrumentation().getContext());
+                CaptureWebView cwebview = new CaptureWebView();
                 mBitmapA = cwebview.capture(Character.toChars(comparedCodePoints[i][0]));
                 mBitmapB = cwebview.capture(Character.toChars(comparedCodePoints[i][1]));
                 bmpDiffMessage = describeBitmap(mBitmapA) + "vs" + describeBitmap(mBitmapB);
@@ -135,6 +152,8 @@
     /**
      * Tests EditText handles Emoji
      */
+    @LargeTest
+    @Test
     public void testEmojiEditable() throws Throwable {
         int testedCodePoints[] = {
             0xAE,    // registered mark
@@ -148,23 +167,19 @@
         for (int i = 0; i < testedCodePoints.length; i++) {
             origStr = "Test character  ";
             // cannot reuse CaptureTextView as 2nd setText call throws NullPointerException
-            final EditText editText = new EditText(getInstrumentation().getContext());
-            editText.setText(origStr + String.valueOf(Character.toChars(testedCodePoints[i])));
+            mActivityRule.runOnUiThread(() -> mEditText = new EditText(mContext));
+            mEditText.setText(origStr + String.valueOf(Character.toChars(testedCodePoints[i])));
 
             // confirm the emoji is added.
-            newStr = editText.getText().toString();
+            newStr = mEditText.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));
-                }
-            });
-            getInstrumentation().waitForIdleSync();
+            // Delete added character by sending KEYCODE_DEL event
+            mActivityRule.runOnUiThread(() -> mEditText.dispatchKeyEvent(
+                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)));
+            InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-            newStr = editText.getText().toString();
+            newStr = mEditText.getText().toString();
             assertEquals(newStr.codePointCount(0, newStr.length()), origStr.length() + 1);
         }
     }
@@ -254,13 +269,15 @@
 
         WebViewOnUiThread webViewOnUiThread;
         Bitmap bitmap;
-        CaptureWebView(Context context) {
-            webViewOnUiThread = new WebViewOnUiThread(EmojiTest.this, getActivity().getWebView());
+        CaptureWebView() {
+            webViewOnUiThread = new WebViewOnUiThread(mActivityRule,
+                    mActivityRule.getActivity().getWebView());
         }
 
         Bitmap capture(char c[]) {
 
-            webViewOnUiThread.loadDataAndWaitForCompletion("<html><body>" + String.valueOf(c) + "</body></html>",
+            webViewOnUiThread.loadDataAndWaitForCompletion(
+                    "<html><body>" + String.valueOf(c) + "</body></html>",
                     "text/html; charset=utf-8", "utf-8");
             // The Chromium-powered WebView renders asynchronously and there's nothing reliable
             // we can easily wait for to be sure that capturePicture will return a fresh frame.
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..8faf638
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/GetCharsTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.GetChars;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GetCharsTest {
+
+    // 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)};
+    }
+
+    @Test
+    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..3b8557b 100644
--- a/tests/tests/text/src/android/text/cts/HtmlTest.java
+++ b/tests/tests/text/src/android/text/cts/HtmlTest.java
@@ -16,19 +16,19 @@
 
 package android.text.cts;
 
+import static android.text.Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
+
 import static org.hamcrest.MatcherAssert.assertThat;
-import org.hamcrest.Description;
-import org.hamcrest.BaseMatcher;
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Typeface;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
 import android.text.Layout;
 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,19 +42,25 @@
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
 
-public class HtmlTest extends AndroidTestCase {
-    private final static int SPAN_EXCLUSIVE_INCLUSIVE = Spannable.SPAN_EXCLUSIVE_INCLUSIVE;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HtmlTest {
+    @Test
     public void testSingleTagOnWhileString() {
         final String source = "<b>hello</b>";
 
         Spanned spanned = Html.fromHtml(source);
-        assertSingleTagOnWhileString(spanned);
+        verifySingleTagOnWhileString(spanned);
         spanned = Html.fromHtml(source, null, null);
-        assertSingleTagOnWhileString(spanned);
+        verifySingleTagOnWhileString(spanned);
     }
 
-    private void assertSingleTagOnWhileString(Spanned spanned) {
+    private void verifySingleTagOnWhileString(Spanned spanned) {
         final int expectStart = 0;
         final int expectEnd = 5;
         final int expectLen = 1;
@@ -67,16 +73,17 @@
         assertEquals(expectEnd, spanned.getSpanEnd(spans[0]));
     }
 
+    @Test
     public void testBadHtml() {
         final String source = "Hello <b>b<i>bi</b>i</i>";
 
         Spanned spanned = Html.fromHtml(source);
-        assertBadHtml(spanned);
+        verifyBadHtml(spanned);
         spanned = Html.fromHtml(source, null, null);
-        assertBadHtml(spanned);
+        verifyBadHtml(spanned);
     }
 
-    private void assertBadHtml(Spanned spanned) {
+    private void verifyBadHtml(Spanned spanned) {
         final int start = 0;
         final int end = 100;
         final int spansLen = 3;
@@ -85,6 +92,7 @@
         assertEquals(spansLen, spans.length);
     }
 
+    @Test
     public void testSymbols() {
         final String source = "&copy; &gt; &lt";
         final String expected = "\u00a9 > <";
@@ -95,7 +103,8 @@
         assertEquals(expected, spanned);
     }
 
-    public void testColor() throws Exception {
+    @Test
+    public void testColor() {
         final Class<ForegroundColorSpan> type = ForegroundColorSpan.class;
 
         Spanned s = Html.fromHtml("<font color=\"#00FF00\">something</font>");
@@ -140,7 +149,8 @@
         assertEquals(0xFF444444, colors[0].getForegroundColor());
     }
 
-    public void testUseCssColor() throws Exception {
+    @Test
+    public void testUseCssColor() {
         final Class<ForegroundColorSpan> type = ForegroundColorSpan.class;
         final int flags = Html.FROM_HTML_OPTION_USE_CSS_COLORS;
 
@@ -173,6 +183,7 @@
         assertEquals(0xFFA9A9A9, colors[0].getForegroundColor());
     }
 
+    @Test
     public void testStylesFromHtml() {
         Spanned s = Html.fromHtml("<span style=\"color:#FF0000; background-color:#00FF00; "
                 + "text-decoration:line-through;\">style</span>");
@@ -189,7 +200,8 @@
         assertEquals(1, strike.length);
     }
 
-    public void testParagraphs() throws Exception {
+    @Test
+    public void testParagraphs() {
         SpannableString s = new SpannableString("Hello world");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace(
                 "<p dir=\"ltr\">Hello world</p>"));
@@ -217,7 +229,8 @@
                 + "<p dir=\"ltr\" style=\"margin-top:0; margin-bottom:0;\">or something</p>"));
     }
 
-    public void testParagraphStyles() throws Exception {
+    @Test
+    public void testParagraphStyles() {
         SpannableString s = new SpannableString("Hello world");
         s.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER),
                 0, s.length(), Spanned.SPAN_PARAGRAPH);
@@ -244,7 +257,8 @@
                 + "Hello world</p>"));
     }
 
-    public void testBulletSpan() throws Exception {
+    @Test
+    public void testBulletSpan() {
         SpannableString s = new SpannableString("Bullet1\nBullet2\nNormal paragraph");
         s.setSpan(new BulletSpan(), 0, 8, Spanned.SPAN_PARAGRAPH);
         s.setSpan(new BulletSpan(), 8, 16, Spanned.SPAN_PARAGRAPH);
@@ -257,7 +271,8 @@
                 + "<p dir=\"ltr\" style=\"margin-top:0; margin-bottom:0;\">Normal paragraph</p>"));
     }
 
-    public void testBlockquote() throws Exception {
+    @Test
+    public void testBlockquote() {
         final int start = 0;
 
         SpannableString s = new SpannableString("Hello world");
@@ -273,7 +288,8 @@
                 "<blockquote><p dir=\"ltr\">Hello</p>\n</blockquote>\n<p dir=\"ltr\">world</p>"));
     }
 
-    public void testEntities() throws Exception {
+    @Test
+    public void testEntities() {
         SpannableString s = new SpannableString("Hello <&> world");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace(
                 "<p dir=\"ltr\">Hello &lt;&amp;&gt; world</p>"));
@@ -287,7 +303,8 @@
                 "<p dir=\"ltr\">Hello&nbsp; world</p>"));
     }
 
-    public void testMarkup() throws Exception {
+    @Test
+    public void testMarkup() {
         final int start = 6;
 
         SpannableString s = new SpannableString("Hello bold world");
@@ -351,7 +368,8 @@
                 + "<span style=\"background-color:#00FF00;\">background</span> world</p>"));
     }
 
-    public void testMarkupFromHtml() throws Exception {
+    @Test
+    public void testMarkupFromHtml() {
         final int expectedStart = 6;
         final int expectedEnd = expectedStart + 6;
 
@@ -372,7 +390,8 @@
      * {@link AlignmentSpan}s. Note that the span will also cover the first newline character after
      * the text.
      */
-    public void testTextAlignCssFromHtml() throws Exception {
+    @Test
+    public void testTextAlignCssFromHtml() {
         String tags[] = {"p", "h1", "h2", "h3", "h4", "h5", "h6", "div", "blockquote"};
 
         for (String tag : tags) {
@@ -417,7 +436,8 @@
         }
     }
 
-    public void testBlockLevelElementsFromHtml() throws Exception {
+    @Test
+    public void testBlockLevelElementsFromHtml() {
         String source = "<blockquote>BLOCKQUOTE</blockquote>"
                 + "<div>DIV</div>"
                 + "<p>P</p>"
@@ -439,7 +459,8 @@
                 Html.fromHtml(source, flags, null, null).toString());
     }
 
-    public void testListFromHtml() throws Exception {
+    @Test
+    public void testListFromHtml() {
         String source = "CITRUS FRUITS:<ul><li>LEMON</li><li>LIME</li><li>ORANGE</li></ul>";
         assertEquals("CITRUS FRUITS:\n\nLEMON\n\nLIME\n\nORANGE\n\n",
                 Html.fromHtml(source).toString());
@@ -459,7 +480,8 @@
                 Html.fromHtml(source, flags, null, null).toString());
     }
 
-    public void testParagraphFromHtml() throws Exception {
+    @Test
+    public void testParagraphFromHtml() {
         final int flags = Html.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH;
 
         String source = "<p>Line 1</p><p>Line 2</p>";
@@ -487,7 +509,8 @@
                 Html.fromHtml(source).toString());
     }
 
-    public void testHeadingFromHtml() throws Exception {
+    @Test
+    public void testHeadingFromHtml() {
         final int flags = Html.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING;
 
         String source = "<h1>Heading 1</h1><h1>Heading 2</h1>";
@@ -509,25 +532,29 @@
                 Html.fromHtml(source).toString());
     }
 
-    public void testImg() throws Exception {
+    @Test
+    public void testImg() {
         Spanned s = Html.fromHtml("yes<img src=\"http://example.com/foo.gif\">no");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace(
                 "<p dir=\"ltr\">yes<img src=\"http://example.com/foo.gif\">no</p>"));
     }
 
-    public void testUtf8() throws Exception {
+    @Test
+    public void testUtf8() {
         Spanned s = Html.fromHtml("<p>\u0124\u00eb\u0142\u0142o, world!</p>");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace(
                 "<p dir=\"ltr\">&#292;&#235;&#322;&#322;o, world!</p>"));
     }
 
-    public void testSurrogates() throws Exception {
+    @Test
+    public void testSurrogates() {
         Spanned s = Html.fromHtml("\ud83d\udc31");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace(
                 "<p dir=\"ltr\">&#128049;</p>"));
     }
 
-    public void testBadSurrogates() throws Exception {
+    @Test
+    public void testBadSurrogates() {
         Spanned s = Html.fromHtml("\udc31\ud83d");
         assertThat(Html.toHtml(s), matchesIgnoringTrailingWhitespace("<p dir=\"ltr\"></p>"));
     }
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..9e5d293 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_AllCapsTest.java
@@ -16,15 +16,22 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
-import android.text.SpannableStringBuilder;
 import android.text.InputFilter.AllCaps;
+import android.text.SpannableStringBuilder;
 
-public class InputFilter_AllCapsTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputFilter_AllCapsTest {
+    @Test
     public void testFilter() {
-
         // Implicitly invoked
         CharSequence source = "Caps";
         SpannableStringBuilder dest = new SpannableStringBuilder("AllTest");
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..722ad19 100644
--- a/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java
+++ b/tests/tests/text/src/android/text/cts/InputFilter_LengthFilterTest.java
@@ -16,13 +16,21 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
-import android.text.SpannableStringBuilder;
 import android.text.InputFilter.LengthFilter;
+import android.text.SpannableStringBuilder;
 
-public class InputFilter_LengthFilterTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputFilter_LengthFilterTest {
+    @Test
     public void testFilter() {
         // Define the variables
         CharSequence source;
@@ -31,6 +39,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..d94fb23 100644
--- a/tests/tests/text/src/android/text/cts/LayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/LayoutTest.java
@@ -16,17 +16,38 @@
 
 package android.text.cts;
 
+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.junit.Assert.fail;
 
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.Rect;
-import android.test.AndroidTestCase;
+import android.graphics.RectF;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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;
 
-public class LayoutTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LayoutTest {
     private final static int LINE_COUNT = 5;
     private final static int LINE_HEIGHT = 12;
     private final static int LINE_DESCENT = 4;
@@ -34,75 +55,79 @@
 
     private int mWidth;
     private Layout.Alignment mAlign;
-    private float mSpacingmult;
-    private float mSpacingadd;
+    private float mSpacingMult;
+    private float mSpacingAdd;
     private SpannableString mSpannedText;
 
     private TextPaint mTextPaint;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mTextPaint = new TextPaint();
         mSpannedText = new SpannableString(LAYOUT_TEXT);
         mSpannedText.setSpan(new StrikethroughSpan(), 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
         mWidth = 11;
         mAlign = Alignment.ALIGN_CENTER;
-        mSpacingmult = 1;
-        mSpacingadd = 2;
+        mSpacingMult = 1;
+        mSpacingAdd = 2;
     }
 
+    @Test
     public void testConstructor() {
-        new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingmult, mSpacingadd);
-
-        try {
-            new MockLayout(null, null, -1, null, 0, 0);
-            fail("should throw IllegalArgumentException here");
-        } catch (IllegalArgumentException e) {
-        }
+        new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorNull() {
+        new MockLayout(null, null, -1, null, 0, 0);
+    }
+
+    @Test
     public void testGetText() {
         CharSequence text = "test case 1";
         Layout layout = new MockLayout(text, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(text, layout.getText());
 
-        layout = new MockLayout(null, mTextPaint, mWidth, mAlign, mSpacingmult, mSpacingadd);
+        layout = new MockLayout(null, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
         assertNull(layout.getText());
     }
 
+    @Test
     public void testGetPaint() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
 
         assertSame(mTextPaint, layout.getPaint());
 
-        layout = new MockLayout(LAYOUT_TEXT, null, mWidth, mAlign, mSpacingmult, mSpacingadd);
+        layout = new MockLayout(LAYOUT_TEXT, null, mWidth, mAlign, mSpacingMult, mSpacingAdd);
         assertNull(layout.getPaint());
     }
 
+    @Test
     public void testGetWidth() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 10,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(10,  layout.getWidth());
 
-        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingmult, mSpacingadd);
+        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(0,  layout.getWidth());
     }
 
+    @Test
     public void testGetEllipsizedWidth() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 15,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(15, layout.getEllipsizedWidth());
 
-        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingmult, mSpacingadd);
+        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(0,  layout.getEllipsizedWidth());
     }
 
+    @Test
     public void testIncreaseWidthTo() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         int oldWidth = layout.getWidth();
 
         layout.increaseWidthTo(oldWidth);
@@ -118,40 +143,45 @@
         assertEquals(oldWidth + 1, layout.getWidth());
     }
 
+    @Test
     public void testGetHeight() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(60, layout.getHeight());
     }
 
+    @Test
     public void testGetAlignment() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertSame(mAlign, layout.getAlignment());
 
-        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, null, mSpacingmult, mSpacingadd);
+        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, null, mSpacingMult, mSpacingAdd);
         assertNull(layout.getAlignment());
     }
 
+    @Test
     public void testGetSpacingMultiplier() {
-        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, -1, mSpacingadd);
-        assertEquals(-1.0f, layout.getSpacingMultiplier());
+        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, -1, mSpacingAdd);
+        assertEquals(-1.0f, layout.getSpacingMultiplier(), 0.0f);
 
-        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, 5, mSpacingadd);
-        assertEquals(5.0f, layout.getSpacingMultiplier());
+        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, 5, mSpacingAdd);
+        assertEquals(5.0f, layout.getSpacingMultiplier(), 0.0f);
     }
 
+    @Test
     public void testGetSpacingAdd() {
-        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingmult, -1);
-        assertEquals(-1.0f, layout.getSpacingAdd());
+        Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, -1);
+        assertEquals(-1.0f, layout.getSpacingAdd(), 0.0f);
 
-        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingmult, 20);
-        assertEquals(20.0f, layout.getSpacingAdd());
+        layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, 20);
+        assertEquals(20.0f, layout.getSpacingAdd(), 0.0f);
     }
 
+    @Test
     public void testGetLineBounds() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         Rect bounds = new Rect();
 
         assertEquals(32, layout.getLineBounds(2, bounds));
@@ -161,33 +191,37 @@
         assertEquals(36, bounds.bottom);
     }
 
+    @Test
     public void testGetLineForVertical() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(0, layout.getLineForVertical(-1));
         assertEquals(0, layout.getLineForVertical(0));
         assertEquals(0, layout.getLineForVertical(LINE_COUNT));
         assertEquals(LINE_COUNT - 1, layout.getLineForVertical(1000));
     }
 
+    @Test
     public void testGetLineForOffset() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(0, layout.getLineForOffset(-1));
         assertEquals(1, layout.getLineForOffset(1));
         assertEquals(LINE_COUNT - 1, layout.getLineForOffset(LINE_COUNT - 1));
         assertEquals(LINE_COUNT - 1, layout.getLineForOffset(1000));
     }
 
+    @Test
     public void testGetLineEnd() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(2, layout.getLineEnd(1));
     }
 
+    @Test
     public void testGetLineVisibleEnd() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
 
         assertEquals(2, layout.getLineVisibleEnd(1));
         assertEquals(LINE_COUNT, layout.getLineVisibleEnd(LINE_COUNT - 1));
@@ -199,59 +233,67 @@
         }
     }
 
+    @Test
     public void testGetLineBottom() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(LINE_HEIGHT, layout.getLineBottom(0));
     }
 
+    @Test
     public void testGetLineBaseline() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(8, layout.getLineBaseline(0));
     }
 
+    @Test
     public void testGetLineAscent() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(-8, layout.getLineAscent(0));
     }
 
+    @Test
     public void testGetParagraphAlignment() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertSame(mAlign, layout.getParagraphAlignment(0));
 
         layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertSame(mAlign, layout.getParagraphAlignment(0));
         assertSame(mAlign, layout.getParagraphAlignment(1));
     }
 
+    @Test
     public void testGetParagraphLeft() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(0, layout.getParagraphLeft(0));
     }
 
+    @Test
     public void testGetParagraphRight() {
         Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertEquals(mWidth, layout.getParagraphRight(0));
     }
 
+    @Test
     public void testIsSpanned() {
         MockLayout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         // default is not spanned text
         assertFalse(layout.mockIsSpanned());
 
         // try to create a spanned text
         layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
-                mAlign, mSpacingmult, mSpacingadd);
+                mAlign, mSpacingMult, mSpacingAdd);
         assertTrue(layout.mockIsSpanned());
     }
 
+    @Test
     public void testGetDesiredWidthRange() {
         CharSequence textShort = "test";
         CharSequence textLonger = "test\ngetDesiredWidth";
@@ -264,10 +306,11 @@
         float widthZero = Layout.getDesiredWidth(textLonger, 5, textShort.length() - 3, paint);
         assertTrue(widthLonger > widthShort);
         assertTrue(widthLongest > widthLonger);
-        assertEquals(0f, widthZero);
+        assertEquals(0f, widthZero, 0.0f);
         assertTrue(widthShort > widthPartShort);
     }
 
+    @Test
     public void testGetDesiredWidth() {
         CharSequence textShort = "test";
         CharSequence textLonger = "test\ngetDesiredWidth";
@@ -322,7 +365,7 @@
 
         @Override
         public Directions getLineDirections(int line) {
-            return null;
+            return Layout.DIRS_ALL_LEFT_TO_RIGHT;
         }
 
         @Override
@@ -351,4 +394,109 @@
             return 0;
         }
     }
+
+    @Test
+    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);
+        }
+    }
+
+    @Test
+    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);
+        }
+    }
+
+    @Test
+    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, 0.0f);
+        }
+    }
+
+    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..855823a 100644
--- a/tests/tests/text/src/android/text/cts/LoginFilterTest.java
+++ b/tests/tests/text/src/android/text/cts/LoginFilterTest.java
@@ -16,72 +16,85 @@
 
 package android.text.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyChar;
+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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.LoginFilter;
+import android.text.LoginFilter.UsernameFilterGeneric;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.SpannedString;
 
-public class LoginFilterTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LoginFilterTest {
+    @Test
     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());
@@ -116,72 +129,25 @@
 
     // This method does nothing. we only test onInvalidCharacter function here,
     // the callback should be tested in testFilter()
+    @Test
     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()
+    @Test
     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()
+    @Test
     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/LoginFilter_PasswordFilterGMailTest.java b/tests/tests/text/src/android/text/cts/LoginFilter_PasswordFilterGMailTest.java
index ec567c3..1f02481 100644
--- a/tests/tests/text/src/android/text/cts/LoginFilter_PasswordFilterGMailTest.java
+++ b/tests/tests/text/src/android/text/cts/LoginFilter_PasswordFilterGMailTest.java
@@ -16,19 +16,27 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.LoginFilter.PasswordFilterGMail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class LoginFilter_PasswordFilterGMailTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LoginFilter_PasswordFilterGMailTest {
+    @Test
     public void testConstructor() {
         new PasswordFilterGMail();
         new PasswordFilterGMail(true);
         new PasswordFilterGMail(false);
     }
 
+    @Test
     public void testIsAllowed() {
         PasswordFilterGMail passwordFilterGMail = new PasswordFilterGMail();
 
diff --git a/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGMailTest.java b/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGMailTest.java
index 90cc097..fd196b8 100644
--- a/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGMailTest.java
+++ b/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGMailTest.java
@@ -16,18 +16,27 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.LoginFilter.UsernameFilterGMail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class LoginFilter_UsernameFilterGMailTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LoginFilter_UsernameFilterGMailTest {
+    @Test
     public void testConstructor() {
         new UsernameFilterGMail();
         new UsernameFilterGMail(true);
         new UsernameFilterGMail(false);
     }
 
+    @Test
     public void testIsAllowed() {
         UsernameFilterGMail usernameFilterGMail = new UsernameFilterGMail();
 
diff --git a/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGenericTest.java b/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGenericTest.java
index f9043ee..68cc840 100644
--- a/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGenericTest.java
+++ b/tests/tests/text/src/android/text/cts/LoginFilter_UsernameFilterGenericTest.java
@@ -16,19 +16,27 @@
 
 package android.text.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.LoginFilter.UsernameFilterGeneric;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class LoginFilter_UsernameFilterGenericTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LoginFilter_UsernameFilterGenericTest {
+    @Test
     public void testConstructor() {
         new UsernameFilterGeneric();
         new UsernameFilterGeneric(true);
         new UsernameFilterGeneric(false);
     }
 
+    @Test
     public void testIsAllowed() {
         UsernameFilterGeneric usernameFilterGeneric = new UsernameFilterGeneric();
 
diff --git a/tests/tests/text/src/android/text/cts/MyanmarTest.java b/tests/tests/text/src/android/text/cts/MyanmarTest.java
index 9988ab9..5ded363 100644
--- a/tests/tests/text/src/android/text/cts/MyanmarTest.java
+++ b/tests/tests/text/src/android/text/cts/MyanmarTest.java
@@ -16,41 +16,40 @@
 
 package android.text.cts;
 
-import android.app.Activity;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.TextView;
 
-public class MyanmarTest extends ActivityInstrumentationTestCase2<Activity> {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    public MyanmarTest() {
-        super("android.text.cts", Activity.class);
-    }
-
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MyanmarTest {
     /**
      * Tests Unicode composition semantics.
      */
+    @UiThreadTest
+    @Test
     public void testCompositionSemantics() {
+        Context context = InstrumentationRegistry.getTargetContext();
         String textA = "\u1019\u102d\u102f";
         String textB = "\u1019\u102f\u102d"; // wrong order for Unicode
 
-        CaptureTextView cviewA = new CaptureTextView(getInstrumentation().getContext());
+        CaptureTextView cviewA = new CaptureTextView(context);
         Bitmap bitmapA = cviewA.capture(textA);
-        CaptureTextView cviewB = new CaptureTextView(getInstrumentation().getContext());
+        CaptureTextView cviewB = new CaptureTextView(context);
         Bitmap bitmapB = cviewB.capture(textB);
         if (bitmapA.sameAs(bitmapB)) {
             // if textA and textB render identically, test against replacement characters
             String textC = "\ufffd\ufffd\ufffd"; // replacement characters are acceptable
-            CaptureTextView cviewC = new CaptureTextView(getInstrumentation().getContext());
+            CaptureTextView cviewC = new CaptureTextView(context);
             Bitmap bitmapC = cviewC.capture(textC);
             if (!bitmapA.sameAs(bitmapC)) {
                 // ...or against blank/empty glyphs
diff --git a/tests/tests/text/src/android/text/cts/SelectionTest.java b/tests/tests/text/src/android/text/cts/SelectionTest.java
index 4946a50..f920bda 100644
--- a/tests/tests/text/src/android/text/cts/SelectionTest.java
+++ b/tests/tests/text/src/android/text/cts/SelectionTest.java
@@ -16,14 +16,25 @@
 
 package android.text.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 android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 
-public class SelectionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SelectionTest {
+    @Test
     public void testGetSelectionStart() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -41,6 +52,7 @@
         assertEquals(-1, Selection.getSelectionStart(null));
     }
 
+    @Test
     public void testGetSelectionEnd() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -58,6 +70,7 @@
         assertEquals(-1, Selection.getSelectionStart(null));
     }
 
+    @Test
     public void testSetSelection1() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -87,6 +100,7 @@
         }
     }
 
+    @Test
     public void testSetSelection2() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         assertEquals(-1, Selection.getSelectionStart(builder));
@@ -113,6 +127,7 @@
         }
     }
 
+    @Test
     public void testRemoveSelection() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -132,6 +147,7 @@
         assertEquals(-1, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testSelectAll() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -158,6 +174,7 @@
         assertEquals(0, Selection.getSelectionEnd(empty));
     }
 
+    @Test
     public void testMoveLeft() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -185,6 +202,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testMoveRight() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -216,6 +234,7 @@
         assertEquals(text.length(), Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testMoveUp() {
         CharSequence text = "Google\nhello,world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -255,6 +274,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testMoveDown() {
         CharSequence text = "hello,world\nGoogle";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -292,6 +312,7 @@
         assertEquals(18, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendSelection() {
         CharSequence text = "hello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -338,6 +359,7 @@
         }
     }
 
+    @Test
     public void testExtendLeft() {
         CharSequence text = "Google\nhello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -364,6 +386,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendRight() {
         CharSequence text = "Google\nhello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -386,6 +409,7 @@
         assertEquals(text.length(), Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendUp() {
         CharSequence text = "Google\nhello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -416,6 +440,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendDown() {
         CharSequence text = "Google\nhello, world";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -437,6 +462,7 @@
         assertEquals(text.length(), Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendToLeftEdge() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -472,6 +498,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testExtendToRightEdge() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -498,6 +525,7 @@
         assertEquals(text.length(), Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testMoveToLeftEdge() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -529,6 +557,7 @@
         assertEquals(0, Selection.getSelectionEnd(builder));
     }
 
+    @Test
     public void testMoveToRightEdge() {
         CharSequence text = "hello\nworld";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
index 14bcc8e..f693038 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
@@ -16,10 +16,12 @@
 
 package android.text.cts;
 
-import java.util.ArrayList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
 import android.text.SpanWatcher;
 import android.text.Spannable;
@@ -29,17 +31,24 @@
 import android.text.style.ParagraphStyle;
 import android.text.style.QuoteSpan;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
 /**
  * Test {@link SpannableStringBuilder}.
  */
-public class SpannableStringBuilderSpanTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringBuilderSpanTest {
     private static final boolean DEBUG = false;
 
     private SpanSet mSpanSet = new SpanSet();
     private SpanSet mReplacementSpanSet = new SpanSet();
     private int testCounter;
 
+    @Test
     public void testReplaceWithSpans() {
         testCounter = 0;
         String originals[] = { "", "A", "here", "Well, hello there" };
@@ -116,13 +125,13 @@
 
         assertEquals(expected, originalSpannable.toString());
 
-        checkSpanPositions(originalSpannable, replaceStart, replaceEnd, subReplacement.length(),
+        verifySpanPositions(originalSpannable, replaceStart, replaceEnd, subReplacement.length(),
                 flag);
-        checkReplacementSpanPositions(originalSpannable, replaceStart, replacementSpannable,
+        verifyReplacementSpanPositions(originalSpannable, replaceStart, replacementSpannable,
                 replacementStart, replacementEnd, flag);
     }
 
-    private void checkSpanPositions(Spannable spannable, int replaceStart, int replaceEnd,
+    private void verifySpanPositions(Spannable spannable, int replaceStart, int replaceEnd,
             int replacementLength, int flag) {
         int count = 0;
         int replacedLength = replaceEnd - replaceStart;
@@ -154,7 +163,7 @@
                     // 0-length spans should have been removed
                     assertEquals(-1, start);
                     assertEquals(-1, end);
-                    mSpanSet.mRecorder.assertRemoved(span, originalStart, originalEnd);
+                    mSpanSet.mRecorder.verifyRemoved(span, originalStart, originalEnd);
                     continue;
                 }
 
@@ -227,15 +236,15 @@
                 }
 
                 if (start != originalStart || end != originalEnd) {
-                    mSpanSet.mRecorder.assertChanged(span, originalStart, originalEnd, start, end);
+                    mSpanSet.mRecorder.verifyChanged(span, originalStart, originalEnd, start, end);
                 } else {
-                    mSpanSet.mRecorder.assertUnmodified(span);
+                    mSpanSet.mRecorder.verifyUnmodified(span);
                 }
             }
         }
     }
 
-    private void checkReplacementSpanPositions(Spannable originalSpannable, int replaceStart,
+    private void verifyReplacementSpanPositions(Spannable originalSpannable, int replaceStart,
             Spannable replacementSpannable, int replStart, int replEnd, int flag) {
 
         // Get all spans overlapping the replacement substring region
@@ -257,7 +266,7 @@
                         " -> " + start + "," + end);
 
                 // There should be no change reported to the replacement string spanWatcher
-                mReplacementSpanSet.mRecorder.assertUnmodified(span);
+                mReplacementSpanSet.mRecorder.verifyUnmodified(span);
 
                 boolean shouldBeAdded = false;
                 for (int i = 0; i < addedSpans.length; i++) {
@@ -273,12 +282,12 @@
                     if (isValidSpan(newStart, newEnd, flag)) {
                         assertEquals(start, newStart);
                         assertEquals(end, newEnd);
-                        mSpanSet.mRecorder.assertAdded(span, start, end);
+                        mSpanSet.mRecorder.verifyAdded(span, start, end);
                         continue;
                     }
                 }
 
-                mSpanSet.mRecorder.assertUnmodified(span);
+                mSpanSet.mRecorder.verifyUnmodified(span);
             }
         }
     }
@@ -443,7 +452,7 @@
             if (text == mSpannable) mChanged.add(new Changed(span, ostart, oend, nstart, nend));
         }
 
-        public void assertUnmodified(Object span) {
+        public void verifyUnmodified(Object span) {
             for (AddedRemoved added: mAdded) {
                 if (added.span == span)
                     fail("Span " + span + " was added and not unmodified");
@@ -458,7 +467,7 @@
             }
         }
 
-        public void assertChanged(Object span, int oldStart, int oldEnd, int newStart, int newEnd) {
+        public void verifyChanged(Object span, int oldStart, int oldEnd, int newStart, int newEnd) {
             for (Changed changed : mChanged) {
                 if (changed.span == span) {
                     assertEquals(changed.newStart, newStart);
@@ -473,7 +482,7 @@
             fail("Span " + span + " was not changed");
         }
 
-        public void assertAdded(Object span, int start, int end) {
+        public void verifyAdded(Object span, int start, int end) {
             for (AddedRemoved added : mAdded) {
                 if (added.span == span) {
                     assertEquals(added.start, start);
@@ -484,7 +493,7 @@
             fail("Span " + span + " was not added");
         }
 
-        public void assertRemoved(Object span, int start, int end) {
+        public void verifyRemoved(Object span, int start, int end) {
             for (AddedRemoved removed : mRemoved) {
                 if (removed.span == span) {
                     assertEquals(removed.start, start);
@@ -499,10 +508,8 @@
     // TODO Thoroughly test the SPAN_PARAGRAPH span flag.
 
 
-    @SmallTest
-    public void
-    testReplace_discardsParagraphSpanInSourceIfThereIsNoNewLineBefore()
-            throws Exception {
+    @Test
+    public void testReplace_discardsParagraphSpanInSourceIfThereIsNoNewLineBefore() {
         SpannableStringBuilder spannable = new SpannableStringBuilder("1 selection_to_replace");
         Spanned newText = Html.fromHtml("<blockquote>new text</blockquote>");
         assertEquals(1, newText.getSpans(0, newText.length(), ParagraphStyle.class).length);
@@ -514,9 +521,8 @@
         assertEquals(0, paragraphSpans.length);
     }
 
-    @SmallTest
-    public void testReplace_retainsParagraphSpanInSourceIfThereIsNewLineBefore()
-            throws Exception {
+    @Test
+    public void testReplace_retainsParagraphSpanInSourceIfThereIsNewLineBefore() {
         SpannableStringBuilder spannable = new SpannableStringBuilder("1\nselection_to_replace");
         Spanned newText = Html.fromHtml("<blockquote>new text</blockquote>");
         assertTrue(newText.getSpans(0, newText.length(), ParagraphStyle.class).length > 0);
@@ -528,9 +534,8 @@
         assertEquals(1, paragraphSpans.length);
     }
 
-    @SmallTest
-    public void testReplace_retainsParagraphSpanInSourceIfStartIsZero()
-            throws Exception {
+    @Test
+    public void testReplace_retainsParagraphSpanInSourceIfStartIsZero() {
         // copy the paragraph span even if there is no previous character - start is equal to 0
 
         SpannableStringBuilder spannable = new SpannableStringBuilder("selection_to_replace");
@@ -544,9 +549,8 @@
         assertEquals(1, paragraphSpans.length);
     }
 
-    @SmallTest
-    public void testReplace_retainsParagraphSpanInSourceIfEndIsEqualToLengthOfString()
-            throws Exception {
+    @Test
+    public void testReplace_retainsParagraphSpanInSourceIfEndIsEqualToLengthOfString() {
         // copy the paragraph span even if the final char is not next line, and if the end is
         // equal to the string length
 
@@ -564,9 +568,8 @@
         assertEquals(1, paragraphSpans.length);
     }
 
-    @SmallTest
-    public void testReplace_discardsParagraphSpanInSourceIfThereIsNoNewLineAfter()
-            throws Exception {
+    @Test
+    public void testReplace_discardsParagraphSpanInSourceIfThereIsNoNewLineAfter() {
         SpannableStringBuilder spannable = new SpannableStringBuilder("r remaining\n");
         // create a spannable that does not have \n at the end. Html.fromHtml adds \n to the end of
         // the text
@@ -580,5 +583,4 @@
                 ParagraphStyle.class);
         assertEquals(0, paragraphSpans.length);
     }
-
 }
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
index 6dee5e9..70a68ea 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
@@ -17,78 +17,82 @@
 package android.text.cts;
 
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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 org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
 /**
  * Test {@link SpannableStringBuilder}.
  */
-public class SpannableStringBuilderTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringBuilderTest {
     private StrikethroughSpan mStrikethroughSpan;
     private UnderlineSpan mUnderlineSpan;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mUnderlineSpan = new UnderlineSpan();
         mStrikethroughSpan = new StrikethroughSpan();
     }
 
-    public void testConstructor1() {
-        @SuppressWarnings("unused")
-        SpannableStringBuilder dummy = new SpannableStringBuilder();
-        dummy = new SpannableStringBuilder("test");
-
-        try {
-            dummy = new SpannableStringBuilder(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
+    @Test
+    public void testConstructor() {
+        new SpannableStringBuilder();
+        new SpannableStringBuilder("test");
     }
 
-    public void testConstructor2() {
-        @SuppressWarnings("unused")
-        SpannableStringBuilder dummy = new SpannableStringBuilder("Text", 0, "Text".length());
-        dummy = new SpannableStringBuilder(new SpannableString("test"), 0, "Text".length());
-
-        try {
-            dummy = new SpannableStringBuilder("Text", 0, 10);
-            fail("should throw StringIndexOutOfBoundsException");
-        } catch (StringIndexOutOfBoundsException e) {
-            // expected exception
-        }
-
-        try {
-            dummy = new SpannableStringBuilder("Text", -3, 3);
-            fail("should throw StringIndexOutOfBoundsException");
-        } catch (StringIndexOutOfBoundsException e) {
-            // expected exception
-        }
-
-        try {
-            dummy = new SpannableStringBuilder("Text", 3, 0);
-            fail("should throw StringIndexOutOfBoundsException");
-        } catch (StringIndexOutOfBoundsException e) {
-            // expected exception
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullString() {
+         new SpannableStringBuilder(null);
     }
 
+    @Test
+    public void testConstructorStartEnd() {
+        new SpannableStringBuilder("Text", 0, "Text".length());
+        new SpannableStringBuilder(new SpannableString("test"), 0, "Text".length());
+    }
+
+    @Test(expected=StringIndexOutOfBoundsException.class)
+    public void testConstructorStartEndEndTooLarge() {
+        new SpannableStringBuilder("Text", 0, 10);
+    }
+
+    @Test(expected=StringIndexOutOfBoundsException.class)
+    public void testConstructorStartEndStartTooLow() {
+        new SpannableStringBuilder("Text", -3, 3);
+    }
+
+    @Test(expected=StringIndexOutOfBoundsException.class)
+    public void testConstructorStartEndEndTooLow() {
+        new SpannableStringBuilder("Text", 3, 0);
+    }
+
+    @Test
     public void testGetSpanFlags() {
         SpannableStringBuilder builder = new SpannableStringBuilder("spannable string");
         assertEquals(0, builder.getSpanFlags(mUnderlineSpan));
@@ -102,6 +106,7 @@
         assertEquals(0, builder.getSpanFlags(new Object()));
     }
 
+    @Test
     public void testNextSpanTransition() {
         SpannableStringBuilder builder = new SpannableStringBuilder("spannable string");
 
@@ -117,6 +122,7 @@
         assertEquals(1, builder.nextSpanTransition(3, 1, UnderlineSpan.class));
     }
 
+    @Test
     public void testSetSpan() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         try {
@@ -144,27 +150,25 @@
         assertEquals(Spanned.SPAN_EXCLUSIVE_EXCLUSIVE, builder.getSpanFlags(mUnderlineSpan));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testValueOfNull() {
+        SpannableStringBuilder.valueOf(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testValueOfNullBuilder() {
+        SpannableStringBuilder.valueOf((SpannableStringBuilder) null);
+    }
+
+    @Test
     public void testValueOf() {
-        try {
-            SpannableStringBuilder.valueOf(null);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
-
-        try {
-            SpannableStringBuilder.valueOf((SpannableStringBuilder) null);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
-
         assertNotNull(SpannableStringBuilder.valueOf("hello, string"));
 
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         assertSame(builder, SpannableStringBuilder.valueOf(builder));
     }
 
+    @Test
     public void testReplace1() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world!");
         CharSequence text = "hi";
@@ -197,6 +201,7 @@
         }
     }
 
+    @Test
     public void testReplace2() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         CharSequence text = "ahiabc";
@@ -272,6 +277,7 @@
         }
     }
 
+    @Test
     public void testSubSequence() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         CharSequence text = builder.subSequence(0, 2);
@@ -286,6 +292,7 @@
         }
     }
 
+    @Test
     public void testGetChars() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         char[] buf = new char[4];
@@ -319,6 +326,7 @@
         }
     }
 
+    @Test
     public void testAppend1() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.append(",world");
@@ -331,6 +339,7 @@
         }
     }
 
+    @Test
     public void testAppend2() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.append(",world", 1, 3);
@@ -362,6 +371,7 @@
         }
     }
 
+    @Test
     public void testAppend3() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.append('a');
@@ -377,6 +387,29 @@
         }
     }
 
+    @Test
+    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]));
+    }
+
+    @Test
     public void testClearSpans() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
 
@@ -391,6 +424,7 @@
         assertEquals(0, builder.getSpanFlags(mUnderlineSpan));
     }
 
+    @Test
     public void testGetSpanStart() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.setSpan(mUnderlineSpan, 1, 3, 0);
@@ -399,6 +433,7 @@
         assertEquals(-1, builder.getSpanStart(null));
     }
 
+    @Test
     public void testAccessFilters() {
         InputFilter[] filters = new InputFilter[100];
         SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -413,6 +448,7 @@
         }
     }
 
+    @Test
     public void testRemoveSpan() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
 
@@ -435,6 +471,7 @@
         builder.removeSpan(null);
     }
 
+    @Test
     public void testToString() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         assertEquals("hello", builder.toString());
@@ -443,6 +480,7 @@
         assertEquals("", builder.toString());
     }
 
+    @Test
     public void testGetSpanEnd() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.setSpan(mUnderlineSpan, 1, 3, 0);
@@ -451,6 +489,7 @@
         assertEquals(-1, builder.getSpanEnd(null));
     }
 
+    @Test
     public void testCharAt() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         assertEquals('h', builder.charAt(0));
@@ -470,6 +509,7 @@
         }
     }
 
+    @Test
     public void testInsert1() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.insert(1, "abcd", 1, 3);
@@ -515,6 +555,7 @@
         }
     }
 
+    @Test
     public void testInsert2() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.insert(1, "abcd");
@@ -546,6 +587,7 @@
         }
     }
 
+    @Test
     public void testClear() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         assertEquals("hello", builder.toString());
@@ -553,6 +595,7 @@
         assertEquals("", builder.toString());
     }
 
+    @Test
     public void testGetSpans() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello, world");
         UnderlineSpan span1 = new UnderlineSpan();
@@ -577,7 +620,7 @@
         builder.getSpans(4, 1, UnderlineSpan.class);
     }
 
-    @SmallTest
+    @Test
     public void testGetSpans_returnsEmptyIfSetSpanIsNotCalled() {
         String text = "p_in_s";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -585,7 +628,7 @@
         assertEquals(0, spans.length);
     }
 
-    @SmallTest
+    @Test
     public void testGetSpans_returnsSpansInInsertionOrderWhenTheLaterCoversTheFirst() {
         String text = "p_in_s";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -603,7 +646,7 @@
         assertEquals(second, spans[1]);
     }
 
-    @SmallTest
+    @Test
     public void testGetSpans_returnsSpansSortedFirstByPriorityThenByInsertionOrder() {
         String text = "p_in_s";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -630,7 +673,7 @@
         assertEquals(third, spans[3]);
     }
 
-    @SmallTest
+    @Test
     public void testGetSpans_returnsSpansInInsertionOrderAfterRemoveSpanCalls() {
         String text = "p_in_s";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -655,7 +698,7 @@
         assertEquals(fourth, spans[1]);
     }
 
-    @SmallTest
+    @Test
     public void testGetSpans_sortsByPriorityEvenWhenSortParamIsFalse() {
         String text = "p_in_s";
         SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -681,6 +724,7 @@
         assertEquals(first, spans[3]);
     }
 
+    @Test
     public void testLength() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         assertEquals(5, builder.length());
@@ -688,6 +732,21 @@
         assertEquals(0, builder.length());
     }
 
+    @Test
+    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());
+    }
+
+    @Test
     public void testDelete() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello,world");
         assertEquals("hello,world", builder.toString());
@@ -746,6 +805,7 @@
         }
     }
 
+    @Test
     public void testGetTextWatcherDepth() {
         SpannableStringBuilder builder = new SpannableStringBuilder("hello");
         builder.setSpan(new MockTextWatcher(), 0, builder.length(), 0);
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..4969e67 100644
--- a/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java
+++ b/tests/tests/text/src/android/text/cts/Spannable_FactoryTest.java
@@ -16,13 +16,24 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.Spannable.Factory;
+import android.text.SpannableString;
 
-public class Spannable_FactoryTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Spannable_FactoryTest {
+    @Test
     public void testNewSpannable() {
         final String text = "test newSpannable";
         Factory factory = Spannable.Factory.getInstance();
@@ -31,14 +42,15 @@
         assertNotNull(spannable);
         assertTrue(spannable instanceof SpannableString);
         assertEquals(text, spannable.toString());
-
-        try {
-            factory.newSpannable(null);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testNewSpannableNull() {
+        Factory factory = Spannable.Factory.getInstance();
+        factory.newSpannable(null);
+    }
+
+    @Test
     public void testGetInstance() {
         Spannable.Factory factory = Spannable.Factory.getInstance();
         assertNotNull(factory);
diff --git a/tests/tests/text/src/android/text/cts/SpannedStringTest.java b/tests/tests/text/src/android/text/cts/SpannedStringTest.java
index 3c9b41b..ccdb119 100644
--- a/tests/tests/text/src/android/text/cts/SpannedStringTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannedStringTest.java
@@ -16,20 +16,32 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannedString;
 
-public class SpannedStringTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannedStringTest {
+    @Test
     public void testConstructor() {
         new SpannedString("test");
-
-        try {
-            new SpannedString(null);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNull() {
+        new SpannedString(null);
+    }
+
+    @Test
     public void testValueOf() {
         String text = "test valueOf";
         SpannedString spanned = SpannedString.valueOf(text);
@@ -37,14 +49,14 @@
 
         spanned = new SpannedString(text);
         assertSame(spanned, SpannedString.valueOf(spanned));
-
-        try {
-            SpannedString.valueOf(null);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testValueOfNull() {
+        SpannedString.valueOf(null);
+    }
+
+    @Test
     public void testSubSequence() {
         String text = "hello, world";
         SpannedString spanned = new SpannedString(text);
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..12ebfed
--- /dev/null
+++ b/tests/tests/text/src/android/text/cts/SpannedTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannedTest {
+    // 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)};
+    }
+
+    @Test
+    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) {
+            }
+        }
+    }
+
+    @Test
+    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..5055972 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutLineBreakingTest.java
@@ -16,17 +16,26 @@
 
 package android.text.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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;
 
-public class StaticLayoutLineBreakingTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutLineBreakingTest {
     // Span test are currently not supported because text measurement uses the MeasuredText
     // internal mWorkPaint instead of the provided MockTestPaint.
     private static final boolean SPAN_TESTS_SUPPORTED = false;
@@ -37,8 +46,8 @@
     private static final int WIDTH = 100;
     private static final Alignment ALIGN = Alignment.ALIGN_LEFT;
 
-    final static char SURR_FIRST = '\uD800';
-    final static char SURR_SECOND = '\uDF31';
+    private static final char SURR_FIRST = '\uD800';
+    private static final char SURR_SECOND = '\uDF31';
 
     private static final int[] NO_BREAK = new int[] {};
 
@@ -116,12 +125,12 @@
     private static void debugLayout(CharSequence source, StaticLayout staticLayout) {
         if (DEBUG) {
             int count = staticLayout.getLineCount();
-            Log.i("StaticLayoutLineBreakingTest", "\"" + source.toString() + "\": " +
+            Log.i("SLLBTest", "\"" + source.toString() + "\": " +
                     count + " lines");
             for (int line = 0; line < count; line++) {
                 int lineStart = staticLayout.getLineStart(line);
                 int lineEnd = staticLayout.getLineEnd(line);
-                Log.i("StaticLayoutLineBreakingTest", "Line " + line + " [" + lineStart + ".." +
+                Log.i("SLLBTest", "Line " + line + " [" + lineStart + ".." +
                         lineEnd + "]\t" + source.subSequence(lineStart, lineEnd));
             }
         }
@@ -185,9 +194,9 @@
         }
     }
 
-    final static int MAX_SPAN_COUNT = 10;
-    final static int[] spanStarts = new int[MAX_SPAN_COUNT];
-    final static int[] spanEnds = new int[MAX_SPAN_COUNT];
+    private final static int MAX_SPAN_COUNT = 10;
+    private final static int[] spanStarts = new int[MAX_SPAN_COUNT];
+    private final static int[] spanEnds = new int[MAX_SPAN_COUNT];
 
     private static MetricAffectingSpan getMetricAffectingSpan() {
         return new MetricAffectingSpan() {
@@ -231,6 +240,7 @@
         return result;
     }
 
+    @Test
     public void testNoLineBreak() {
         // Width lower than WIDTH
         layout("", NO_BREAK);
@@ -262,6 +272,7 @@
         //      01234567890
     }
 
+    @Test
     public void testOneLineBreak() {
         //      01234567890
         layout("XX XXX XXXX", new int[] {7});
@@ -281,6 +292,7 @@
         layout("CC", new int[] {1});
     }
 
+    @Test
     public void testSpaceAtBreak() {
         //      0123456789012
         layout("XXXX XXXXX X", new int[] {11});
@@ -289,6 +301,7 @@
         layout("C X", new int[] {2});
     }
 
+    @Test
     public void testMultipleSpacesAtBreak() {
         //      0123456789012
         layout("LXX XXXX", new int[] {4});
@@ -298,6 +311,7 @@
         layout("LXX     XXXX", new int[] {8});
     }
 
+    @Test
     public void testZeroWidthCharacters() {
         //      0123456789012345678901234
         layout("X_X_X_X_X_X_X_X_X_X", NO_BREAK);
@@ -312,6 +326,7 @@
      * To be able to use the fake mTextPaint and make this test pass, use mPaint instead of
      * mWorkPaint in MeasuredText#addStyleRun
      */
+    @Test
     public void testWithSpans() {
         if (!SPAN_TESTS_SUPPORTED) return;
 
@@ -332,6 +347,7 @@
     /*
      * Adding a span to the string should not change the layout, since the metrics are unchanged.
      */
+    @Test
     public void testWithOneSpan() {
         if (!SPAN_TESTS_SUPPORTED) return;
 
@@ -356,6 +372,7 @@
         }
     }
 
+    @Test
     public void testWithTwoSpans() {
         if (!SPAN_TESTS_SUPPORTED) return;
 
@@ -392,18 +409,7 @@
         return string.replaceAll(String.valueOf(c), String.valueOf(r));
     }
 
-    public void testReplacementSpan() {
-        // Add ReplacementSpan to the string
-    }
-
-    public void testParagraphs() {
-        // Add \n to the text
-    }
-
-    public void testWithEmoji() {
-        // Surrogate emoji characters get replaced by a bitmap
-    }
-
+    @Test
     public void testWithSurrogate() {
         layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
         layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK);
@@ -418,6 +424,7 @@
         layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1});
     }
 
+    @Test
     public void testNarrowWidth() {
         int[] widths = new int[] { 0, 4, 10 };
         String[] texts = new String[] { "", "X", " ", "XX", " X", "XXX" };
@@ -433,6 +440,7 @@
         }
     }
 
+    @Test
     public void testNarrowWidthZeroWidth() {
         int[] widths = new int[] { 1, 4 };
         for (int width: widths) {
@@ -449,6 +457,7 @@
         }
     }
 
+    @Test
     public void testMaxLines() {
         layoutMaxLines("C", NO_BREAK, 1);
         layoutMaxLines("C C", new int[] {2}, 1);
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index ed3f1ea..f1e883c 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -16,8 +16,15 @@
 
 package android.text.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.junit.Assert.fail;
+
 import android.graphics.Typeface;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
 import android.text.Layout;
 import android.text.Layout.Alignment;
@@ -33,12 +40,18 @@
 import android.text.method.cts.EditorState;
 import android.text.style.StyleSpan;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.text.Normalizer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
-public class StaticLayoutTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutTest {
     private static final float SPACE_MULTI = 1.0f;
     private static final float SPACE_ADD = 0.0f;
     private static final int DEFAULT_OUTER_WIDTH = 150;
@@ -67,15 +80,10 @@
         // need to have a subclass to insure measurement happens in Java and not C++
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        if (mDefaultPaint == null) {
-            mDefaultPaint = new TextPaint();
-        }
-        if (mDefaultLayout == null) {
-            mDefaultLayout = createDefaultStaticLayout();
-        }
+    @Before
+    public void setup() {
+        mDefaultPaint = new TextPaint();
+        mDefaultLayout = createDefaultStaticLayout();
     }
 
     private StaticLayout createDefaultStaticLayout() {
@@ -100,11 +108,10 @@
                 maxLines);
     }
 
-
-
     /**
      * Constructor test
      */
+    @Test
     public void testConstructor() {
         new StaticLayout(LAYOUT_TEXT, mDefaultPaint, DEFAULT_OUTER_WIDTH,
                 DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
@@ -114,14 +121,14 @@
 
         new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), mDefaultPaint,
                 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, false, null, 0);
-
-        try {
-            new StaticLayout(null, null, -1, null, 0, 0, true);
-            fail("should throw NullPointerException here");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNull() {
+        new StaticLayout(null, null, -1, null, 0, 0, true);
+    }
+
+    @Test
     public void testBuilder() {
         {
             // Obtain.
@@ -136,8 +143,8 @@
             assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR,
                     layout.getTextDirectionHeuristic());
             assertEquals(Alignment.ALIGN_NORMAL, layout.getAlignment());
-            assertEquals(0.0f, layout.getSpacingAdd());
-            assertEquals(1.0f, layout.getSpacingMultiplier());
+            assertEquals(0.0f, layout.getSpacingAdd(), 0.0f);
+            assertEquals(1.0f, layout.getSpacingMultiplier(), 0.0f);
             assertEquals(DEFAULT_OUTER_WIDTH, layout.getEllipsizedWidth());
         }
         {
@@ -181,8 +188,8 @@
                     LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
             builder.setLineSpacing(1.0f, 2.0f);
             StaticLayout layout = builder.build();
-            assertEquals(1.0f, layout.getSpacingAdd());
-            assertEquals(2.0f, layout.getSpacingMultiplier());
+            assertEquals(1.0f, layout.getSpacingAdd(), 0.0f);
+            assertEquals(2.0f, layout.getSpacingMultiplier(), 0.0f);
         }
         {
             // setEllipsizedWidth and setEllipsize.
@@ -227,6 +234,7 @@
      *  if you ask for a position below the bottom of the text, you get the last line.
      *  Test 4 values containing -1, 0, normal number and > count
      */
+    @Test
     public void testGetLineForVertical() {
         assertEquals(0, mDefaultLayout.getLineForVertical(-1));
         assertEquals(0, mDefaultLayout.getLineForVertical(0));
@@ -237,6 +245,7 @@
     /**
      * Return the number of lines of text in this layout.
      */
+    @Test
     public void testGetLineCount() {
         assertEquals(LINE_COUNT, mDefaultLayout.getLineCount());
     }
@@ -247,21 +256,20 @@
      * A line of text contains top and bottom in height. this method just get the top of a line
      * Test 4 values containing -1, 0, normal number and > count
      */
+    @Test
     public void testGetLineTop() {
         assertTrue(mDefaultLayout.getLineTop(0) >= 0);
         assertTrue(mDefaultLayout.getLineTop(1) > mDefaultLayout.getLineTop(0));
+    }
 
-        try {
-            mDefaultLayout.getLineTop(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineTopBeforeFirst() {
+        mDefaultLayout.getLineTop(-1);
+    }
 
-        try {
-            mDefaultLayout.getLineTop(LARGER_THAN_LINE_COUNT );
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineTopAfterLast() {
+        mDefaultLayout.getLineTop(LARGER_THAN_LINE_COUNT );
     }
 
     /**
@@ -269,41 +277,40 @@
      * This method just like getLineTop, descent means the bottom pixel of the line
      * Test 4 values containing -1, 0, normal number and > count
      */
+    @Test
     public void testGetLineDescent() {
         assertTrue(mDefaultLayout.getLineDescent(0) > 0);
         assertTrue(mDefaultLayout.getLineDescent(1) > 0);
+    }
 
-        try {
-            mDefaultLayout.getLineDescent(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineDescentBeforeFirst() {
+        mDefaultLayout.getLineDescent(-1);
+    }
 
-        try {
-            mDefaultLayout.getLineDescent(LARGER_THAN_LINE_COUNT );
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineDescentAfterLast() {
+        mDefaultLayout.getLineDescent(LARGER_THAN_LINE_COUNT );
     }
 
     /**
      * Returns the primary directionality of the paragraph containing the specified line.
      * By default, each line should be same
      */
+    @Test
     public void testGetParagraphDirection() {
         assertEquals(mDefaultLayout.getParagraphDirection(0),
                 mDefaultLayout.getParagraphDirection(1));
-        try {
-            mDefaultLayout.getParagraphDirection(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    }
 
-        try {
-            mDefaultLayout.getParagraphDirection(LARGER_THAN_LINE_COUNT);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetParagraphDirectionBeforeFirst() {
+        mDefaultLayout.getParagraphDirection(-1);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetParagraphDirectionAfterLast() {
+        mDefaultLayout.getParagraphDirection(LARGER_THAN_LINE_COUNT );
     }
 
     /**
@@ -312,41 +319,39 @@
      * Test 4 values containing -1, 0, normal number and > count
      * Each line's offset must >= 0
      */
+    @Test
     public void testGetLineStart() {
         assertTrue(mDefaultLayout.getLineStart(0) >= 0);
         assertTrue(mDefaultLayout.getLineStart(1) >= 0);
+    }
 
-        try {
-            mDefaultLayout.getLineStart(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineStartBeforeFirst() {
+        mDefaultLayout.getLineStart(-1);
+    }
 
-        try {
-            mDefaultLayout.getLineStart(LARGER_THAN_LINE_COUNT);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetLineStartAfterLast() {
+        mDefaultLayout.getLineStart(LARGER_THAN_LINE_COUNT );
     }
 
     /*
      * Returns whether the specified line contains one or more tabs.
      */
+    @Test
     public void testGetContainsTab() {
         assertTrue(mDefaultLayout.getLineContainsTab(0));
         assertFalse(mDefaultLayout.getLineContainsTab(1));
+    }
 
-        try {
-            mDefaultLayout.getLineContainsTab(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetContainsTabBeforeFirst() {
+        mDefaultLayout.getLineContainsTab(-1);
+    }
 
-        try {
-            mDefaultLayout.getLineContainsTab(LARGER_THAN_LINE_COUNT );
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetContainsTabAfterLast() {
+        mDefaultLayout.getLineContainsTab(LARGER_THAN_LINE_COUNT );
     }
 
     /**
@@ -356,27 +361,27 @@
      * We can not check the return value, for Directions's field is package private
      * So only check it not null
      */
-    public void testGetLineDirections() {
+    @Test
+    public void testGetLineDirections(){
         assertNotNull(mDefaultLayout.getLineDirections(0));
         assertNotNull(mDefaultLayout.getLineDirections(1));
+    }
 
-        try {
-            mDefaultLayout.getLineDirections(-1);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected = ArrayIndexOutOfBoundsException.class)
+    public void testGetLineDirectionsBeforeFirst() {
+        mDefaultLayout.getLineDirections(-1);
+    }
 
-        try {
-            mDefaultLayout.getLineDirections(LARGER_THAN_LINE_COUNT);
-            fail("should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-        }
+    @Test(expected = ArrayIndexOutOfBoundsException.class)
+    public void testGetLineDirectionsAfterLast() {
+        mDefaultLayout.getLineDirections(LARGER_THAN_LINE_COUNT);
     }
 
     /**
      * Returns the (negative) number of extra pixels of ascent padding
      * in the top line of the Layout.
      */
+    @Test
     public void testGetTopPadding() {
         assertTrue(mDefaultLayout.getTopPadding() < 0);
     }
@@ -384,6 +389,7 @@
     /**
      * Returns the number of extra pixels of descent padding in the bottom line of the Layout.
      */
+    @Test
     public void testGetBottomPadding() {
         assertTrue(mDefaultLayout.getBottomPadding() > 0);
     }
@@ -392,6 +398,7 @@
      * Returns the number of characters to be ellipsized away, or 0 if no ellipsis is to take place.
      * So each line must >= 0
      */
+    @Test
     public void testGetEllipsisCount() {
         // Multilines (6 lines) and TruncateAt.START so no ellipsis at all
         mDefaultLayout = createEllipsizeStaticLayout(LAYOUT_TEXT,
@@ -459,6 +466,7 @@
      * relative to the start of the line.
      * (So 0 if the beginning of the line is ellipsized, not getLineStart().)
      */
+    @Test
     public void testGetEllipsisStart() {
         mDefaultLayout = createEllipsizeStaticLayout();
         assertTrue(mDefaultLayout.getEllipsisStart(0) >= 0);
@@ -484,6 +492,7 @@
      * ellipsizedWidth if argument is not null
      * outerWidth if argument is null
      */
+    @Test
     public void testGetEllipsizedWidth() {
         int ellipsizedWidth = 60;
         int outerWidth = 100;
@@ -498,6 +507,7 @@
         assertEquals(outerWidth, layout.getEllipsizedWidth());
     }
 
+    @Test
     public void testEllipsis_singleLine() {
         {
             // Single line case and TruncateAt.END so that we have some ellipsis
@@ -523,37 +533,75 @@
                     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);
+            // 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);
+            }
         }
+
         {
-            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));
+            // 2 family emojis (11 code units + 11 code units).
+            final String text = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66"
+                    + "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66";
+            final float textWidth = mDefaultPaint.measureText(text);
+
+            final TextUtils.TruncateAt[] kinds = {TextUtils.TruncateAt.START,
+                    TextUtils.TruncateAt.MIDDLE, TextUtils.TruncateAt.END};
+            for (final TextUtils.TruncateAt kind : kinds) {
+                for (int i = 0; i <= 8; i++) {
+                    int avail = (int)(textWidth * i / 7.0f);
+                    StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint,
+                            avail, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+                            SPACE_MULTI, SPACE_ADD, false, kind, avail, 1);
+
+                    assertTrue(layout.getEllipsisCount(0) == text.length()
+                                    || layout.getEllipsisCount(0) == text.length() / 2
+                                    || layout.getEllipsisCount(0) == 0);
+                }
+            }
         }
     }
 
@@ -563,6 +611,7 @@
      * 2. change the text
      * 3. Check the text won't change to the StaticLayout
     */
+    @Test
     public void testImmutableStaticLayout() {
         Editable editable =  Editable.Factory.getInstance().newEditable("123\t\n555");
         StaticLayout layout = new StaticLayout(editable, mDefaultPaint,
@@ -609,9 +658,9 @@
     };
 
     private List<CharSequence> buildTestCharSequences(String testString, Normalizer.Form[] forms) {
-        List<CharSequence> result = new ArrayList<CharSequence>();
+        List<CharSequence> result = new ArrayList<>();
 
-        List<String> normalizedStrings = new ArrayList<String>();
+        List<String> normalizedStrings = new ArrayList<>();
         for (Normalizer.Form form: forms) {
             normalizedStrings.add(Normalizer.normalize(testString, form));
         }
@@ -650,6 +699,7 @@
                 ", Normalization: " + normalized;
     }
 
+    @Test
     public void testGetOffset_ASCII() {
         String testStrings[] = { "abcde", "ab\ncd", "ab\tcd", "ab\n\nc", "ab\n\tc" };
 
@@ -701,6 +751,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE() {
         String testStrings[] = new String[] {
               // Cyrillic alphabets.
@@ -733,6 +784,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_Normalization() {
         // "A" with acute, circumflex, tilde, diaeresis, ring above.
         String testString = "\u00C1\u00C2\u00C3\u00C4\u00C5";
@@ -791,6 +843,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_SurrogatePairs() {
         // Emoticons for surrogate pairs tests.
         String testString =
@@ -827,6 +880,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_Thai() {
         // Thai Characters. The expected cursorable boundary is
         // | \u0E02 | \u0E2D | \u0E1A | \u0E04\u0E38 | \u0E13 |
@@ -855,6 +909,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_Hebrew() {
         String testString = "\u05DE\u05E1\u05E2\u05D3\u05D4"; // Hebrew Characters
         for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) {
@@ -880,6 +935,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_Arabic() {
         // Arabic Characters. The expected cursorable boundary is
         // | \u0623 \u064F | \u0633 \u0652 | \u0631 \u064E | \u0629 \u064C |";
@@ -914,6 +970,7 @@
         }
     }
 
+    @Test
     public void testGetOffset_UNICODE_Bidi() {
         // String having RTL characters and LTR characters
 
@@ -1000,6 +1057,7 @@
         state.mSelectionStart = state.mSelectionEnd = newOffset;
     }
 
+    @Test
     public void testGetOffset_Emoji() {
         EditorState state = new EditorState();
 
@@ -1124,6 +1182,7 @@
         state.assertEquals("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8");
     }
 
+    @Test
     public void testGetOffsetForHorizontal_Multilines() {
         // Emoticons for surrogate pairs tests.
         String testString = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03\uD83D\uDE04";
@@ -1145,6 +1204,7 @@
         assertEquals(testString.length(), layout.getOffsetForHorizontal(lineCount - 1, width * 2));
     }
 
+    @Test
     public void testIsRtlCharAt() {
         {
             String testString = "ab(\u0623\u0624)c\u0625";
@@ -1177,21 +1237,23 @@
         }
     }
 
+    @Test
     public void testGetHorizontal() {
         String testString = "abc\u0623\u0624\u0625def";
         StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
                 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
 
-        assertEquals(layout.getPrimaryHorizontal(0), layout.getSecondaryHorizontal(0));
+        assertEquals(layout.getPrimaryHorizontal(0), layout.getSecondaryHorizontal(0), 0.0f);
         assertTrue(layout.getPrimaryHorizontal(0) < layout.getPrimaryHorizontal(3));
         assertTrue(layout.getPrimaryHorizontal(3) < layout.getSecondaryHorizontal(3));
         assertTrue(layout.getPrimaryHorizontal(4) < layout.getSecondaryHorizontal(3));
-        assertEquals(layout.getPrimaryHorizontal(4), layout.getSecondaryHorizontal(4));
-        assertEquals(layout.getPrimaryHorizontal(3), layout.getSecondaryHorizontal(6));
-        assertEquals(layout.getPrimaryHorizontal(6), layout.getSecondaryHorizontal(3));
-        assertEquals(layout.getPrimaryHorizontal(7), layout.getSecondaryHorizontal(7));
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getSecondaryHorizontal(4), 0.0f);
+        assertEquals(layout.getPrimaryHorizontal(3), layout.getSecondaryHorizontal(6), 0.0f);
+        assertEquals(layout.getPrimaryHorizontal(6), layout.getSecondaryHorizontal(3), 0.0f);
+        assertEquals(layout.getPrimaryHorizontal(7), layout.getSecondaryHorizontal(7), 0.0f);
     }
 
+    @Test
     public void testVeryLargeString() {
         final int MAX_COUNT = 1 << 21;
         final int WORD_SIZE = 32;
@@ -1206,7 +1268,8 @@
         assertNotNull(layout);
     }
 
-    public void testDoesntCrashWhenWordStyleOverlap() {
+    @Test
+    public void testNoCrashWhenWordStyleOverlap() {
        // test case where word boundary overlaps multiple style spans
        SpannableStringBuilder text = new SpannableStringBuilder("word boundaries, overlap style");
        // span covers "boundaries"
@@ -1221,4 +1284,25 @@
                .build();
        assertNotNull(layout);
     }
+
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void testGetPrimary_shouldFail_whenOffsetIsOutOfBounds_withSpannable() {
+        final String text = "1\n2\n3";
+        final SpannableString spannable = new SpannableString(text);
+        spannable.setSpan(new Object(), 0, text.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
+        final Layout layout = StaticLayout.Builder.obtain(spannable, 0, spannable.length(),
+                mDefaultPaint, Integer.MAX_VALUE - 1).setMaxLines(2)
+                .setEllipsize(TruncateAt.END).build();
+        layout.getPrimaryHorizontal(layout.getText().length());
+    }
+
+    @Test(expected = IndexOutOfBoundsException.class)
+    public void testGetPrimary_shouldFail_whenOffsetIsOutOfBounds_withString() {
+        final String text = "1\n2\n3";
+        final Layout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+                mDefaultPaint, Integer.MAX_VALUE - 1).setMaxLines(2)
+                .setEllipsize(TruncateAt.END).build();
+        layout.getPrimaryHorizontal(layout.getText().length());
+    }
+
 }
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..4d634fb 100644
--- a/tests/tests/text/src/android/text/cts/TextUtilsTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
@@ -16,19 +16,32 @@
 
 package android.text.cts;
 
-
 import static android.view.View.LAYOUT_DIRECTION_LTR;
 import static android.view.View.LAYOUT_DIRECTION_RTL;
 
+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.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+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;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.GetChars;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
@@ -41,24 +54,32 @@
 import android.text.style.ReplacementSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.URLSpan;
-import android.util.Log;
 import android.util.StringBuilderPrinter;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
 /**
  * Test {@link TextUtils}.
  */
-public class TextUtilsTest extends AndroidTestCase {
-    private static String mEllipsis;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextUtilsTest  {
+    private Context mContext;
+    private String mEllipsis;
     private int mStart;
     private int mEnd;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mEllipsis = getEllipsis();
         resetRange();
     }
@@ -72,7 +93,7 @@
      * Get the ellipsis from system.
      * @return the string of ellipsis.
      */
-    private String getEllipsis() {
+    private static String getEllipsis() {
         String text = "xxxxx";
         TextPaint p = new TextPaint();
         float width = p.measureText(text.substring(1));
@@ -80,6 +101,110 @@
         return re.substring(0, re.indexOf("x"));
     }
 
+    /**
+     * @return the number of times the code unit appears in the CharSequence.
+     */
+    private static 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;
+    }
+
+    @Test
+    public void testListEllipsize() {
+        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(mContext, null, separator, paint, fullWidth, moreId));
+
+        final List<CharSequence> emptyList = new ArrayList<>();
+        assertEquals("",
+            TextUtils.listEllipsize(mContext, 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(mContext, fullList, separator, paint, 1.0f, moreId));
+
+        // Test that the full string itself can get returned if there's enough space.
+        assertEquals(fullString,
+                TextUtils.listEllipsize(mContext, fullList, separator, paint, fullWidth, moreId)
+                        .toString());
+        assertEquals(fullString,
+                TextUtils.listEllipsize(mContext, 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(
+                    mContext, 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);
+            }
+        }
+}
+
+    @Test
+    public void testListEllipsize_rtl() {
+        final Resources res = mContext.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(mContext, fullList, separator, paint, enoughWidth,
+                                            moreId).toString());
+        } finally {
+            // Restore the original locales
+            newConfig.setLocales(previousLocales);
+            res.updateConfiguration(newConfig, null);
+        }
+    }
+
+    @Test
     public void testCommaEllipsize() {
         TextPaint p = new TextPaint();
         String text = "long, string, to, truncate";
@@ -132,6 +257,7 @@
         }
     }
 
+    @Test
     public void testConcat() {
         // issue 1695243
         // the javadoc for concat() doesn't describe the expected result when parameter is empty.
@@ -168,15 +294,14 @@
         // issue 1695243, the javadoc for concat() doesn't describe
         // the expected result when parameters are null.
         assertEquals(null, TextUtils.concat((CharSequence) null));
-
-        try {
-            TextUtils.concat((CharSequence[]) null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConcatNullArray() {
+        TextUtils.concat((CharSequence[]) null);
+    }
+
+    @Test
     public void testCopySpansFrom() {
         Object[] spans;
         String text = "content";
@@ -319,6 +444,7 @@
         }
     }
 
+    @Test
     public void testEllipsize() {
         TextPaint p = new TextPaint();
 
@@ -371,6 +497,30 @@
         }
     }
 
+    @Test
+    public void testEllipsize_emoji() {
+        // 2 family emojis (11 code units + 11 code units).
+        final String text = "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66"
+                + "\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66";
+
+        final TextPaint p = new TextPaint();
+        final float width = p.measureText(text);
+
+        final TextUtils.TruncateAt[] kinds = {TextUtils.TruncateAt.START,
+                TextUtils.TruncateAt.MIDDLE, TextUtils.TruncateAt.END};
+        for (final TextUtils.TruncateAt kind : kinds) {
+            for (int i = 0; i <= 8; i++) {
+                float avail = width * i / 7.0f;
+                final String out = TextUtils.ellipsize(text, p, avail, kind).toString();
+                assertTrue("kind: " + kind + ", avail: " + avail + ", out length: " + out.length(),
+                        out.length() == text.length()
+                                || out.length() == text.length() / 2 + 1
+                                || out.length() == 0);
+            }
+        }
+    }
+
+    @Test
     public void testEllipsizeCallback() {
         TextPaint p = new TextPaint();
 
@@ -506,7 +656,7 @@
      * @param len - int length of string.
      * @return a blank string which is filled up by '\uFEFF'.
      */
-    private String getBlankString(boolean isNeedStart, int len) {
+    private static String getBlankString(boolean isNeedStart, int len) {
         StringBuilder buf = new StringBuilder();
 
         int i = 0;
@@ -521,6 +671,7 @@
         return buf.toString();
     }
 
+    @Test
     public void testEquals() {
         // compare with itself.
         // String is a subclass of CharSequence and overrides equals().
@@ -560,6 +711,7 @@
         assertFalse(TextUtils.equals(null, string));
     }
 
+    @Test
     public void testExpandTemplate() {
         // ^1 at the start of template string.
         assertEquals("value1 template to be expanded",
@@ -610,66 +762,55 @@
         } catch (IllegalArgumentException e) {
             // expect
         }
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testExpandTemplateCaret0WithValue() {
         // template string is ^0
-        try {
-            TextUtils.expandTemplate("template ^0 to be expanded", "value1");
-        } catch (IllegalArgumentException e) {
-            // issue 1695243, doesn't discuss the case that ^0 in template string.
-        }
+        TextUtils.expandTemplate("template ^0 to be expanded", "value1");
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testExpandTemplateCaret0NoValues() {
         // template string is ^0
-        try {
-            TextUtils.expandTemplate("template ^0 to be expanded");
-        } catch (IllegalArgumentException e) {
-            // issue 1695243, doesn't discuss the case that ^0 in template string.
-        }
+        TextUtils.expandTemplate("template ^0 to be expanded");
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testExpandTemplateNotEnoughValues() {
         // the template requests 2 values but only 1 is provided
-        try {
-            TextUtils.expandTemplate("template ^2 to be expanded", "value1");
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            // expect
-        }
+        TextUtils.expandTemplate("template ^2 to be expanded", "value1");
+    }
 
+    @Test(expected=NullPointerException.class)
+    public void testExpandTemplateNullValues() {
         // values is null
-        try {
-            TextUtils.expandTemplate("template ^2 to be expanded", (CharSequence[]) null);
-        } catch (NullPointerException e) {
-            // expected
-        }
+        TextUtils.expandTemplate("template ^2 to be expanded", (CharSequence[]) null);
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testExpandTemplateNotEnoughValuesAndFirstIsNull() {
         // the template requests 2 values but only one null value is provided
-        try {
-            TextUtils.expandTemplate("template ^2 to be expanded", (CharSequence) null);
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            // expect
-        }
+        TextUtils.expandTemplate("template ^2 to be expanded", (CharSequence) null);
+    }
 
+    @Test(expected=NullPointerException.class)
+    public void testExpandTemplateAllValuesAreNull() {
         // the template requests 2 values and 2 values is provided, but all values are null.
-        try {
-            TextUtils.expandTemplate("template ^2 to be expanded",
-                    (CharSequence) null, (CharSequence) null);
-        } catch (NullPointerException e) {
-            // expected
-        }
+        TextUtils.expandTemplate("template ^2 to be expanded",
+                (CharSequence) null, (CharSequence) null);
+    }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testExpandTemplateNoValues() {
         // the template requests 2 values but no value is provided.
-        try {
-            TextUtils.expandTemplate("template ^2 to be expanded");
-            fail("Should throw IllegalArgumentException!");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
+        TextUtils.expandTemplate("template ^2 to be expanded");
+    }
 
+    @Test(expected=NullPointerException.class)
+    public void testExpandTemplateNullTemplate() {
         // template is null
-        try {
-            TextUtils.expandTemplate(null, "value1");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        TextUtils.expandTemplate(null, "value1");
     }
 
     /**
@@ -678,7 +819,7 @@
      * @return The char sequence array with the specified length.
      * The value of each item is "value[index+1]"
      */
-    private CharSequence[] createCharSequenceArray(int len) {
+    private static CharSequence[] createCharSequenceArray(int len) {
         CharSequence array[] = new CharSequence[len];
 
         for (int i = 0; i < len; i++) {
@@ -688,6 +829,7 @@
         return array;
     }
 
+    @Test
     public void testGetChars() {
         char[] destOriginal = "destination".toCharArray();
         char[] destResult = destOriginal.clone();
@@ -887,10 +1029,6 @@
     private class MockCharSequence implements CharSequence {
         private char mText[];
 
-        public MockCharSequence() {
-            this("");
-        }
-
         public MockCharSequence(String text) {
             mText = text.toCharArray();
         }
@@ -911,6 +1049,7 @@
         }
     }
 
+    @Test
     public void testGetOffsetAfter() {
         // the first '\uD800' is index 9, the second 'uD800' is index 16
         // the '\uDBFF' is index 26
@@ -932,7 +1071,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 +1097,7 @@
         }
     }
 
-    /**
-     * 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;
-        }
-    }
-
+    @Test
     public void testGetOffsetBefore() {
         // the first '\uDC00' is index 10, the second 'uDC00' is index 17
         // the '\uDFFF' is index 27
@@ -993,7 +1119,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));
@@ -1018,6 +1145,7 @@
         }
     }
 
+    @Test
     public void testGetReverse() {
         String source = "string to be reversed";
         assertEquals("gnirts", TextUtils.getReverse(source, 0, "string".length()).toString());
@@ -1072,6 +1200,7 @@
         }
     }
 
+    @Test
     public void testGetTrimmedLength() {
         assertEquals("normalstring".length(), TextUtils.getTrimmedLength("normalstring"));
         assertEquals("normal string".length(), TextUtils.getTrimmedLength("normal string"));
@@ -1079,33 +1208,31 @@
         assertEquals("blank after".length(), TextUtils.getTrimmedLength("blank after   \n    "));
         assertEquals("blank both".length(), TextUtils.getTrimmedLength(" \t   blank both  \n "));
 
-        char[] allTrimmedChars = new char[] {
+        char[] allTrimmedChars = new char[]{
                 '\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
                 '\u0008', '\u0009', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015',
                 '\u0016', '\u0017', '\u0018', '\u0019', '\u0020'
         };
         assertEquals(0, TextUtils.getTrimmedLength(String.valueOf(allTrimmedChars)));
-
-        try {
-            TextUtils.getTrimmedLength(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGetTrimmedLengthNull() {
+        TextUtils.getTrimmedLength(null);
+    }
+
+    @Test
     public void testHtmlEncode() {
         assertEquals("&lt;_html_&gt;\\ &amp;&quot;&#39;string&#39;&quot;",
                 TextUtils.htmlEncode("<_html_>\\ &\"'string'\""));
-
-         try {
-             TextUtils.htmlEncode(null);
-             fail("Should throw NullPointerException!");
-         } catch (NullPointerException e) {
-             // expected
-         }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testHtmlEncodeNull() {
+         TextUtils.htmlEncode(null);
+    }
+
+    @Test
     public void testIndexOf1() {
         String searchString = "string to be searched";
         final int INDEX_OF_FIRST_R = 2;     // first occurrence of 'r'
@@ -1132,6 +1259,7 @@
         assertEquals(INDEX_OF_FIRST_R, TextUtils.indexOf(mockCharSequence, 'r'));
     }
 
+    @Test
     public void testIndexOf2() {
         String searchString = "string to be searched";
         final int INDEX_OF_FIRST_R = 2;
@@ -1166,6 +1294,7 @@
                 INDEX_OF_FIRST_R + 1));
     }
 
+    @Test
     public void testIndexOf3() {
         String searchString = "string to be searched";
         final int INDEX_OF_FIRST_R = 2;
@@ -1211,6 +1340,7 @@
                 INDEX_OF_FIRST_R + 1, searchString.length()));
     }
 
+    @Test
     public void testIndexOf4() {
         String searchString = "string to be searched by string";
         final int SEARCH_INDEX = 13;
@@ -1234,6 +1364,7 @@
         assertEquals(SEARCH_INDEX, TextUtils.indexOf(mockCharSequence, "search"));
     }
 
+    @Test
     public void testIndexOf5() {
         String searchString = "string to be searched by string";
         final int INDEX_OF_FIRST_STRING = 0;
@@ -1278,6 +1409,7 @@
                 INDEX_OF_FIRST_STRING + 1));
     }
 
+    @Test
     public void testIndexOf6() {
         String searchString = "string to be searched by string";
         final int INDEX_OF_FIRST_STRING = 0;
@@ -1329,6 +1461,7 @@
                 INDEX_OF_FIRST_STRING + 1, searchString.length()));
     }
 
+    @Test
     public void testIsDigitsOnly() {
         assertTrue(TextUtils.isDigitsOnly(""));
         assertFalse(TextUtils.isDigitsOnly("no digit"));
@@ -1343,15 +1476,14 @@
 
         assertFalse(TextUtils.isDigitsOnly("\uD801")); // lonely lead surrogate
         assertFalse(TextUtils.isDigitsOnly("\uDCA0")); // lonely trailing surrogate
-
-        try {
-            TextUtils.isDigitsOnly(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed result if the CharSequence is null.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testIsDigitsOnlyNull() {
+        TextUtils.isDigitsOnly(null);
+    }
+
+    @Test
     public void testIsEmpty() {
         assertFalse(TextUtils.isEmpty("not empty"));
         assertFalse(TextUtils.isEmpty("    "));
@@ -1359,6 +1491,7 @@
         assertTrue(TextUtils.isEmpty(null));
     }
 
+    @Test
     public void testIsGraphicChar() {
         assertTrue(TextUtils.isGraphic('a'));
         assertTrue(TextUtils.isGraphic('\uBA00'));
@@ -1380,15 +1513,14 @@
 
         // SPACE_SEPARATOR
         assertFalse(TextUtils.isGraphic('\u0020'));
-
-        try {
-            assertFalse(TextUtils.isGraphic((Character) null));
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testIsGraphicCharNull() {
+        assertFalse(TextUtils.isGraphic((Character) null));
+    }
+
+    @Test
     public void testIsGraphicCharSequence() {
         assertTrue(TextUtils.isGraphic("printable characters"));
 
@@ -1400,18 +1532,16 @@
         assertFalse(TextUtils.isGraphic("\uDB40\uDC01")); // U+E0000 (unassigned)
         assertFalse(TextUtils.isGraphic("\uDB3D")); // unpaired high surrogate
         assertFalse(TextUtils.isGraphic("\uDC0C")); // unpaired low surrogate
-
-        try {
-            TextUtils.isGraphic(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
-    @SuppressWarnings("unchecked")
-    public void testJoin1() {
-        ArrayList<CharSequence> charTokens = new ArrayList<CharSequence>();
+    @Test(expected=NullPointerException.class)
+    public void testIsGraphicCharSequenceNull() {
+        TextUtils.isGraphic(null);
+    }
+
+    @Test
+    public void testJoinIterable() {
+        ArrayList<CharSequence> charTokens = new ArrayList<>();
         charTokens.add("string1");
         charTokens.add("string2");
         charTokens.add("string3");
@@ -1421,12 +1551,6 @@
 
         // issue 1695243, not clear what is supposed result if the delimiter or tokens are null.
         assertEquals("string1nullstring2nullstring3", TextUtils.join(null, charTokens));
-        try {
-            TextUtils.join("|", (Iterable) null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
 
         ArrayList<SpannableString> spannableStringTokens = new ArrayList<SpannableString>();
         spannableStringTokens.add(new SpannableString("span 1"));
@@ -1435,7 +1559,13 @@
         assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
     }
 
-    public void testJoin2() {
+    @Test(expected=NullPointerException.class)
+    public void testJoinIterableNull() {
+        TextUtils.join("|", (Iterable) null);
+    }
+
+    @Test
+    public void testJoinArray() {
         CharSequence[] charTokens = new CharSequence[] { "string1", "string2", "string3" };
         assertEquals("string1|string2|string3", TextUtils.join("|", charTokens));
         assertEquals("string1; string2; string3", TextUtils.join("; ", charTokens));
@@ -1443,12 +1573,6 @@
 
         // issue 1695243, not clear what is supposed result if the delimiter or tokens are null.
         assertEquals("string1nullstring2nullstring3", TextUtils.join(null, charTokens));
-        try {
-            TextUtils.join("|", (Object[]) null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
 
         SpannableString[] spannableStringTokens = new SpannableString[] {
                 new SpannableString("span 1"),
@@ -1457,6 +1581,12 @@
         assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testJoinArrayNull() {
+        TextUtils.join("|", (Object[]) null);
+    }
+
+    @Test
     public void testLastIndexOf1() {
         String searchString = "string to be searched";
         final int INDEX_OF_LAST_R = 16;
@@ -1482,6 +1612,7 @@
         assertEquals(INDEX_OF_LAST_R, TextUtils.lastIndexOf(mockCharSequence, 'r'));
     }
 
+    @Test
     public void testLastIndexOf2() {
         String searchString = "string to be searched";
         final int INDEX_OF_FIRST_R = 2;
@@ -1516,6 +1647,7 @@
                 TextUtils.lastIndexOf(mockCharSequence, 'r', INDEX_OF_FIRST_R));
     }
 
+    @Test
     public void testLastIndexOf3() {
         String searchString = "string to be searched";
         final int INDEX_OF_FIRST_R = 2;
@@ -1556,6 +1688,7 @@
                 INDEX_OF_SECOND_R - 1));
     }
 
+    @Test
     public void testRegionMatches() {
         assertFalse(TextUtils.regionMatches("one", 0, "two", 0, "one".length()));
         assertTrue(TextUtils.regionMatches("one", 0, "one", 0, "one".length()));
@@ -1626,6 +1759,7 @@
         }
     }
 
+    @Test
     public void testReplace() {
         String template = "this is a string to be as the template for replacement";
 
@@ -1676,6 +1810,7 @@
         }
     }
 
+    @Test
     public void testSplitPattern() {
         String testString = "abccbadecdebz";
         assertEquals(calculateCharsCount(testString, "c") + 1,
@@ -1694,25 +1829,22 @@
         // issue 1695243, not clear what is supposed result if the pattern string is empty.
         assertEquals(testString.length() + 2,
                 TextUtils.split(testString, Pattern.compile("")).length);
+    }
 
-        try {
-            TextUtils.split(null, Pattern.compile("a"));
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-        try {
+    @Test(expected=NullPointerException.class)
+    public void testSplitPatternNullText() {
+        TextUtils.split(null, Pattern.compile("a"));
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testSplitPatternNullPattern() {
             TextUtils.split("abccbadecdebz", (Pattern) null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
     }
 
     /*
      * return the appearance count of searched chars in text.
      */
-    private int calculateCharsCount(CharSequence text, CharSequence searches) {
+    private static int calculateCharsCount(CharSequence text, CharSequence searches) {
         int count = 0;
         int start = TextUtils.indexOf(text, searches, 0);
 
@@ -1723,6 +1855,7 @@
         return count;
     }
 
+    @Test
     public void testSplitString() {
         String testString = "abccbadecdebz";
         assertEquals(calculateCharsCount(testString, "c") + 1,
@@ -1737,21 +1870,19 @@
         // issue 1695243, not clear what is supposed result if the pattern string is empty.
         assertEquals(testString.length() + 2,
                 TextUtils.split("abccbadecdebz", "").length);
-
-        try {
-            TextUtils.split(null, "a");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-        try {
-            TextUtils.split("abccbadecdebz", (String) null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testSplitStringNullText() {
+        TextUtils.split(null, "a");
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testSplitStringNullPattern() {
+        TextUtils.split("abccbadecdebz", (String) null);
+    }
+
+    @Test
     public void testStringOrSpannedString() {
         assertNull(TextUtils.stringOrSpannedString(null));
 
@@ -1771,6 +1902,7 @@
                 TextUtils.stringOrSpannedString(stringBuffer).getClass());
     }
 
+    @Test
     public void testSubString() {
         String string = "String";
         assertSame(string, TextUtils.substring(string, 0, string.length()));
@@ -1828,6 +1960,7 @@
         assertTrue(mockGetChars.hasCalledGetChars());
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcelable.Creator<CharSequence> creator = TextUtils.CHAR_SEQUENCE_CREATOR;
         String string = "String";
@@ -1915,6 +2048,7 @@
         }
     }
 
+    @Test
     public void testGetCapsMode() {
         final int CAP_MODE_ALL = TextUtils.CAP_MODE_CHARACTERS
                 | TextUtils.CAP_MODE_WORDS | TextUtils.CAP_MODE_SENTENCES;
@@ -1999,6 +2133,7 @@
                 TextUtils.getCapsMode(testString, offset, CAP_MODE_ALL));
     }
 
+    @Test
     public void testGetCapsModeException() {
         String testString = "Start. Sentence word!No space before\n\t" +
                 "Paragraph? (\"\'skip begin\'\"). skip end";
@@ -2025,6 +2160,7 @@
         }
     }
 
+    @Test
     public void testDumpSpans() {
         StringBuilder builder = new StringBuilder();
         StringBuilderPrinter printer = new StringBuilderPrinter(builder);
@@ -2044,6 +2180,7 @@
         assertTrue(builder.length() > 0);
     }
 
+    @Test
     public void testGetLayoutDirectionFromLocale() {
         assertEquals(LAYOUT_DIRECTION_LTR,
                 TextUtils.getLayoutDirectionFromLocale(null));
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..7993f58 100644
--- a/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtils_SimpleStringSplitterTest.java
@@ -16,15 +16,28 @@
 
 package android.text.cts;
 
-import java.util.Iterator;
+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.junit.Assert.fail;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils.SimpleStringSplitter;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Iterator;
+
 /**
  * Test {@link SimpleStringSplitter}.
  */
-public class TextUtils_SimpleStringSplitterTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextUtils_SimpleStringSplitterTest {
+    @Test
     public void testConstructor() {
         new SimpleStringSplitter('|');
 
@@ -33,6 +46,7 @@
         new SimpleStringSplitter(Character.MIN_VALUE);
     }
 
+    @Test
     public void testHasNext() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter('|');
         assertFalse(simpleStringSplitter.hasNext());
@@ -50,6 +64,7 @@
         assertFalse(simpleStringSplitter.hasNext());
     }
 
+    @Test
     public void testIterator() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter('|');
 
@@ -67,6 +82,7 @@
         assertFalse(iterator.hasNext());
     }
 
+    @Test
     public void testNext1() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter(',');
 
@@ -80,6 +96,7 @@
         }
     }
 
+    @Test
     public void testNext2() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter(',');
 
@@ -96,6 +113,7 @@
         assertEquals("", simpleStringSplitter.next());
     }
 
+    @Test
     public void testRemove() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter(',');
 
@@ -106,6 +124,7 @@
         }
     }
 
+    @Test
     public void testSetString() {
         SimpleStringSplitter simpleStringSplitter = new SimpleStringSplitter(',');
 
diff --git a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
index f72111b..4529f2a 100644
--- a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
@@ -16,20 +16,33 @@
 
 package android.text.format.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.junit.Assert.fail;
 
-import android.content.ContentResolver;
+import android.app.UiAutomation;
 import android.content.Context;
-import android.cts.util.SystemUtil;
 import android.os.ParcelFileDescriptor;
 import android.provider.Settings;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateFormat;
 
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.io.FileInputStream;
-import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
@@ -38,13 +51,12 @@
 import java.util.Scanner;
 import java.util.TimeZone;
 
-public class DateFormatTest extends InstrumentationTestCase {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class DateFormatTest {
     private static final String TIME_FORMAT_12 = "12";
     private static final String TIME_FORMAT_24 = "24";
 
-    private Context mContext;
-    private ContentResolver mContentResolver;
-
     // Date: 2008-12-18 05:30
     private static final int YEAR_FROM_1900 = 108;
     private static final int YEAR = 2008;
@@ -53,36 +65,48 @@
     private static final int HOUR = 5;
     private static final int MINUTE = 30;
 
+    private Context mContext;
+
     private boolean mIs24HourFormat;
     private Locale mDefaultLocale;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        enableAppOps();
-        mContext = getInstrumentation().getContext();
-        mContentResolver = mContext.getContentResolver();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mIs24HourFormat = DateFormat.is24HourFormat(mContext);
         mDefaultLocale = Locale.getDefault();
+
+        enableAppOps();
+    }
+
+    @After
+    public void teardown() throws Exception {
+        if (!mIs24HourFormat) {
+            setTimeFormat(TIME_FORMAT_12);
+        }
+        if ((mDefaultLocale != null) && !Locale.getDefault().equals(mDefaultLocale)) {
+            Locale.setDefault(mDefaultLocale);
+        }
     }
 
     private void enableAppOps() {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
         StringBuilder cmd = new StringBuilder();
         cmd.append("appops set ");
-        cmd.append(getInstrumentation().getContext().getPackageName());
+        cmd.append(mContext.getPackageName());
         cmd.append(" android:write_settings allow");
-        getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
+        uiAutomation.executeShellCommand(cmd.toString());
 
         StringBuilder query = new StringBuilder();
         query.append("appops get ");
-        query.append(getInstrumentation().getContext().getPackageName());
+        query.append(mContext.getPackageName());
         query.append(" android:write_settings");
         String queryStr = query.toString();
 
         String result = "No operations.";
         while (result.contains("No operations")) {
-            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
-                                        queryStr);
+            ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(queryStr);
             InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
             result = convertStreamToString(inputStream);
         }
@@ -94,18 +118,7 @@
         }
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        if (!mIs24HourFormat) {
-            setTimeFormat(TIME_FORMAT_12);
-        }
-        if (!Locale.getDefault().equals(mDefaultLocale)) {
-            Locale.setDefault(mDefaultLocale);
-        }
-
-        super.tearDown();
-    }
-
+    @Test
     public void test_is24HourFormat() throws Exception {
         setTimeFormat(TIME_FORMAT_24);
         assertTrue(DateFormat.is24HourFormat(mContext));
@@ -113,6 +126,7 @@
         assertFalse(DateFormat.is24HourFormat(mContext));
     }
 
+    @Test
     public void test_format_M() {
         Calendar c = new GregorianCalendar(2008, Calendar.DECEMBER, 18);
         assertEquals("D", DateFormat.format("MMMMM", c));
@@ -122,6 +136,7 @@
         assertEquals("12", DateFormat.format("M", c));
     }
 
+    @Test
     public void test_format_L() {
         // TODO: we can't test other locales with this API so we can't test 'L' properly!
         Calendar c = new GregorianCalendar(2008, Calendar.DECEMBER, 18);
@@ -132,6 +147,7 @@
         assertEquals("12", DateFormat.format("L", c));
     }
 
+    @Test
     public void test_format_E() {
         Calendar c = new GregorianCalendar(2008, Calendar.DECEMBER, 18);
         assertEquals("T", DateFormat.format("EEEEE", c));
@@ -141,6 +157,7 @@
         assertEquals("Thu", DateFormat.format("E", c));
     }
 
+    @Test
     public void test_format_c() {
         // TODO: we can't test other locales with this API, so we can't test 'c' properly!
         Calendar c = new GregorianCalendar(2008, Calendar.DECEMBER, 18);
@@ -152,6 +169,7 @@
     }
 
     @SuppressWarnings("deprecation")
+    @Test
     public void testFormatMethods() throws ParseException {
         if (!mDefaultLocale.equals(Locale.US)) {
             Locale.setDefault(Locale.US);
@@ -192,6 +210,7 @@
         assertEquals(expectedString, actual.toString());
     }
 
+    @Test
     public void test2038() {
         Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT+00:00"));
 
@@ -235,6 +254,7 @@
         assertEquals(expected, sdf.format(c.getTime()));
     }
 
+    @Test
     public void test_bug_8359981() {
         checkFormat("24", "k", 00);
         checkFormat( "0", "K", 00);
@@ -262,6 +282,7 @@
         checkFormat( "0", "H", 24);
     }
 
+    @Test
     public void test_bug_82144() {
         for (Locale locale : Locale.getAvailableLocales()) {
             Locale.setDefault(locale);
@@ -291,7 +312,7 @@
     }
 
     private void setTimeFormat(String timeFormat) throws IOException {
-        SystemUtil.runShellCommand(getInstrumentation(), "settings put system "
-                + Settings.System.TIME_12_24 + " " + timeFormat);
+        SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                "settings put system " + Settings.System.TIME_12_24 + " " + timeFormat);
     }
 }
diff --git a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
index a05ba7a..735f6a0 100644
--- a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
@@ -16,30 +16,41 @@
 
 package android.text.format.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 android.content.Context;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.text.DateFormat;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.Formatter;
 import java.util.Locale;
 import java.util.TimeZone;
 
-public class DateUtilsTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DateUtilsTest {
     private long mBaseTime;
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
         mBaseTime = System.currentTimeMillis();
     }
 
+    @Test
     public void testGetDayOfWeekString() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -60,6 +71,7 @@
                 DateUtils.getDayOfWeekString(Calendar.SUNDAY, 60));
     }
 
+    @Test
     public void testGetMonthString() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -76,6 +88,7 @@
         assertEquals("Jan", DateUtils.getMonthString(Calendar.JANUARY, 60));
     }
 
+    @Test
     public void testGetAMPMString() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -87,6 +100,7 @@
     // This is to test the mapping between DateUtils' public API and
     // libcore/icu4c's implementation. More tests, in different locales, are
     // in libcore's CTS tests.
+    @Test
     public void test_getRelativeTimeSpanString() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -116,12 +130,14 @@
     // test the mapping between DateUtils's public API and libcore/icu4c's
     // implementation. More tests, in different locales, are in libcore's
     // CTS tests.
+    @Test
     public void test_getRelativeDateTimeString() {
         final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
         assertNotNull(DateUtils.getRelativeDateTimeString(mContext, mBaseTime - DAY_DURATION,
                 DateUtils.MINUTE_IN_MILLIS, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_NUMERIC_DATE));
     }
 
+    @Test
     public void test_formatElapsedTime() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -129,19 +145,20 @@
 
         long MINUTES = 60;
         long HOURS = 60 * MINUTES;
-        test_formatElapsedTime("02:01", 2 * MINUTES + 1);
-        test_formatElapsedTime("3:02:01", 3 * HOURS + 2 * MINUTES + 1);
+        verifyFormatElapsedTime("02:01", 2 * MINUTES + 1);
+        verifyFormatElapsedTime("3:02:01", 3 * HOURS + 2 * MINUTES + 1);
         // http://code.google.com/p/android/issues/detail?id=41401
-        test_formatElapsedTime("123:02:01", 123 * HOURS + 2 * MINUTES + 1);
+        verifyFormatElapsedTime("123:02:01", 123 * HOURS + 2 * MINUTES + 1);
     }
 
-    private void test_formatElapsedTime(String expected, long elapsedTime) {
+    private void verifyFormatElapsedTime(String expected, long elapsedTime) {
         assertEquals(expected, DateUtils.formatElapsedTime(elapsedTime));
         StringBuilder sb = new StringBuilder();
         assertEquals(expected, DateUtils.formatElapsedTime(sb, elapsedTime));
         assertEquals(expected, sb.toString());
     }
 
+    @Test
     public void testFormatSameDayTime() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -154,7 +171,6 @@
 
         int currentYear = Calendar.getInstance().get(Calendar.YEAR);
         Date dateWithCurrentYear = new Date(currentYear - 1900, 0, 19, 3, 30, 15);
-        long timeWithCurrentYear = dateWithCurrentYear.getTime();
 
         final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
         assertEquals("Saturday, January 24, 2009", DateUtils.formatSameDayTime(
@@ -184,6 +200,7 @@
 
     // This is just to exercise the wrapper that calls the libcore/icu4c implementation.
     // Full testing, in multiple locales, is in libcore's CTS tests.
+    @Test
     public void testFormatDateRange() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
@@ -196,12 +213,14 @@
                 fixedTime + HOUR_DURATION, DateUtils.FORMAT_SHOW_WEEKDAY));
     }
 
+    @Test
     public void testIsToday() {
         final long ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
         assertTrue(DateUtils.isToday(mBaseTime));
         assertFalse(DateUtils.isToday(mBaseTime - ONE_DAY_IN_MS));
     }
 
+    @Test
     public void test_bug_7548161() {
         if (!LocaleUtils.isCurrentLocale(mContext, Locale.US)) {
             return;
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..fa11023 100644
--- a/tests/tests/text/src/android/text/format/cts/FormatterTest.java
+++ b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
@@ -16,47 +16,59 @@
 
 package android.text.format.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.format.Formatter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.math.BigDecimal;
 import java.math.MathContext;
 
-import android.test.AndroidTestCase;
-import android.text.format.Formatter;
-
-public class FormatterTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FormatterTest {
+    @Test
     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);
+        Context context = InstrumentationRegistry.getTargetContext();
 
         // test different long values with various length
-        assertEquals("0 B", Formatter.formatFileSize(mContext, 0));
-        assertEquals("1 B", Formatter.formatFileSize(mContext, 1));
-        assertEquals("9 B", Formatter.formatFileSize(mContext, 9));
-        assertEquals("10 B", Formatter.formatFileSize(mContext, 10));
-        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 B", Formatter.formatFileSize(context, 0));
+        assertEquals("1 B", Formatter.formatFileSize(context, 1));
+        assertEquals("9 B", Formatter.formatFileSize(context, 9));
+        assertEquals("10 B", Formatter.formatFileSize(context, 10));
+        assertEquals("99 B", Formatter.formatFileSize(context, 99));
+        assertEquals("100 B", Formatter.formatFileSize(context, 100));
+        assertEquals("900 B", Formatter.formatFileSize(context, 900));
+        assertEquals("0.90 kB", Formatter.formatFileSize(context, 901));
 
-        assertEquals("1.00 KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
+        assertEquals("1.00 kB", Formatter.formatFileSize(context, bd.pow(1).longValue()));
 
-        assertEquals("1.00 MB", Formatter.formatFileSize(mContext, bd.pow(2).longValue()));
+        assertEquals("1.00 MB", Formatter.formatFileSize(context, bd.pow(2).longValue()));
 
-        assertEquals("1.00 GB", Formatter.formatFileSize(mContext, bd.pow(3).longValue()));
+        assertEquals("1.00 GB", Formatter.formatFileSize(context, bd.pow(3).longValue()));
 
-        assertEquals("1.00 TB", Formatter.formatFileSize(mContext, bd.pow(4).longValue()));
+        assertEquals("1.00 TB", Formatter.formatFileSize(context, bd.pow(4).longValue()));
 
-        assertEquals("1.00 PB", Formatter.formatFileSize(mContext, bd.pow(5).longValue()));
+        assertEquals("1.00 PB", Formatter.formatFileSize(context, bd.pow(5).longValue()));
 
-        assertEquals("1024 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
+        assertEquals("1000 PB", Formatter.formatFileSize(context, bd.pow(6).longValue()));
 
         // test Negative value
-        assertEquals("-1 B", Formatter.formatFileSize(mContext, -1));
+        assertEquals("-1 B", Formatter.formatFileSize(context, -1));
     }
 
+    @Test
     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/format/cts/TimeTest.java b/tests/tests/text/src/android/text/format/cts/TimeTest.java
index cc73272..7c44c77 100644
--- a/tests/tests/text/src/android/text/format/cts/TimeTest.java
+++ b/tests/tests/text/src/android/text/format/cts/TimeTest.java
@@ -16,13 +16,24 @@
 
 package android.text.format.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 android.content.res.Configuration;
 import android.content.res.Resources;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.Time;
 import android.util.Log;
 import android.util.TimeFormatException;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -31,36 +42,37 @@
 import java.util.Objects;
 import java.util.TimeZone;
 
-public class TimeTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimeTest {
     private static final String TAG = "TimeTest";
+    private static List<Locale> sSystemLocales;
 
     private Locale originalLocale;
 
-    private static List<Locale> sSystemLocales;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         originalLocale = Locale.getDefault();
 
         maybeInitializeSystemLocales();
     }
 
-    @Override
-    public void tearDown() throws Exception {
+    @After
+    public void teardown() {
         // The Locale may be changed by tests. Revert to the original.
         changeJavaAndAndroidLocale(originalLocale, true /* force */);
-        super.tearDown();
     }
 
+    @Test
     public void testConstructor() {
         Time time = new Time();
         new Time(Time.getCurrentTimezone());
         time.set(System.currentTimeMillis());
         Time anotherTime = new Time(time);
-        assertTime(time, anotherTime);
+        verifyTime(time, anotherTime);
     }
 
+    @Test
     public void testNormalize() {
         final int expectedMonth = 3;
         final int expectedDate = 1;
@@ -86,6 +98,7 @@
         assertEquals(expectedDate, time.monthDay);
     }
 
+    @Test
     public void testSwitchTimezone() {
         String timeZone = "US/Pacific";
         String anotherTimeZone = "Asia/Chongqing";
@@ -95,6 +108,7 @@
         assertEquals(anotherTimeZone, time.timezone);
     }
 
+    @Test
     public void testSet() {
         final int year = 2008;
         final int month = 5;
@@ -107,10 +121,10 @@
 
         Time anotherTime = new Time();
         anotherTime.set(time);
-        assertTime(time, anotherTime);
+        verifyTime(time, anotherTime);
     }
 
-    private void assertTime(Time time, Time anotherTime) {
+    private void verifyTime(Time time, Time anotherTime) {
         assertEquals(time.timezone, anotherTime.timezone);
         assertEquals(time.allDay, anotherTime.allDay);
         assertEquals(time.second, anotherTime.second);
@@ -125,6 +139,7 @@
         assertEquals(time.gmtoff, anotherTime.gmtoff);
     }
 
+    @Test
     public void testGetWeekNumber() {
         Time time = new Time();
         time.normalize(false);
@@ -151,24 +166,22 @@
         }
     }
 
+    @Test(expected=NullPointerException.class)
     public void testParseNull() {
         Time t = new Time();
-        try {
-            t.parse(null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
+        t.parse(null);
+    }
 
-        try {
-            t.parse3339(null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testParse3339Null() {
+        Time t = new Time();
+        t.parse3339(null);
     }
 
     // http://code.google.com/p/android/issues/detail?id=16002
     // We'd leak one JNI global reference each time parsing failed.
     // This would cause a crash when we filled the global reference table.
+    @Test
     public void testBug16002() {
         Time t = new Time();
         for (int i = 0; i < 8192; ++i) {
@@ -183,6 +196,7 @@
     // http://code.google.com/p/android/issues/detail?id=22225
     // We'd leak one JNI global reference each time parsing failed.
     // This would cause a crash when we filled the global reference table.
+    @Test
     public void testBug22225() {
         Time t = new Time();
         for (int i = 0; i < 8192; ++i) {
@@ -194,6 +208,7 @@
         }
     }
 
+    @Test
     public void testIsEpoch() {
         Time time = new Time();
         assertTrue(Time.isEpoch(time));
@@ -202,6 +217,7 @@
         assertFalse(Time.isEpoch(time));
     }
 
+    @Test
     public void testAfterBefore() {
         Time a = new Time(Time.TIMEZONE_UTC);
         Time b = new Time("America/Los_Angeles");
@@ -347,7 +363,8 @@
             new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0),
     };
 
-    public void testNormalize1() throws Exception {
+    @Test
+    public void testNormalize1() {
         String tz = "America/Los_Angeles";
         Time local = new Time(tz);
 
@@ -363,7 +380,7 @@
             Time expected = new Time(tz);
             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
                     test.minute2, 0);
-            Fields.assertTimeEquals("day test index " + index + ", normalize():",
+            Fields.verifyTimeEquals("day test index " + index + ", normalize():",
                     Fields.MAIN_DATE_TIME, expected, local);
 
             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
@@ -376,7 +393,7 @@
             expected = new Time(tz);
             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
                     test.minute2, 0);
-            Fields.assertTimeEquals("day test index " + index + ", toMillis():",
+            Fields.verifyTimeEquals("day test index " + index + ", toMillis():",
                     Fields.MAIN_DATE_TIME, expected, local);
         }
 
@@ -395,7 +412,7 @@
             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
                     test.minute2, 0);
             Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2));
-            Fields.assertTimeEquals("minute test index " + index + ", normalize():",
+            Fields.verifyTimeEquals("minute test index " + index + ", normalize():",
                     Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local);
 
             local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
@@ -411,12 +428,13 @@
             Fields.setDateTime(expected, test.year2, test.month2, test.day2, test.hour2,
                     test.minute2, 0);
             Fields.setDst(expected, test.dst2 /* isDst */, PstPdt.getUtcOffsetSeconds(test.dst2));
-            Fields.assertTimeEquals("minute test index " + index + ", toMillis():",
+            Fields.verifyTimeEquals("minute test index " + index + ", toMillis():",
                     Fields.MAIN_DATE_TIME | Fields.DST_FIELDS, expected, local);
         }
     }
 
-    public void testSwitchTimezone_simpleUtc() throws Exception {
+    @Test
+    public void testSwitchTimezone_simpleUtc() {
         String originalTz = Time.TIMEZONE_UTC;
         Time t = new Time(originalTz);
         Fields.set(t, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
@@ -426,16 +444,17 @@
 
         Time expected1 = new Time(newTz);
         Fields.set(expected1, 2006, 9, 5, 5, 0, 0, 1 /* isDst */, -25200, 277, 4);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
 
         t.switchTimezone(originalTz);
 
         Time expected2 = new Time(originalTz);
         Fields.set(expected2, 2006, 9, 5, 12, 0, 0, 0 /* isDst */, 0, 277, 4);
-        Fields.assertTimeEquals(expected2, t);
+        Fields.verifyTimeEquals(expected2, t);
     }
 
-    public void testSwitchTimezone_standardToStandardTime() throws Exception {
+    @Test
+    public void testSwitchTimezone_standardToStandardTime() {
         String zone1 = "Europe/London";
         String zone2 = "America/Los_Angeles";
 
@@ -447,16 +466,17 @@
 
         Time expected1 = new Time(zone2);
         Fields.set(expected1, 2007, 2, 10, 4, 0, 0, 0 /* isDst */, -28800, 68, 6);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
 
         t.switchTimezone(zone1);
 
         Time expected2 = new Time(zone1);
         Fields.set(expected2, 2007, 2, 10, 12, 0, 0, 0 /* isDst */, 0, 68, 6);
-        Fields.assertTimeEquals(expected2, t);
+        Fields.verifyTimeEquals(expected2, t);
     }
 
-    public void testSwitchTimezone_dstToDstTime() throws Exception {
+    @Test
+    public void testSwitchTimezone_dstToDstTime() {
         String zone1 = "Europe/London";
         String zone2 = "America/Los_Angeles";
 
@@ -468,16 +488,17 @@
 
         Time expected1 = new Time(zone2);
         Fields.set(expected1, 2007, 2, 26, 4, 0, 0, 1 /* isDst */, -25200, 84, 1);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
 
         t.switchTimezone(zone1);
 
         Time expected2 = new Time(zone1);
         Fields.set(expected2, 2007, 2, 26, 12, 0, 0, 1 /* isDst */, 3600, 84, 1);
-        Fields.assertTimeEquals(expected2, t);
+        Fields.verifyTimeEquals(expected2, t);
     }
 
-    public void testSwitchTimezone_standardToDstTime() throws Exception {
+    @Test
+    public void testSwitchTimezone_standardToDstTime() {
         String zone1 = "Europe/London";
         String zone2 = "America/Los_Angeles";
 
@@ -489,16 +510,17 @@
 
         Time expected1 = new Time(zone2);
         Fields.set(expected1, 2007, 2, 24, 5, 0, 0, 1 /* isDst */, -25200, 82, 6);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
 
         t.switchTimezone(zone1);
 
         Time expected2 = new Time(zone1);
         Fields.set(expected2, 2007, 2, 24, 12, 0, 0, 0 /* isDst */, 0, 82, 6);
-        Fields.assertTimeEquals(expected2, t);
+        Fields.verifyTimeEquals(expected2, t);
     }
 
-    public void testSwitchTimezone_sourceDateInvalid() throws Exception {
+    @Test
+    public void testSwitchTimezone_sourceDateInvalid() {
         String zone1 = "Europe/London";
         String zone2 = "America/Los_Angeles";
 
@@ -513,10 +535,11 @@
         // This illustrates why using -1 to indicate a problem, when -1 is in range, is a poor idea.
         Time expected1 = new Time(zone2);
         Fields.set(expected1, 1969, 11, 31, 15, 59, 59, 0 /* isDst */, -28800, 364, 3);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
     }
 
-    public void testSwitchTimezone_dstToStandardTime() throws Exception {
+    @Test
+    public void testSwitchTimezone_dstToStandardTime() {
         String zone1 = "America/Los_Angeles";
         String zone2 = "Europe/London";
 
@@ -528,26 +551,28 @@
 
         Time expected1 = new Time(zone2);
         Fields.set(expected1, 2007, 2, 12, 19, 0, 0, 0 /* isDst */, 0, 70, 1);
-        Fields.assertTimeEquals(expected1, t);
+        Fields.verifyTimeEquals(expected1, t);
 
         t.switchTimezone(zone1);
 
         Time expected2 = new Time(zone1);
         Fields.set(expected2, 2007, 2, 12, 12, 0, 0, 1 /* isDst */, -25200, 70, 1);
-        Fields.assertTimeEquals(expected2, t);
+        Fields.verifyTimeEquals(expected2, t);
     }
 
-    public void testCtor() throws Exception {
+    @Test
+    public void testCtor() {
         String tz = Time.TIMEZONE_UTC;
         Time t = new Time(tz);
         assertEquals(tz, t.timezone);
 
         Time expected = new Time(tz);
         Fields.set(expected, 1970, 0, 1, 0, 0, 0, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testGetActualMaximum() throws Exception {
+    @Test
+    public void testGetActualMaximum() {
         Time t = new Time(Time.TIMEZONE_UTC);
         assertEquals(59, t.getActualMaximum(Time.SECOND));
         assertEquals(59, t.getActualMaximum(Time.MINUTE));
@@ -576,21 +601,22 @@
         final int[] DAYS_PER_MONTH = {
                 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
         };
-        assertMonth(t, DAYS_PER_MONTH);
+        verifyMonth(t, DAYS_PER_MONTH);
 
         t.year = 2000;
         DAYS_PER_MONTH[1] = 29;
-        assertMonth(t, DAYS_PER_MONTH);
+        verifyMonth(t, DAYS_PER_MONTH);
     }
 
-    private void assertMonth(Time t, final int[] DAYS_PER_MONTH) {
+    private void verifyMonth(Time t, final int[] DAYS_PER_MONTH) {
         for (int i = 0; i < t.getActualMaximum(Time.MONTH); i++) {
             t.month = i;
             assertEquals(DAYS_PER_MONTH[i], t.getActualMaximum(Time.MONTH_DAY));
         }
     }
 
-    public void testClear0() throws Exception {
+    @Test
+    public void testClear0() {
         Time t = new Time(Time.getCurrentTimezone());
         t.clear(Time.TIMEZONE_UTC);
         assertEquals(Time.TIMEZONE_UTC, t.timezone);
@@ -607,7 +633,8 @@
         assertEquals(-1, t.isDst);
     }
 
-    public void testClear() throws Exception {
+    @Test
+    public void testClear() {
         Time t = new Time("America/Los_Angeles");
         Fields.set(t, 1, 2, 3, 4, 5, 6, 7 /* isDst */, 8, 9, 10);
 
@@ -615,10 +642,11 @@
 
         Time expected = new Time(Time.TIMEZONE_UTC);
         Fields.set(expected, 0, 0, 0, 0, 0, 0, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testCompare() throws Exception {
+    @Test
+    public void testCompare() {
         String timezone = "America/New_York";
         int[] aDateTimeFields = new int[] { 2005, 2, 3, 4, 5, 6 };
 
@@ -684,32 +712,25 @@
         assertEquals(0, Time.compare(b, a));
     }
 
-    public void testCompareNullFailure() throws Exception {
+    @Test(expected=NullPointerException.class)
+    public void testCompareNullSecond() {
         Time a = new Time(Time.TIMEZONE_UTC);
-
-        try {
-            Time.compare(a, null);
-            fail("Should throw NullPointerException on second argument");
-        } catch (NullPointerException e) {
-            // pass
-        }
-
-        try {
-            Time.compare(null, a);
-            fail("Should throw NullPointerException on first argument");
-        } catch (NullPointerException e) {
-            // pass
-        }
-
-        try {
-            Time.compare(null, null);
-            fail("Should throw NullPointerException because both args are null");
-        } catch (NullPointerException e) {
-            // pass
-        }
+        Time.compare(a, null);
     }
 
-    public void testCompare_invalidDatesAreEqualIfTimezoneDiffers() throws Exception {
+    @Test(expected=NullPointerException.class)
+    public void testCompareNullFirst() {
+        Time a = new Time(Time.TIMEZONE_UTC);
+        Time.compare(null, a);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testCompareNullBoth() {
+        Time.compare(null, null);
+    }
+
+    @Test
+    public void testCompare_invalidDatesAreEqualIfTimezoneDiffers() {
         String timezone = "America/New_York";
         // This date is outside of the valid set of dates that can be calculated so toMillis()
         // returns -1.
@@ -741,40 +762,45 @@
         assertEquals(0, Time.compare(a, b));
     }
 
-    public void testFormat() throws Exception {
+    @Test
+    public void testFormat() {
         Time t = new Time(Time.TIMEZONE_UTC);
         String r = t.format("%Y%m%dT%H%M%S");
         assertEquals("19700101T000000", r);
     }
 
+    @Test
     public void testFormat_null() {
         Time t = new Time(Time.TIMEZONE_UTC);
         assertEquals(t.format("%c"), t.format(null));
     }
 
-    public void testFormat_badPatterns() throws Exception {
+    @Test
+    public void testFormat_badPatterns() {
         Time t = new Time(Time.TIMEZONE_UTC);
-        assertFormatEquals(t, "%~Y", "~Y");
-        assertFormatEquals(t, "%", "%");
+        verifyFormatEquals(t, "%~Y", "~Y");
+        verifyFormatEquals(t, "%", "%");
     }
 
-    public void testFormat_doesNotNormalize() throws Exception {
+    @Test
+    public void testFormat_doesNotNormalize() {
         Time t = new Time(Time.TIMEZONE_UTC);
         Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2);
 
         Time tCopy = new Time(t);
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
 
-        assertFormatEquals(t, "%Y%m%dT%H%M%S", "20051432T-1-1-1");
+        verifyFormatEquals(t, "%Y%m%dT%H%M%S", "20051432T-1-1-1");
 
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
     }
 
-    private static void assertFormatEquals(Time t, String formatArg, String expected) {
+    private static void verifyFormatEquals(Time t, String formatArg, String expected) {
         assertEquals(expected, t.format(formatArg));
     }
 
-    public void testFormat_tokensUkLocale() throws Exception {
+    @Test
+    public void testFormat_tokensUkLocale() {
         if (!changeJavaAndAndroidLocale(Locale.UK, false /* force */)) {
             Log.w(TAG, "Skipping testFormat_tokensUkLocale: no assets found");
             return;
@@ -784,92 +810,93 @@
         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
 
         // Prove the un-normalized fields are used.
-        assertFormatEquals(t, "%A", "Sunday");
+        verifyFormatEquals(t, "%A", "Sunday");
 
         // Set fields like weekday.
         t.normalize(true);
 
-        assertFormatEquals(t, "%A", "Wednesday");
-        assertFormatEquals(t, "%a", "Wed");
-        assertFormatEquals(t, "%B", "June");
-        assertFormatEquals(t, "%b", "Jun");
-        assertFormatEquals(t, "%C", "20");
-        assertFormatEquals(t, "%c", "1 Jun 2005, 12:30:15");
-        assertFormatEquals(t, "%D", "06/01/05");
-        assertFormatEquals(t, "%d", "01");
-        assertFormatEquals(t, "%E", "E");
-        assertFormatEquals(t, "%e", " 1");
-        assertFormatEquals(t, "%F", "2005-06-01");
-        assertFormatEquals(t, "%G", "2005");
-        assertFormatEquals(t, "%g", "05");
-        assertFormatEquals(t, "%H", "12");
-        assertFormatEquals(t, "%h", "Jun");
-        assertFormatEquals(t, "%I", "12");
-        assertFormatEquals(t, "%j", "152");
-        assertFormatEquals(t, "%K", "K");
-        assertFormatEquals(t, "%k", "12");
-        assertFormatEquals(t, "%l", "12");
-        assertFormatEquals(t, "%M", "30");
-        assertFormatEquals(t, "%m", "06");
-        assertFormatEquals(t, "%n", "\n");
-        assertFormatEquals(t, "%O", "O");
-        assertFormatEquals(t, "%p", "pm");
-        assertFormatEquals(t, "%P", "pm");
-        assertFormatEquals(t, "%R", "12:30");
-        assertFormatEquals(t, "%r", "12:30:15 pm");
-        assertFormatEquals(t, "%S", "15");
+        verifyFormatEquals(t, "%A", "Wednesday");
+        verifyFormatEquals(t, "%a", "Wed");
+        verifyFormatEquals(t, "%B", "June");
+        verifyFormatEquals(t, "%b", "Jun");
+        verifyFormatEquals(t, "%C", "20");
+        verifyFormatEquals(t, "%c", "1 Jun 2005, 12:30:15");
+        verifyFormatEquals(t, "%D", "06/01/05");
+        verifyFormatEquals(t, "%d", "01");
+        verifyFormatEquals(t, "%E", "E");
+        verifyFormatEquals(t, "%e", " 1");
+        verifyFormatEquals(t, "%F", "2005-06-01");
+        verifyFormatEquals(t, "%G", "2005");
+        verifyFormatEquals(t, "%g", "05");
+        verifyFormatEquals(t, "%H", "12");
+        verifyFormatEquals(t, "%h", "Jun");
+        verifyFormatEquals(t, "%I", "12");
+        verifyFormatEquals(t, "%j", "152");
+        verifyFormatEquals(t, "%K", "K");
+        verifyFormatEquals(t, "%k", "12");
+        verifyFormatEquals(t, "%l", "12");
+        verifyFormatEquals(t, "%M", "30");
+        verifyFormatEquals(t, "%m", "06");
+        verifyFormatEquals(t, "%n", "\n");
+        verifyFormatEquals(t, "%O", "O");
+        verifyFormatEquals(t, "%p", "pm");
+        verifyFormatEquals(t, "%P", "pm");
+        verifyFormatEquals(t, "%R", "12:30");
+        verifyFormatEquals(t, "%r", "12:30:15 pm");
+        verifyFormatEquals(t, "%S", "15");
         // The original C implementation uses the (native) system default TZ, not the timezone of
         // the Time to calculate this and was therefore not stable. This changed to use the Time's
         // timezone when the Time class was re-written in Java.
-        assertFormatEquals(t, "%s", "1117625415");
-        assertFormatEquals(t, "%T", "12:30:15");
-        assertFormatEquals(t, "%t", "\t");
-        assertFormatEquals(t, "%U", "22");
-        assertFormatEquals(t, "%u", "3");
-        assertFormatEquals(t, "%V", "22");
-        assertFormatEquals(t, "%v", " 1-Jun-2005");
-        assertFormatEquals(t, "%W", "22");
-        assertFormatEquals(t, "%w", "3");
-        assertFormatEquals(t, "%X", "12:30:15");
-        assertFormatEquals(t, "%x", "1 June 2005");
-        assertFormatEquals(t, "%y", "05");
-        assertFormatEquals(t, "%Y", "2005");
-        assertFormatEquals(t, "%Z", "BST");
-        assertFormatEquals(t, "%z", "+0100");
-        assertFormatEquals(t, "%+", "Wed Jun  1 12:30:15 BST 2005");
-        assertFormatEquals(t, "%%", "%");
+        verifyFormatEquals(t, "%s", "1117625415");
+        verifyFormatEquals(t, "%T", "12:30:15");
+        verifyFormatEquals(t, "%t", "\t");
+        verifyFormatEquals(t, "%U", "22");
+        verifyFormatEquals(t, "%u", "3");
+        verifyFormatEquals(t, "%V", "22");
+        verifyFormatEquals(t, "%v", " 1-Jun-2005");
+        verifyFormatEquals(t, "%W", "22");
+        verifyFormatEquals(t, "%w", "3");
+        verifyFormatEquals(t, "%X", "12:30:15");
+        verifyFormatEquals(t, "%x", "1 June 2005");
+        verifyFormatEquals(t, "%y", "05");
+        verifyFormatEquals(t, "%Y", "2005");
+        verifyFormatEquals(t, "%Z", "BST");
+        verifyFormatEquals(t, "%z", "+0100");
+        verifyFormatEquals(t, "%+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%%", "%");
 
         // Modifiers
 
-        assertFormatEquals(t, "%EC", "20");
-        assertFormatEquals(t, "%OC", "20");
+        verifyFormatEquals(t, "%EC", "20");
+        verifyFormatEquals(t, "%OC", "20");
 
-        assertFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 BST 2005");
-        assertFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 BST 2005");
-        assertFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 BST 2005");
-        assertFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 BST 2005");
-        assertFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 BST 2005");
+        verifyFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 BST 2005");
 
-        assertFormatEquals(t, "%_A", "Wednesday");
-        assertFormatEquals(t, "%-A", "Wednesday");
-        assertFormatEquals(t, "%0A", "Wednesday");
-        assertFormatEquals(t, "%^A", "WEDNESDAY");
-        assertFormatEquals(t, "%#A", "wEDNESDAY");
+        verifyFormatEquals(t, "%_A", "Wednesday");
+        verifyFormatEquals(t, "%-A", "Wednesday");
+        verifyFormatEquals(t, "%0A", "Wednesday");
+        verifyFormatEquals(t, "%^A", "WEDNESDAY");
+        verifyFormatEquals(t, "%#A", "wEDNESDAY");
 
-        assertFormatEquals(t, "%_Y", "20 5");
-        assertFormatEquals(t, "%-Y", "205");
-        assertFormatEquals(t, "%0Y", "2005");
-        assertFormatEquals(t, "%^Y", "2005");
-        assertFormatEquals(t, "%#Y", "2005");
+        verifyFormatEquals(t, "%_Y", "20 5");
+        verifyFormatEquals(t, "%-Y", "205");
+        verifyFormatEquals(t, "%0Y", "2005");
+        verifyFormatEquals(t, "%^Y", "2005");
+        verifyFormatEquals(t, "%#Y", "2005");
 
-        assertFormatEquals(t, "%_d", " 1");
-        assertFormatEquals(t, "%-d", "1");
-        assertFormatEquals(t, "%0d", "01");
-        assertFormatEquals(t, "%^d", "01");
-        assertFormatEquals(t, "%#d", "01");
+        verifyFormatEquals(t, "%_d", " 1");
+        verifyFormatEquals(t, "%-d", "1");
+        verifyFormatEquals(t, "%0d", "01");
+        verifyFormatEquals(t, "%^d", "01");
+        verifyFormatEquals(t, "%#d", "01");
     }
 
-    public void testFormat_tokensUsLocale() throws Exception {
+    @Test
+    public void testFormat_tokensUsLocale() {
         if (!changeJavaAndAndroidLocale(Locale.US, false /* force */)) {
             Log.w(TAG, "Skipping testFormat_tokensUSLocale: no assets found");
             return;
@@ -879,92 +906,93 @@
         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
 
         // Prove the un-normalized fields are used.
-        assertFormatEquals(t, "%A", "Sunday");
+        verifyFormatEquals(t, "%A", "Sunday");
 
         // Set fields like weekday.
         t.normalize(true);
 
-        assertFormatEquals(t, "%A", "Wednesday");
-        assertFormatEquals(t, "%a", "Wed");
-        assertFormatEquals(t, "%B", "June");
-        assertFormatEquals(t, "%b", "Jun");
-        assertFormatEquals(t, "%C", "20");
-        assertFormatEquals(t, "%c", "Jun 1, 2005, 12:30:15 PM");
-        assertFormatEquals(t, "%D", "06/01/05");
-        assertFormatEquals(t, "%d", "01");
-        assertFormatEquals(t, "%E", "E");
-        assertFormatEquals(t, "%e", " 1");
-        assertFormatEquals(t, "%F", "2005-06-01");
-        assertFormatEquals(t, "%G", "2005");
-        assertFormatEquals(t, "%g", "05");
-        assertFormatEquals(t, "%H", "12");
-        assertFormatEquals(t, "%h", "Jun");
-        assertFormatEquals(t, "%I", "12");
-        assertFormatEquals(t, "%j", "152");
-        assertFormatEquals(t, "%K", "K");
-        assertFormatEquals(t, "%k", "12");
-        assertFormatEquals(t, "%l", "12");
-        assertFormatEquals(t, "%M", "30");
-        assertFormatEquals(t, "%m", "06");
-        assertFormatEquals(t, "%n", "\n");
-        assertFormatEquals(t, "%O", "O");
-        assertFormatEquals(t, "%p", "PM");
-        assertFormatEquals(t, "%P", "pm");
-        assertFormatEquals(t, "%R", "12:30");
-        assertFormatEquals(t, "%r", "12:30:15 PM");
-        assertFormatEquals(t, "%S", "15");
+        verifyFormatEquals(t, "%A", "Wednesday");
+        verifyFormatEquals(t, "%a", "Wed");
+        verifyFormatEquals(t, "%B", "June");
+        verifyFormatEquals(t, "%b", "Jun");
+        verifyFormatEquals(t, "%C", "20");
+        verifyFormatEquals(t, "%c", "Jun 1, 2005, 12:30:15 PM");
+        verifyFormatEquals(t, "%D", "06/01/05");
+        verifyFormatEquals(t, "%d", "01");
+        verifyFormatEquals(t, "%E", "E");
+        verifyFormatEquals(t, "%e", " 1");
+        verifyFormatEquals(t, "%F", "2005-06-01");
+        verifyFormatEquals(t, "%G", "2005");
+        verifyFormatEquals(t, "%g", "05");
+        verifyFormatEquals(t, "%H", "12");
+        verifyFormatEquals(t, "%h", "Jun");
+        verifyFormatEquals(t, "%I", "12");
+        verifyFormatEquals(t, "%j", "152");
+        verifyFormatEquals(t, "%K", "K");
+        verifyFormatEquals(t, "%k", "12");
+        verifyFormatEquals(t, "%l", "12");
+        verifyFormatEquals(t, "%M", "30");
+        verifyFormatEquals(t, "%m", "06");
+        verifyFormatEquals(t, "%n", "\n");
+        verifyFormatEquals(t, "%O", "O");
+        verifyFormatEquals(t, "%p", "PM");
+        verifyFormatEquals(t, "%P", "pm");
+        verifyFormatEquals(t, "%R", "12:30");
+        verifyFormatEquals(t, "%r", "12:30:15 PM");
+        verifyFormatEquals(t, "%S", "15");
         // The original C implementation uses the (native) system default TZ, not the timezone of
         // the Time to calculate this and was therefore not stable. This changed to use the Time's
         // timezone when the Time class was re-written in Java.
-        assertFormatEquals(t, "%s", "1117643415");
-        assertFormatEquals(t, "%T", "12:30:15");
-        assertFormatEquals(t, "%t", "\t");
-        assertFormatEquals(t, "%U", "22");
-        assertFormatEquals(t, "%u", "3");
-        assertFormatEquals(t, "%V", "22");
-        assertFormatEquals(t, "%v", " 1-Jun-2005");
-        assertFormatEquals(t, "%W", "22");
-        assertFormatEquals(t, "%w", "3");
-        assertFormatEquals(t, "%X", "12:30:15 PM");
-        assertFormatEquals(t, "%x", "June 1, 2005");
-        assertFormatEquals(t, "%y", "05");
-        assertFormatEquals(t, "%Y", "2005");
-        assertFormatEquals(t, "%Z", "EDT");
-        assertFormatEquals(t, "%z", "-0400");
-        assertFormatEquals(t, "%+", "Wed Jun  1 12:30:15 EDT 2005");
-        assertFormatEquals(t, "%%", "%");
+        verifyFormatEquals(t, "%s", "1117643415");
+        verifyFormatEquals(t, "%T", "12:30:15");
+        verifyFormatEquals(t, "%t", "\t");
+        verifyFormatEquals(t, "%U", "22");
+        verifyFormatEquals(t, "%u", "3");
+        verifyFormatEquals(t, "%V", "22");
+        verifyFormatEquals(t, "%v", " 1-Jun-2005");
+        verifyFormatEquals(t, "%W", "22");
+        verifyFormatEquals(t, "%w", "3");
+        verifyFormatEquals(t, "%X", "12:30:15 PM");
+        verifyFormatEquals(t, "%x", "June 1, 2005");
+        verifyFormatEquals(t, "%y", "05");
+        verifyFormatEquals(t, "%Y", "2005");
+        verifyFormatEquals(t, "%Z", "EDT");
+        verifyFormatEquals(t, "%z", "-0400");
+        verifyFormatEquals(t, "%+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%%", "%");
 
         // Modifiers
 
-        assertFormatEquals(t, "%EC", "20");
-        assertFormatEquals(t, "%OC", "20");
+        verifyFormatEquals(t, "%EC", "20");
+        verifyFormatEquals(t, "%OC", "20");
 
-        assertFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 EDT 2005");
-        assertFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 EDT 2005");
-        assertFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 EDT 2005");
-        assertFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 EDT 2005");
-        assertFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%_+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%-+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%0+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%^+", "Wed Jun  1 12:30:15 EDT 2005");
+        verifyFormatEquals(t, "%#+", "Wed Jun  1 12:30:15 EDT 2005");
 
-        assertFormatEquals(t, "%_A", "Wednesday");
-        assertFormatEquals(t, "%-A", "Wednesday");
-        assertFormatEquals(t, "%0A", "Wednesday");
-        assertFormatEquals(t, "%^A", "WEDNESDAY");
-        assertFormatEquals(t, "%#A", "wEDNESDAY");
+        verifyFormatEquals(t, "%_A", "Wednesday");
+        verifyFormatEquals(t, "%-A", "Wednesday");
+        verifyFormatEquals(t, "%0A", "Wednesday");
+        verifyFormatEquals(t, "%^A", "WEDNESDAY");
+        verifyFormatEquals(t, "%#A", "wEDNESDAY");
 
-        assertFormatEquals(t, "%_Y", "20 5");
-        assertFormatEquals(t, "%-Y", "205");
-        assertFormatEquals(t, "%0Y", "2005");
-        assertFormatEquals(t, "%^Y", "2005");
-        assertFormatEquals(t, "%#Y", "2005");
+        verifyFormatEquals(t, "%_Y", "20 5");
+        verifyFormatEquals(t, "%-Y", "205");
+        verifyFormatEquals(t, "%0Y", "2005");
+        verifyFormatEquals(t, "%^Y", "2005");
+        verifyFormatEquals(t, "%#Y", "2005");
 
-        assertFormatEquals(t, "%_d", " 1");
-        assertFormatEquals(t, "%-d", "1");
-        assertFormatEquals(t, "%0d", "01");
-        assertFormatEquals(t, "%^d", "01");
-        assertFormatEquals(t, "%#d", "01");
+        verifyFormatEquals(t, "%_d", " 1");
+        verifyFormatEquals(t, "%-d", "1");
+        verifyFormatEquals(t, "%0d", "01");
+        verifyFormatEquals(t, "%^d", "01");
+        verifyFormatEquals(t, "%#d", "01");
     }
 
-    public void testFormat_tokensFranceLocale() throws Exception {
+    @Test
+    public void testFormat_tokensFranceLocale() {
         if (!changeJavaAndAndroidLocale(Locale.FRANCE, false /* force */)) {
             Log.w(TAG, "Skipping testFormat_tokensFranceLocale: no assets found");
             return;
@@ -974,92 +1002,93 @@
         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
 
         // Prove the un-normalized fields are used.
-        assertFormatEquals(t, "%A", "dimanche");
+        verifyFormatEquals(t, "%A", "dimanche");
 
         // Set fields like weekday.
         t.normalize(true);
 
-        assertFormatEquals(t, "%A", "mercredi");
-        assertFormatEquals(t, "%a", "mer.");
-        assertFormatEquals(t, "%B", "juin");
-        assertFormatEquals(t, "%b", "juin");
-        assertFormatEquals(t, "%C", "20");
-        assertFormatEquals(t, "%c", "1 juin 2005 à 12:30:15");
-        assertFormatEquals(t, "%D", "06/01/05");
-        assertFormatEquals(t, "%d", "01");
-        assertFormatEquals(t, "%E", "E");
-        assertFormatEquals(t, "%e", " 1");
-        assertFormatEquals(t, "%F", "2005-06-01");
-        assertFormatEquals(t, "%G", "2005");
-        assertFormatEquals(t, "%g", "05");
-        assertFormatEquals(t, "%H", "12");
-        assertFormatEquals(t, "%h", "juin");
-        assertFormatEquals(t, "%I", "12");
-        assertFormatEquals(t, "%j", "152");
-        assertFormatEquals(t, "%K", "K");
-        assertFormatEquals(t, "%k", "12");
-        assertFormatEquals(t, "%l", "12");
-        assertFormatEquals(t, "%M", "30");
-        assertFormatEquals(t, "%m", "06");
-        assertFormatEquals(t, "%n", "\n");
-        assertFormatEquals(t, "%O", "O");
-        assertFormatEquals(t, "%p", "PM");
-        assertFormatEquals(t, "%P", "pm");
-        assertFormatEquals(t, "%R", "12:30");
-        assertFormatEquals(t, "%r", "12:30:15 PM");
-        assertFormatEquals(t, "%S", "15");
+        verifyFormatEquals(t, "%A", "mercredi");
+        verifyFormatEquals(t, "%a", "mer.");
+        verifyFormatEquals(t, "%B", "juin");
+        verifyFormatEquals(t, "%b", "juin");
+        verifyFormatEquals(t, "%C", "20");
+        verifyFormatEquals(t, "%c", "1 juin 2005 à 12:30:15");
+        verifyFormatEquals(t, "%D", "06/01/05");
+        verifyFormatEquals(t, "%d", "01");
+        verifyFormatEquals(t, "%E", "E");
+        verifyFormatEquals(t, "%e", " 1");
+        verifyFormatEquals(t, "%F", "2005-06-01");
+        verifyFormatEquals(t, "%G", "2005");
+        verifyFormatEquals(t, "%g", "05");
+        verifyFormatEquals(t, "%H", "12");
+        verifyFormatEquals(t, "%h", "juin");
+        verifyFormatEquals(t, "%I", "12");
+        verifyFormatEquals(t, "%j", "152");
+        verifyFormatEquals(t, "%K", "K");
+        verifyFormatEquals(t, "%k", "12");
+        verifyFormatEquals(t, "%l", "12");
+        verifyFormatEquals(t, "%M", "30");
+        verifyFormatEquals(t, "%m", "06");
+        verifyFormatEquals(t, "%n", "\n");
+        verifyFormatEquals(t, "%O", "O");
+        verifyFormatEquals(t, "%p", "PM");
+        verifyFormatEquals(t, "%P", "pm");
+        verifyFormatEquals(t, "%R", "12:30");
+        verifyFormatEquals(t, "%r", "12:30:15 PM");
+        verifyFormatEquals(t, "%S", "15");
         // The original C implementation uses the (native) system default TZ, not the timezone of
         // the Time to calculate this and was therefore not stable. This changed to use the Time's
         // timezone when the Time class was re-written in Java.
-        assertFormatEquals(t, "%s", "1117621815");
-        assertFormatEquals(t, "%T", "12:30:15");
-        assertFormatEquals(t, "%t", "\t");
-        assertFormatEquals(t, "%U", "22");
-        assertFormatEquals(t, "%u", "3");
-        assertFormatEquals(t, "%V", "22");
-        assertFormatEquals(t, "%v", " 1-juin-2005");
-        assertFormatEquals(t, "%W", "22");
-        assertFormatEquals(t, "%w", "3");
-        assertFormatEquals(t, "%X", "12:30:15");
-        assertFormatEquals(t, "%x", "1 juin 2005");
-        assertFormatEquals(t, "%y", "05");
-        assertFormatEquals(t, "%Y", "2005");
-        assertFormatEquals(t, "%Z", "GMT+02:00");
-        assertFormatEquals(t, "%z", "+0200");
-        assertFormatEquals(t, "%+", "mer. juin  1 12:30:15 GMT+02:00 2005");
-        assertFormatEquals(t, "%%", "%");
+        verifyFormatEquals(t, "%s", "1117621815");
+        verifyFormatEquals(t, "%T", "12:30:15");
+        verifyFormatEquals(t, "%t", "\t");
+        verifyFormatEquals(t, "%U", "22");
+        verifyFormatEquals(t, "%u", "3");
+        verifyFormatEquals(t, "%V", "22");
+        verifyFormatEquals(t, "%v", " 1-juin-2005");
+        verifyFormatEquals(t, "%W", "22");
+        verifyFormatEquals(t, "%w", "3");
+        verifyFormatEquals(t, "%X", "12:30:15");
+        verifyFormatEquals(t, "%x", "1 juin 2005");
+        verifyFormatEquals(t, "%y", "05");
+        verifyFormatEquals(t, "%Y", "2005");
+        verifyFormatEquals(t, "%Z", "GMT+02:00");
+        verifyFormatEquals(t, "%z", "+0200");
+        verifyFormatEquals(t, "%+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%%", "%");
 
         // Modifiers
 
-        assertFormatEquals(t, "%EC", "20");
-        assertFormatEquals(t, "%OC", "20");
+        verifyFormatEquals(t, "%EC", "20");
+        verifyFormatEquals(t, "%OC", "20");
 
-        assertFormatEquals(t, "%_+", "mer. juin  1 12:30:15 GMT+02:00 2005");
-        assertFormatEquals(t, "%-+", "mer. juin  1 12:30:15 GMT+02:00 2005");
-        assertFormatEquals(t, "%0+", "mer. juin  1 12:30:15 GMT+02:00 2005");
-        assertFormatEquals(t, "%^+", "mer. juin  1 12:30:15 GMT+02:00 2005");
-        assertFormatEquals(t, "%#+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%_+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%-+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%0+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%^+", "mer. juin  1 12:30:15 GMT+02:00 2005");
+        verifyFormatEquals(t, "%#+", "mer. juin  1 12:30:15 GMT+02:00 2005");
 
-        assertFormatEquals(t, "%_A", "mercredi");
-        assertFormatEquals(t, "%-A", "mercredi");
-        assertFormatEquals(t, "%0A", "mercredi");
-        assertFormatEquals(t, "%^A", "MERCREDI");
-        assertFormatEquals(t, "%#A", "MERCREDI");
+        verifyFormatEquals(t, "%_A", "mercredi");
+        verifyFormatEquals(t, "%-A", "mercredi");
+        verifyFormatEquals(t, "%0A", "mercredi");
+        verifyFormatEquals(t, "%^A", "MERCREDI");
+        verifyFormatEquals(t, "%#A", "MERCREDI");
 
-        assertFormatEquals(t, "%_Y", "20 5");
-        assertFormatEquals(t, "%-Y", "205");
-        assertFormatEquals(t, "%0Y", "2005");
-        assertFormatEquals(t, "%^Y", "2005");
-        assertFormatEquals(t, "%#Y", "2005");
+        verifyFormatEquals(t, "%_Y", "20 5");
+        verifyFormatEquals(t, "%-Y", "205");
+        verifyFormatEquals(t, "%0Y", "2005");
+        verifyFormatEquals(t, "%^Y", "2005");
+        verifyFormatEquals(t, "%#Y", "2005");
 
-        assertFormatEquals(t, "%_d", " 1");
-        assertFormatEquals(t, "%-d", "1");
-        assertFormatEquals(t, "%0d", "01");
-        assertFormatEquals(t, "%^d", "01");
-        assertFormatEquals(t, "%#d", "01");
+        verifyFormatEquals(t, "%_d", " 1");
+        verifyFormatEquals(t, "%-d", "1");
+        verifyFormatEquals(t, "%0d", "01");
+        verifyFormatEquals(t, "%^d", "01");
+        verifyFormatEquals(t, "%#d", "01");
     }
 
-    public void testFormat_tokensJapanLocale() throws Exception {
+    @Test
+    public void testFormat_tokensJapanLocale() {
         if (!changeJavaAndAndroidLocale(Locale.JAPAN, false /* force */)) {
             Log.w(TAG, "Skipping testFormat_tokensJapanLocale: no assets found");
             return;
@@ -1069,91 +1098,92 @@
         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
 
         // Prove the un-normalized fields are used.
-        assertFormatEquals(t, "%A", "日曜日");
+        verifyFormatEquals(t, "%A", "日曜日");
 
         // Set fields like weekday.
         t.normalize(true);
 
-        assertFormatEquals(t, "%A", "水曜日");
-        assertFormatEquals(t, "%a", "水");
-        assertFormatEquals(t, "%B", "6月");
-        assertFormatEquals(t, "%b", "6月");
-        assertFormatEquals(t, "%C", "20");
-        assertFormatEquals(t, "%c", "2005/06/01 12:30:15");
-        assertFormatEquals(t, "%D", "06/01/05");
-        assertFormatEquals(t, "%d", "01");
-        assertFormatEquals(t, "%E", "E");
-        assertFormatEquals(t, "%e", " 1");
-        assertFormatEquals(t, "%F", "2005-06-01");
-        assertFormatEquals(t, "%G", "2005");
-        assertFormatEquals(t, "%g", "05");
-        assertFormatEquals(t, "%H", "12");
-        assertFormatEquals(t, "%h", "6月");
-        assertFormatEquals(t, "%I", "12");
-        assertFormatEquals(t, "%j", "152");
-        assertFormatEquals(t, "%k", "12");
-        assertFormatEquals(t, "%l", "12");
-        assertFormatEquals(t, "%M", "30");
-        assertFormatEquals(t, "%m", "06");
-        assertFormatEquals(t, "%n", "\n");
-        assertFormatEquals(t, "%O", "O");
-        assertFormatEquals(t, "%p", "午後");
-        assertFormatEquals(t, "%P", "午後");
-        assertFormatEquals(t, "%R", "12:30");
-        assertFormatEquals(t, "%r", "12:30:15 午後");
-        assertFormatEquals(t, "%S", "15");
+        verifyFormatEquals(t, "%A", "水曜日");
+        verifyFormatEquals(t, "%a", "水");
+        verifyFormatEquals(t, "%B", "6月");
+        verifyFormatEquals(t, "%b", "6月");
+        verifyFormatEquals(t, "%C", "20");
+        verifyFormatEquals(t, "%c", "2005/06/01 12:30:15");
+        verifyFormatEquals(t, "%D", "06/01/05");
+        verifyFormatEquals(t, "%d", "01");
+        verifyFormatEquals(t, "%E", "E");
+        verifyFormatEquals(t, "%e", " 1");
+        verifyFormatEquals(t, "%F", "2005-06-01");
+        verifyFormatEquals(t, "%G", "2005");
+        verifyFormatEquals(t, "%g", "05");
+        verifyFormatEquals(t, "%H", "12");
+        verifyFormatEquals(t, "%h", "6月");
+        verifyFormatEquals(t, "%I", "12");
+        verifyFormatEquals(t, "%j", "152");
+        verifyFormatEquals(t, "%k", "12");
+        verifyFormatEquals(t, "%l", "12");
+        verifyFormatEquals(t, "%M", "30");
+        verifyFormatEquals(t, "%m", "06");
+        verifyFormatEquals(t, "%n", "\n");
+        verifyFormatEquals(t, "%O", "O");
+        verifyFormatEquals(t, "%p", "午後");
+        verifyFormatEquals(t, "%P", "午後");
+        verifyFormatEquals(t, "%R", "12:30");
+        verifyFormatEquals(t, "%r", "12:30:15 午後");
+        verifyFormatEquals(t, "%S", "15");
         // The original C implementation uses the (native) system default TZ, not the timezone of
         // the Time to calculate this and was therefore not stable. This changed to use the Time's
         // timezone when the Time class was re-written in Java.
-        assertFormatEquals(t, "%s", "1117596615");
-        assertFormatEquals(t, "%T", "12:30:15");
-        assertFormatEquals(t, "%t", "\t");
-        assertFormatEquals(t, "%U", "22");
-        assertFormatEquals(t, "%u", "3");
-        assertFormatEquals(t, "%V", "22");
-        assertFormatEquals(t, "%v", " 1-6月-2005");
-        assertFormatEquals(t, "%W", "22");
-        assertFormatEquals(t, "%w", "3");
-        assertFormatEquals(t, "%X", "12:30:15");
-        assertFormatEquals(t, "%x", "2005年6月1日");
-        assertFormatEquals(t, "%y", "05");
-        assertFormatEquals(t, "%Y", "2005");
-        assertFormatEquals(t, "%Z", "JST");
-        assertFormatEquals(t, "%z", "+0900");
-        assertFormatEquals(t, "%+", "水 6月  1 12:30:15 JST 2005");
-        assertFormatEquals(t, "%%", "%");
+        verifyFormatEquals(t, "%s", "1117596615");
+        verifyFormatEquals(t, "%T", "12:30:15");
+        verifyFormatEquals(t, "%t", "\t");
+        verifyFormatEquals(t, "%U", "22");
+        verifyFormatEquals(t, "%u", "3");
+        verifyFormatEquals(t, "%V", "22");
+        verifyFormatEquals(t, "%v", " 1-6月-2005");
+        verifyFormatEquals(t, "%W", "22");
+        verifyFormatEquals(t, "%w", "3");
+        verifyFormatEquals(t, "%X", "12:30:15");
+        verifyFormatEquals(t, "%x", "2005年6月1日");
+        verifyFormatEquals(t, "%y", "05");
+        verifyFormatEquals(t, "%Y", "2005");
+        verifyFormatEquals(t, "%Z", "JST");
+        verifyFormatEquals(t, "%z", "+0900");
+        verifyFormatEquals(t, "%+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%%", "%");
 
         // Modifiers
 
-        assertFormatEquals(t, "%EC", "20");
-        assertFormatEquals(t, "%OC", "20");
+        verifyFormatEquals(t, "%EC", "20");
+        verifyFormatEquals(t, "%OC", "20");
 
-        assertFormatEquals(t, "%_+", "水 6月  1 12:30:15 JST 2005");
-        assertFormatEquals(t, "%-+", "水 6月  1 12:30:15 JST 2005");
-        assertFormatEquals(t, "%0+", "水 6月  1 12:30:15 JST 2005");
-        assertFormatEquals(t, "%^+", "水 6月  1 12:30:15 JST 2005");
-        assertFormatEquals(t, "%#+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%_+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%-+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%0+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%^+", "水 6月  1 12:30:15 JST 2005");
+        verifyFormatEquals(t, "%#+", "水 6月  1 12:30:15 JST 2005");
 
-        assertFormatEquals(t, "%_A", "水曜日");
-        assertFormatEquals(t, "%-A", "水曜日");
-        assertFormatEquals(t, "%0A", "水曜日");
-        assertFormatEquals(t, "%^A", "水曜日");
-        assertFormatEquals(t, "%#A", "水曜日");
+        verifyFormatEquals(t, "%_A", "水曜日");
+        verifyFormatEquals(t, "%-A", "水曜日");
+        verifyFormatEquals(t, "%0A", "水曜日");
+        verifyFormatEquals(t, "%^A", "水曜日");
+        verifyFormatEquals(t, "%#A", "水曜日");
 
-        assertFormatEquals(t, "%_Y", "20 5");
-        assertFormatEquals(t, "%-Y", "205");
-        assertFormatEquals(t, "%0Y", "2005");
-        assertFormatEquals(t, "%^Y", "2005");
-        assertFormatEquals(t, "%#Y", "2005");
+        verifyFormatEquals(t, "%_Y", "20 5");
+        verifyFormatEquals(t, "%-Y", "205");
+        verifyFormatEquals(t, "%0Y", "2005");
+        verifyFormatEquals(t, "%^Y", "2005");
+        verifyFormatEquals(t, "%#Y", "2005");
 
-        assertFormatEquals(t, "%_d", " 1");
-        assertFormatEquals(t, "%-d", "1");
-        assertFormatEquals(t, "%0d", "01");
-        assertFormatEquals(t, "%^d", "01");
-        assertFormatEquals(t, "%#d", "01");
+        verifyFormatEquals(t, "%_d", " 1");
+        verifyFormatEquals(t, "%-d", "1");
+        verifyFormatEquals(t, "%0d", "01");
+        verifyFormatEquals(t, "%^d", "01");
+        verifyFormatEquals(t, "%#d", "01");
     }
 
-    public void testFormat2445() throws Exception {
+    @Test
+    public void testFormat2445() {
         Time t = new Time(Time.TIMEZONE_UTC);
         Fields.setDateTime(t, 2005, 5, 1, 12, 30, 15);
 
@@ -1171,22 +1201,24 @@
         assertEquals("2005000 T0 0 0 ", t.format2445());
     }
 
-    public void testFormat2445_doesNotNormalize() throws Exception {
+    @Test
+    public void testFormat2445_doesNotNormalize() {
         Time t = new Time(Time.TIMEZONE_UTC);
         Fields.set(t, 2005, 13, 32, 25, 61, 61, -2, -2, -2, -2);
 
         Time tCopy = new Time(t);
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
 
         assertEquals("20051432T256161Z", t.format2445());
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
 
         t.timezone = tCopy.timezone = "America/Los_Angeles";
         assertEquals("20051432T256161", t.format2445());
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
     }
 
-    public void testToString() throws Exception {
+    @Test
+    public void testToString() {
         Time t = new Time(Time.TIMEZONE_UTC);
         assertEquals("19700101T000000UTC(0,0,0,-1,0)", t.toString());
 
@@ -1194,25 +1226,28 @@
         assertEquals("19700101T000000America/Los_Angeles(0,0,0,-1,28800)", t.toString());
     }
 
-    public void testToString_doesNotNormalize() throws Exception {
+    @Test
+    public void testToString_doesNotNormalize() {
         Time t = new Time(Time.TIMEZONE_UTC);
         Fields.set(t, 2005, 13, 32, -1, -1, -1, -2, -2, -2, -2);
 
         Time tCopy = new Time(t);
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
 
         String r = t.toString();
         assertEquals("20051432T-1-1-1UTC(-2,-2,-2,-2,1141426739)", r);
 
-        Fields.assertTimeEquals(t, tCopy);
+        Fields.verifyTimeEquals(t, tCopy);
     }
 
-    public void testGetCurrentTimezone() throws Exception {
+    @Test
+    public void testGetCurrentTimezone() {
         String r = Time.getCurrentTimezone();
         assertEquals(TimeZone.getDefault().getID(), r);
     }
 
-    public void testSetToNow() throws Exception {
+    @Test
+    public void testSetToNow() {
         Time t = new Time(Time.TIMEZONE_UTC);
 
         // Time works in seconds so all millis values have to be divided by 1000, otherwise
@@ -1228,7 +1263,8 @@
         assertTrue(lowerBound <= actual && actual <= upperBound);
     }
 
-    public void testToMillis_utc() throws Exception {
+    @Test
+    public void testToMillis_utc() {
         Time t = new Time(Time.TIMEZONE_UTC);
 
         long winterTimeUtcMillis = 1167613323000L;
@@ -1284,7 +1320,8 @@
         assertEquals(summerTimeUtcMillis, r);
     }
 
-    public void testToMillis_dstTz() throws Exception {
+    @Test
+    public void testToMillis_dstTz() {
         Time t = new Time(PstPdt.ID);
 
         // A STD time
@@ -1296,68 +1333,71 @@
         assertEquals(stdTimeMillis, r);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(true, t, stdTimeMillis);
+        verifyToMillisResult(true, t, stdTimeMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(true, t, stdTimeMillis);
+        verifyToMillisResult(true, t, stdTimeMillis);
 
         long dstToStdCorrectionMillis =
                 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, stdTimeMillis);
+        verifyToMillisResult(false, t, stdTimeMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, stdTimeMillis + dstToStdCorrectionMillis);
+        verifyToMillisResult(false, t, stdTimeMillis + dstToStdCorrectionMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, stdTimeMillis);
+        verifyToMillisResult(false, t, stdTimeMillis);
 
         // A DST time
         long dstTimeUtcMillis = 1180659723000L;
         long dstTimeMillis = dstTimeUtcMillis - PstPdt.getUtcOffsetMillis(true);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
-        assertToMillisResult(true, t, dstTimeMillis);
+        verifyToMillisResult(true, t, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(true, t, dstTimeMillis);
+        verifyToMillisResult(true, t, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(true, t, dstTimeMillis);
+        verifyToMillisResult(true, t, dstTimeMillis);
 
         long stdToDstCorrectionMillis = -dstToStdCorrectionMillis;
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, dstTimeMillis + stdToDstCorrectionMillis);
+        verifyToMillisResult(false, t, dstTimeMillis + stdToDstCorrectionMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, dstTimeMillis);
+        verifyToMillisResult(false, t, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
-        assertToMillisResult(false, t, dstTimeMillis);
+        verifyToMillisResult(false, t, dstTimeMillis);
     }
 
-    private static void assertToMillisResult(boolean toMillisArgument, Time t, long expectedResult) {
+    private static void verifyToMillisResult(boolean toMillisArgument, Time t,
+            long expectedResult) {
         long r = t.toMillis(toMillisArgument /* ignore isDst */);
         assertEquals(expectedResult, r);
     }
 
+    @Test
     public void testToMillis_doesNotNormalize() {
         Time t = new Time(Time.TIMEZONE_UTC);
 
         Fields.set(t, 2007, 13, 32, 25, 60, 60, -2 /* isDst */, Integer.MAX_VALUE, 367, 7);
 
         Time originalTime = new Time(t);
-        Fields.assertTimeEquals(t, originalTime);
+        Fields.verifyTimeEquals(t, originalTime);
 
         t.toMillis(true);
-        Fields.assertTimeEquals(originalTime, t);
+        Fields.verifyTimeEquals(originalTime, t);
 
         t.toMillis(false);
-        Fields.assertTimeEquals(originalTime, t);
+        Fields.verifyTimeEquals(originalTime, t);
     }
 
+    @Test
     public void testToMillis_skippedTime() {
         // Tests behavior around a transition from STD to DST that introduces an hour of "skipped"
         // time from 01:00 to 01:59.
@@ -1383,13 +1423,13 @@
             } else {
                 expectedTimeMillis = -1;
             }
-            assertToMillisResult(true, time, expectedTimeMillis);
+            verifyToMillisResult(true, time, expectedTimeMillis);
 
             // isDst = 0, toMillis(false)
             Fields.set(time, timeFields);
             time.isDst = 0;
             expectedTimeMillis = stdBaseTimeMillis + minutesInMillis;
-            assertToMillisResult(false, time, expectedTimeMillis);
+            verifyToMillisResult(false, time, expectedTimeMillis);
 
             // isDst = 1, toMillis(true)
             Fields.set(time, timeFields);
@@ -1401,13 +1441,13 @@
             } else {
                 expectedTimeMillis = -1;
             }
-            assertToMillisResult(true, time, expectedTimeMillis);
+            verifyToMillisResult(true, time, expectedTimeMillis);
 
             // isDst = 1, toMillis(false)
             Fields.set(time, timeFields);
             time.isDst = 1;
             expectedTimeMillis = dstBaseTimeMillis + minutesInMillis;
-            assertToMillisResult(false, time, expectedTimeMillis);
+            verifyToMillisResult(false, time, expectedTimeMillis);
 
             // isDst = -1, toMillis(true)
             Fields.set(time, timeFields);
@@ -1420,15 +1460,16 @@
             } else {
                 expectedTimeMillis = -1;
             }
-            assertToMillisResult(false, time, expectedTimeMillis);
+            verifyToMillisResult(false, time, expectedTimeMillis);
 
             // isDst = -1, toMillis(false)
             Fields.set(time, timeFields);
             time.isDst = -1;
-            assertToMillisResult(false, time, expectedTimeMillis);
+            verifyToMillisResult(false, time, expectedTimeMillis);
         }
     }
 
+    @Test
     public void testToMillis_duplicateWallTime() {
         // 1:00 in standard / 2:00 in DST
         long timeBaseMillis = 1194163200000L;
@@ -1460,7 +1501,7 @@
             // isDst = 0, toMillis(false)
             Fields.set(time, timeFields);
             time.isDst = 0;
-            assertToMillisResult(false, time,
+            verifyToMillisResult(false, time,
                     timeBaseMillis + minutesInMillis + dstCorrectionMillis);
 
             // isDst = 1, toMillis(true)
@@ -1481,7 +1522,7 @@
             // isDst = 1, toMillis(false)
             Fields.set(time, timeFields);
             time.isDst = 1;
-            assertToMillisResult(false, time, timeBaseMillis + minutesInMillis);
+            verifyToMillisResult(false, time, timeBaseMillis + minutesInMillis);
 
             // isDst = -1, toMillis(true)
             Fields.set(time, timeFields);
@@ -1517,59 +1558,63 @@
         }
     }
 
+    @Test
     public void testToMillis_beforeTzRecords() {
         int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
-        assertToMillisInvalid(timeFields, PstPdt.ID);
-        assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyToMillisInvalid(timeFields, PstPdt.ID);
+        verifyToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
-    private static void assertToMillisInvalid(int[] timeFields, String timezone) {
+    private static void verifyToMillisInvalid(int[] timeFields, String timezone) {
         Time time = new Time(timezone);
 
         // isDst = 0, toMillis(true)
         Fields.set(time, timeFields);
         time.isDst = 0;
-        assertToMillisResult(true, time, -1);
+        verifyToMillisResult(true, time, -1);
 
         // isDst = 0, toMillis(false)
         Fields.set(time, timeFields);
         time.isDst = 0;
-        assertToMillisResult(false, time, -1);
+        verifyToMillisResult(false, time, -1);
 
         // isDst = 1, toMillis(true)
         Fields.set(time, timeFields);
         time.isDst = 1;
-        assertToMillisResult(true, time, -1);
+        verifyToMillisResult(true, time, -1);
 
         // isDst = 1, toMillis(false)
         Fields.set(time, timeFields);
         time.isDst = 1;
-        assertToMillisResult(false, time, -1);
+        verifyToMillisResult(false, time, -1);
 
         // isDst = -1, toMillis(true)
         Fields.set(time, timeFields);
         time.isDst = -1;
-        assertToMillisResult(true, time, -1);
+        verifyToMillisResult(true, time, -1);
 
         // isDst = -1, toMillis(false)
         Fields.set(time, timeFields);
         time.isDst = -1;
-        assertToMillisResult(false, time, -1);
+        verifyToMillisResult(false, time, -1);
     }
 
+    @Test
     public void testToMillis_afterTzRecords() {
         int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
-        assertToMillisInvalid(timeFields, PstPdt.ID);
-        assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyToMillisInvalid(timeFields, PstPdt.ID);
+        verifyToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
+    @Test
     public void testToMillis_invalid() {
         int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 };
-        assertToMillisInvalid(timeFields, PstPdt.ID);
-        assertToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyToMillisInvalid(timeFields, PstPdt.ID);
+        verifyToMillisInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
-    public void testParse_date() throws Exception {
+    @Test
+    public void testParse_date() {
         String nonUtcTz = PstPdt.ID;
         Time t = new Time(nonUtcTz);
         assertFalse(t.parse("12345678"));
@@ -1577,80 +1622,78 @@
         Fields.setAllDayDate(expected, 1234, 55, 78);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testParse_null() throws Exception {
+    @Test(expected=NullPointerException.class)
+    public void testParse_null() {
         Time t = new Time(Time.TIMEZONE_UTC);
-        try {
-            t.parse(null);
-            fail();
-        } catch (NullPointerException e) {
-        }
+        t.parse(null);
     }
 
-    public void testParse() throws Exception {
+    @Test
+    public void testParse() {
         Time t = new Time(Time.TIMEZONE_UTC);
         t.parse("20061005T120000");
 
         Time expected = new Time(Time.TIMEZONE_UTC);
         Fields.set(expected, 2006, 9, 5, 12, 0, 0, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testParse_dateTime() throws Exception {
+    @Test
+    public void testParse_dateTime() {
         String nonUtcTz = PstPdt.ID;
         Time t = new Time(nonUtcTz);
         assertFalse(t.parse("12345678T901234"));
         Time expected = new Time(nonUtcTz);
         Fields.set(expected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         Time t2 = new Time(nonUtcTz);
         assertTrue(t2.parse("12345678T901234Z"));
         Time utcExpected = new Time(Time.TIMEZONE_UTC);
         Fields.set(utcExpected, 1234, 55, 78, 90, 12, 34, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(utcExpected, t2);
+        Fields.verifyTimeEquals(utcExpected, t2);
     }
 
-    public void testParse_errors() throws Exception {
-        String nonUtcTz = PstPdt.ID;
-        try {
-            Time t = new Time(nonUtcTz);
-            t.parse(null);
-            fail();
-        } catch (NullPointerException e) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testParse_pstPdtNull() {
+        Time t = new Time(PstPdt.ID);
+        t.parse(null);
+    }
 
+    @Test
+    public void testParse_errors() {
         // Too short
-        assertParseError("");
-        assertParseError("1");
-        assertParseError("12");
-        assertParseError("123");
-        assertParseError("1234");
-        assertParseError("12345");
-        assertParseError("123456");
-        assertParseError("1234567");
+        verifyParseError("");
+        verifyParseError("1");
+        verifyParseError("12");
+        verifyParseError("123");
+        verifyParseError("1234");
+        verifyParseError("12345");
+        verifyParseError("123456");
+        verifyParseError("1234567");
 
         // No "T" in the expected place
-        assertParseError("12345678S");
+        verifyParseError("12345678S");
 
         // Invalid character in the first 8 characters.
-        assertParseError("12X45678");
+        verifyParseError("12X45678");
 
         // Too short for a date/time (15 or 16 characters allowed)
-        assertParseError("12345678T");
-        assertParseError("12345678T0");
-        assertParseError("12345678T01");
-        assertParseError("12345678T012");
-        assertParseError("12345678T0123");
-        assertParseError("12345678T01234");
+        verifyParseError("12345678T");
+        verifyParseError("12345678T0");
+        verifyParseError("12345678T01");
+        verifyParseError("12345678T012");
+        verifyParseError("12345678T0123");
+        verifyParseError("12345678T01234");
 
         // Invalid character
-        assertParseError("12345678T0X2345");
+        verifyParseError("12345678T0X2345");
     }
 
-    private static void assertParseError(String s) {
+    private static void verifyParseError(String s) {
         Time t = new Time(Time.TIMEZONE_UTC);
         try {
             t.parse(s);
@@ -1659,77 +1702,76 @@
         }
     }
 
-    public void testParse3339() throws Exception {
+    @Test
+    public void testParse3339() {
         String tz = Time.TIMEZONE_UTC;
         Time expected = new Time(tz);
         Fields.setAllDayDate(expected, 1980, 4, 23);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23", expected);
 
         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50", expected);
 
         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50Z", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50Z", expected);
 
         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50.0Z", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50.0Z", expected);
 
         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50.12Z", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50.12Z", expected);
 
         Fields.setDateTime(expected, 1980, 4, 23, 9, 50, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123Z", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50.123Z", expected);
 
         // The time should be normalized to UTC
         Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50-01:05", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50-01:05", expected);
 
         // The time should be normalized to UTC
         Fields.setDateTime(expected, 1980, 4, 23, 10, 55, 50);
         Fields.setDst(expected, -1 /* isDst */, 0);
         Fields.setDerivedDateTime(expected, 0, 0);
-        assertParse3339Succeeds(tz, "1980-05-23T09:50:50.123-01:05", expected);
+        verifyParse3339Succeeds(tz, "1980-05-23T09:50:50.123-01:05", expected);
     }
 
-    private static void assertParse3339Succeeds(String timeZone, String toParse, Time expected) {
+    private static void verifyParse3339Succeeds(String timeZone, String toParse, Time expected) {
         Time t = new Time(timeZone);
         t.parse3339(toParse);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
+    @Test
     public void testParse3339_parseErrors() {
         // Too short
-        assertParse3339Error("1980");
+        verifyParse3339Error("1980");
 
         // Timezone too short
-        assertParse3339Error("1980-05-23T09:50:50.123+");
-        assertParse3339Error("1980-05-23T09:50:50.123+05:0");
+        verifyParse3339Error("1980-05-23T09:50:50.123+");
+        verifyParse3339Error("1980-05-23T09:50:50.123+05:0");
     }
 
+    @Test(expected=NullPointerException.class)
     public void testParse3339_null() {
         Time t = new Time(Time.TIMEZONE_UTC);
-        try {
-            t.parse3339(null);
-            fail();
-        } catch (NullPointerException e) {
-        }
+        t.parse3339(null);
     }
 
-    private void assertParse3339Error(String s) {
+    private void verifyParse3339Error(String s) {
         String tz = Time.TIMEZONE_UTC;
         Time t = new Time(tz);
         try {
@@ -1739,29 +1781,31 @@
         }
     }
 
-    public void testSetMillis_utc() throws Exception {
+    @Test
+    public void testSetMillis_utc() {
         String tz = Time.TIMEZONE_UTC;
         Time t = new Time(tz);
         t.set(1000L);
 
         Time expected = new Time(tz);
         Fields.set(expected, 1970, 0, 1, 0, 0, 1, 0 /* isDst */, 0, 0, 4);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         t.set(2000L);
         Fields.set(expected, 1970, 0, 1, 0, 0, 2, 0 /* isDst */, 0, 0, 4);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         t.set(1000L * 60);
         Fields.set(expected, 1970, 0, 1, 0, 1, 0, 0 /* isDst */, 0, 0, 4);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         t.set((1000L * 60 * 60 * 24) + 1000L);
         Fields.set(expected, 1970, 0, 2, 0, 0, 1, 0 /* isDst */, 0, 1, 5);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testSetMillis_utc_edgeCases() throws Exception {
+    @Test
+    public void testSetMillis_utc_edgeCases() {
         String tz = Time.TIMEZONE_UTC;
         Time t = new Time(tz);
         t.set(Integer.MAX_VALUE + 1L);
@@ -1769,16 +1813,17 @@
         Time expected = new Time(tz);
         // This a 32-bit int overflow bug.
         Fields.set(expected, 1970, 0, 25, 20, 31, 23, 0 /* isDst */, 0, 24, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         t = new Time(tz);
         t.set(Integer.MIN_VALUE - 1L);
         // This a 32-bit int underflow bug.
         Fields.set(expected, 1969, 11, 7, 3, 28, 37, 0 /* isDst */, 0, 340, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    public void testSetFields() throws Exception {
+    @Test
+    public void testSetFields() {
         String tz = Time.TIMEZONE_UTC;
         Time t = new Time(tz);
         Fields.set(t, 9, 9, 9, 9, 9, 9, 9 /* isDst */, 9, 9, 9);
@@ -1787,7 +1832,7 @@
 
         Time expected = new Time(tz);
         Fields.set(expected, 6, 5, 4, 3, 2, 1, -1 /* isDst */, 0, 0, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
     // Timezones that cover the world.  Some GMT offsets occur more than
@@ -1854,7 +1899,8 @@
         "Pacific/Midway",
     };
 
-    public void testGetJulianDay() throws Exception {
+    @Test
+    public void testGetJulianDay() {
         Time time = new Time();
 
         // For every 15th day of 2008, and for each of the timezones listed above,
@@ -1901,7 +1947,8 @@
         }
     }
 
-    public void testSetJulianDay() throws Exception {
+    @Test
+    public void testSetJulianDay() {
         Time time = new Time();
 
         // For each day of the year in 2008, and for each timezone,
@@ -1947,7 +1994,8 @@
         }
     }
 
-    public void testNormalize_utc() throws Exception {
+    @Test
+    public void testNormalize_utc() {
         Time t = new Time(Time.TIMEZONE_UTC);
         Time expected = new Time(Time.TIMEZONE_UTC);
 
@@ -1955,56 +2003,57 @@
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
-        assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, winterTimeUtcMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
-        assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, winterTimeUtcMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
-        assertNormalizeResult(true, t, expected, winterTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, winterTimeUtcMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
-        assertNormalizeResult(false, t, expected, winterTimeUtcMillis);
+        verifyNormalizeResult(false, t, expected, winterTimeUtcMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 0, 0, 1);
-        assertNormalizeResult(false, t, expected, winterTimeUtcMillis);
+        verifyNormalizeResult(false, t, expected, winterTimeUtcMillis);
 
         long summerTimeUtcMillis = 1180659723000L;
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, summerTimeUtcMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, summerTimeUtcMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        assertNormalizeResult(true, t, expected, summerTimeUtcMillis);
+        verifyNormalizeResult(true, t, expected, summerTimeUtcMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        assertNormalizeResult(false, t, expected, summerTimeUtcMillis);
+        verifyNormalizeResult(false, t, expected, summerTimeUtcMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 1, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        assertNormalizeResult(false, t, expected, summerTimeUtcMillis);
+        verifyNormalizeResult(false, t, expected, summerTimeUtcMillis);
     }
 
-    public void testNormalize_dstTz() throws Exception {
+    @Test
+    public void testNormalize_dstTz() {
         Time t = new Time(PstPdt.ID);
         Time expected = new Time(PstPdt.ID);
 
@@ -2014,30 +2063,30 @@
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(true, t, expected, stdTimeMillis);
+        verifyNormalizeResult(true, t, expected, stdTimeMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(true, t, expected, stdTimeMillis);
+        verifyNormalizeResult(true, t, expected, stdTimeMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(true, t, expected, stdTimeMillis);
+        verifyNormalizeResult(true, t, expected, stdTimeMillis);
 
         long dstToStdCorrectionMillis =
                 PstPdt.getUtcOffsetMillis(false) - PstPdt.getUtcOffsetMillis(true);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(false, t, expected, stdTimeMillis);
+        verifyNormalizeResult(false, t, expected, stdTimeMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 0, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(false, t, expected, stdTimeMillis + dstToStdCorrectionMillis);
+        verifyNormalizeResult(false, t, expected, stdTimeMillis + dstToStdCorrectionMillis);
 
         Fields.set(t, 2007, 0, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 0, 1, 1, 2, 3, 0 /* isDst */, -28800, 0, 1);
-        assertNormalizeResult(false, t, expected, stdTimeMillis);
+        verifyNormalizeResult(false, t, expected, stdTimeMillis);
 
         // A DST time
         long dstTimeUtcMillis = 1180659723000L;
@@ -2045,31 +2094,32 @@
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(true, t, expected, dstTimeMillis);
+        verifyNormalizeResult(true, t, expected, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(true, t, expected, dstTimeMillis);
+        verifyNormalizeResult(true, t, expected, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(true, t, expected, dstTimeMillis);
+        verifyNormalizeResult(true, t, expected, dstTimeMillis);
 
         long stdToDstCorrectionMillis = -dstToStdCorrectionMillis;
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2007, 5, 1, 2, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(false, t, expected, dstTimeMillis + stdToDstCorrectionMillis);
+        verifyNormalizeResult(false, t, expected, dstTimeMillis + stdToDstCorrectionMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(false, t, expected, dstTimeMillis);
+        verifyNormalizeResult(false, t, expected, dstTimeMillis);
 
         Fields.set(t, 2007, 5, 1, 1, 2, 3, -1 /* isDst */, -25200, 151, 5);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 1 /* isDst */, -25200, 151, 5);
-        assertNormalizeResult(false, t, expected, dstTimeMillis);
+        verifyNormalizeResult(false, t, expected, dstTimeMillis);
     }
 
+    @Test
     public void testNormalize_skippedTime() {
         // Tests behavior around a transition from STD to DST that introduces an hour of "skipped"
         // time from 01:00 to 01:59.
@@ -2126,7 +2176,7 @@
                 Fields.setDerivedDateTime(expected, 9, 9);
             }
             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 0, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2144,7 +2194,7 @@
                 Fields.setDst(expected, 1, PstPdt.getUtcOffsetSeconds(1));
             }
             Fields.setDerivedDateTime(expected, 69, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 1, normalize(true)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2169,7 +2219,7 @@
                 Fields.setDerivedDateTime(expected, 9, 9);
             }
             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 1, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2187,7 +2237,7 @@
                 Fields.setDst(expected, 0, PstPdt.getUtcOffsetSeconds(0));
             }
             Fields.setDerivedDateTime(expected, 69, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = -1, normalize(true)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2212,7 +2262,7 @@
                 Fields.setDerivedDateTime(expected, 9, 9);
             }
             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = -1, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2237,10 +2287,11 @@
                 Fields.setDerivedDateTime(expected, 9, 9);
             }
             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
         }
     }
 
+    @Test
     public void testNormalize_duplicateWallTime() {
         // 1:00 in standard / 2:00 in DST
         long timeBaseMillis = 1194163200000L;
@@ -2293,7 +2344,7 @@
                 fail("i =" + i);
             }
             Fields.setDerivedDateTime(expected, 307, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 0, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2311,7 +2362,7 @@
                 Fields.setDst(expected, 0 /* isDst */, PstPdt.getUtcOffsetSeconds(0));
             }
             Fields.setDerivedDateTime(expected, 307, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 1, normalize(true)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2334,7 +2385,7 @@
                 fail("i =" + i);
             }
             Fields.setDerivedDateTime(expected, 307, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = 1, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2352,7 +2403,7 @@
             }
             Fields.setDerivedDateTime(expected, 307, 0);
             assertEquals("i = " + i, expectedTimeMillis, timeMillis);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = -1, normalize(true)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2375,7 +2426,7 @@
                 fail("i =" + i);
             }
             Fields.setDerivedDateTime(expected, 307, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
 
             // isDst = -1, normalize(false)
             Fields.setDateTime(time, dateTimeArgs);
@@ -2397,17 +2448,18 @@
                 fail("i =" + i);
             }
             Fields.setDerivedDateTime(expected, 307, 0);
-            Fields.assertTimeEquals("i = " + i, expected, time);
+            Fields.verifyTimeEquals("i = " + i, expected, time);
         }
     }
 
+    @Test
     public void testNormalize_beforeTzRecords() {
         int[] timeFields = new int[] { 1900, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
-        assertNormalizeInvalid(timeFields, PstPdt.ID);
-        assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyNormalizeInvalid(timeFields, PstPdt.ID);
+        verifyNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
-    private static void assertNormalizeInvalid(int[] timeFields, String timezone) {
+    private static void verifyNormalizeInvalid(int[] timeFields, String timezone) {
         Time time = new Time(timezone);
         Time expected = new Time(timezone);
 
@@ -2416,56 +2468,59 @@
         time.isDst = 0;
         Fields.set(expected, timeFields);
         expected.isDst = -1;
-        assertNormalizeResult(true, time, expected, -1);
+        verifyNormalizeResult(true, time, expected, -1);
 
         // isDst = 0, normalize(false)
         Fields.set(time, timeFields);
         time.isDst = 0;
         Fields.set(expected, timeFields);
         expected.isDst = 0;
-        assertNormalizeResult(false, time, expected, -1);
+        verifyNormalizeResult(false, time, expected, -1);
 
         // isDst = 1, normalize(true)
         Fields.set(time, timeFields);
         time.isDst = 1;
         Fields.set(expected, timeFields);
         expected.isDst = -1;
-        assertNormalizeResult(true, time, expected, -1);
+        verifyNormalizeResult(true, time, expected, -1);
 
         // isDst = 1, normalize(false)
         Fields.set(time, timeFields);
         time.isDst = 1;
         Fields.set(expected, timeFields);
         expected.isDst = 1;
-        assertNormalizeResult(false, time, expected, -1);
+        verifyNormalizeResult(false, time, expected, -1);
 
         // isDst = -1, normalize(true)
         Fields.set(time, timeFields);
         time.isDst = -1;
         Fields.set(expected, timeFields);
         expected.isDst = -1;
-        assertNormalizeResult(true, time, expected, -1);
+        verifyNormalizeResult(true, time, expected, -1);
 
         // isDst = -1, normalize(false)
         Fields.set(time, timeFields);
         time.isDst = -1;
         Fields.set(expected, timeFields);
         expected.isDst = -1;
-        assertNormalizeResult(false, time, expected, -1);
+        verifyNormalizeResult(false, time, expected, -1);
     }
 
+    @Test
     public void testNormalize_afterTzRecords() {
         int[] timeFields = new int[] { 2039, 0, 1, 2, 3, 4, -999 /* not used */, 9, 9, 9 };
-        assertNormalizeInvalid(timeFields, PstPdt.ID);
-        assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyNormalizeInvalid(timeFields, PstPdt.ID);
+        verifyNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
+    @Test
     public void testNormalize_invalid() {
         int[] timeFields = new int[] { 0, 0, 0, 0, 0, 0, -999 /* not used */, 9, 9, 9 };
-        assertNormalizeInvalid(timeFields, PstPdt.ID);
-        assertNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
+        verifyNormalizeInvalid(timeFields, PstPdt.ID);
+        verifyNormalizeInvalid(timeFields, Time.TIMEZONE_UTC);
     }
 
+    @Test
     public void testNormalize_dstToDstSkip() {
         // In London, 4th May 1941 02:00 - 03:00 was a skip from DST -> DST (+1 hour -> +2 hours)
         String timezone = "Europe/London";
@@ -2475,22 +2530,22 @@
         // Demonstrate the data we expect either side of the skipped interval: 01:59
         Fields.set(t, 1941, 4, 4, 1, 59, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 4, 4, 1, 59, 0, 1 /* isDst */, 3600, 123, 0);
-        assertNormalizeResult(true, t, expected, -904518060000L);
+        verifyNormalizeResult(true, t, expected, -904518060000L);
 
         // Demonstrate the data we expect either side of the skipped interval: 03:00
         Fields.set(t, 1941, 4, 4, 3, 0, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 4, 4, 3, 0, 0, 1 /* isDst */, 7200, 123, 0);
-        assertNormalizeResult(true, t, expected, -904518000000L);
+        verifyNormalizeResult(true, t, expected, -904518000000L);
 
         // isDst = 1, normalize(false)
         Fields.set(t, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 4, 4, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         // isDst = -1, normalize(false)
         Fields.set(t, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 4, 4, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard
         // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
@@ -2499,7 +2554,7 @@
         // isDst = 0, normalize(false) @ 01:30
         Fields.set(t, 1941, 4, 4, 1, 30, 0, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 4, 4, 3, 30, 0, 1 /* isDst */, 7200, 123, 0);
-        assertNormalizeResult(false, t, expected, -904516200000L);
+        verifyNormalizeResult(false, t, expected, -904516200000L);
 
         // isDst = 0, normalize(false) @ 02:30
         Fields.set(t, 1941, 4, 4, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
@@ -2513,9 +2568,10 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
+    @Test
     public void testNormalize_dstToDstRepeat() {
         // In London, 10th August 1941 02:00 - 03:00 was a repeat from DST -> DST
         // (+2 hour -> +1 hour)
@@ -2526,24 +2582,24 @@
         // Demonstrate the data we expect during the repeated interval: 02:30 (first)
         t.set(-896052600000L);
         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 7200, 221, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // Demonstrate the data we expect during the repeated interval: 02:30 (second)
         t.set(-896049000000L);
         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // Now check times in the repeated hour with different isDst assertions...
 
         // isDst = 1, normalize(false) @ 02:30
         Fields.set(t, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
-        assertNormalizeResult(false, t, expected, -896049000000L);
+        verifyNormalizeResult(false, t, expected, -896049000000L);
 
         // isDst = -1, normalize(false) @ 02:30
         Fields.set(t, 1941, 7, 10, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 7, 10, 2, 30, 0, 1 /* isDst */, 3600, 221, 0);
-        assertNormalizeResult(false, t, expected, -896049000000L);
+        verifyNormalizeResult(false, t, expected, -896049000000L);
 
         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid standard
         // times so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
@@ -2560,14 +2616,15 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // isDst = 0, normalize(false) @ 02:30
         Fields.set(t, 1941, 7, 10, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1941, 7, 10, 3, 30, 0, 1 /* isDst */, 3600, 221, 0);
-        assertNormalizeResult(false, t, expected, -896045400000L);
+        verifyNormalizeResult(false, t, expected, -896045400000L);
     }
 
+    @Test
     public void testNormalize_stdToStdRepeat() {
         // In London, 31st October 1971 02:00 - 03:00 was a repeat from STD -> STD
         String timezone = "Europe/London";
@@ -2577,12 +2634,12 @@
         // Demonstrate the data we expect during the repeated interval: 02:30 (first)
         t.set(57720600000L);
         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 3600, 303, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // Demonstrate the data we expect during the repeated interval: 02:30 (second)
         t.set(57724200000L);
         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // isDst = 0, normalize(false) @ 02:30
         Fields.set(t, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 9, 9, 9);
@@ -2598,7 +2655,7 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // isDst = -1, normalize(false) @ 02:30
         Fields.set(t, 1971, 9, 31, 2, 30, 0, -1 /* isDst */, 9, 9, 9);
@@ -2615,7 +2672,7 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // The results below are potentially arbitrary: 01:30 and 02:30 are not a valid DST
         // so normalize() must apply one of the possible STD -> DST adjustments to arrive at a
@@ -2634,7 +2691,7 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // isDst = 1, normalize(false) @ 02:30
         Fields.set(t, 1971, 9, 31, 2, 30, 0, 1 /* isDst */, 9, 9, 9);
@@ -2647,14 +2704,15 @@
         } else {
             fail();
         }
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
 
         // isDst = 1, normalize(false) @ 03:30
         Fields.set(t, 1971, 9, 31, 3, 30, 0, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1971, 9, 31, 2, 30, 0, 0 /* isDst */, 0, 303, 0);
-        assertNormalizeResult(false, t, expected, 57724200000L);
+        verifyNormalizeResult(false, t, expected, 57724200000L);
     }
 
+    @Test
     public void testNormalize_stdToStdSkip() {
         // In Kiritimati, 1st Jan 1995 10:00 - 10:40 was a skip from STD -> STD (plus they do not
         // observe DST).
@@ -2665,19 +2723,20 @@
         // isDst = 0, normalize(false)
         Fields.set(t, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1995, 0, 1, 10, 20, 0, 0 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         // isDst = 1, normalize(false)
         Fields.set(t, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1995, 0, 1, 10, 20, 0, 1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         // isDst = -1, normalize(false)
         Fields.set(t, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 1995, 0, 1, 10, 20, 0, -1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
     }
 
+    @Test
     public void testNormalize_utcWithDst() {
         // In UTC (or other zone without DST), what happens when a DST time is specified and there
         // is no DST offset available in the timezone data.
@@ -2687,14 +2746,15 @@
         // isDst = 1, normalize(false)
         Fields.set(t, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2005, 6, 22, 1, 30, 0, 1 /* isDst */, 9, 9, 9);
-        assertNormalizeResult(false, t, expected, -1);
+        verifyNormalizeResult(false, t, expected, -1);
 
         // isDst = -1, normalize(false)
         Fields.set(t, 2005, 6, 22, 1, 30, 0, -1 /* isDst */, 9, 9, 9);
         Fields.set(expected, 2005, 6, 22, 1, 30, 0, 0 /* isDst */, 0, 202, 5);
-        assertNormalizeResult(false, t, expected, 1121995800000L);
+        verifyNormalizeResult(false, t, expected, 1121995800000L);
     }
 
+    @Test
     public void testUnknownTz() {
         // Historically the code used UTC if the timezone is unrecognized.
 
@@ -2712,14 +2772,14 @@
 
         Time expected = new Time(unknownTimezoneId);
         Fields.set(expected, 2007, 5, 1, 1, 2, 3, 0 /* isDst */, 0, 151, 5);
-        Fields.assertTimeEquals(expected, t);
+        Fields.verifyTimeEquals(expected, t);
     }
 
-    private static void assertNormalizeResult(boolean normalizeArgument, Time toNormalize,
+    private static void verifyNormalizeResult(boolean normalizeArgument, Time toNormalize,
             Time expectedTime, long expectedTimeMillis) {
         long actualTimeMillis = toNormalize.normalize(normalizeArgument /* ignore isDst */);
         assertEquals(expectedTimeMillis, actualTimeMillis);
-        Fields.assertTimeEquals(expectedTime, toNormalize);
+        Fields.verifyTimeEquals(expectedTime, toNormalize);
     }
 
     /** A helper class for manipulating / testing fields on Time objects. */
@@ -2730,19 +2790,15 @@
 
         final static int ALL = MAIN_DATE_TIME | DST_FIELDS | DERIVED_DATE_TIME;
 
-        public static void assertTimeEquals(Time expected, Time actual) {
-            assertTimeEquals("", ALL, expected, actual);
+        public static void verifyTimeEquals(Time expected, Time actual) {
+            verifyTimeEquals("", ALL, expected, actual);
         }
 
-        public static void assertTimeEquals(int fields, Time expected, Time actual) {
-            assertTimeEquals("", fields, expected, actual);
+        public static void verifyTimeEquals(String message, Time expected, Time actual) {
+            verifyTimeEquals(message, Fields.ALL, expected, actual);
         }
 
-        public static void assertTimeEquals(String message, Time expected, Time actual) {
-            assertTimeEquals(message, Fields.ALL, expected, actual);
-        }
-
-        public static void assertTimeEquals(String message, int fields, Time expected,
+        public static void verifyTimeEquals(String message, int fields, Time expected,
                 Time actual) {
             boolean mainDateTimeOk = (fields & Fields.MAIN_DATE_TIME) == 0
                     || (Objects.equals(expected.timezone, actual.timezone)
@@ -2769,7 +2825,7 @@
         }
 
         private static String timeToString(int fields, Time time) {
-            List<Object> values = new ArrayList<Object>();
+            List<Object> values = new ArrayList<>();
             StringBuilder format = new StringBuilder();
             if ((fields & Fields.MAIN_DATE_TIME) > 0) {
                 format.append("%d-%02d-%02d %02d:%02d:%02d allDay=%b timezone=%s ");
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..7057913 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -16,10 +16,21 @@
 
 package android.text.method.cts;
 
+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 android.app.Activity;
+import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
@@ -35,6 +46,13 @@
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ArrowKeyMovementMethod}. The class is an implementation of interface
  * {@link MovementMethod}. The typical usage of {@link MovementMethod} is tested in
@@ -43,7 +61,9 @@
  *
  * @see android.widget.cts.TextViewTest
  */
-public class ArrowKeyMovementMethodTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ArrowKeyMovementMethodTest {
     private static final String THREE_LINES_TEXT = "first line\nsecond line\nlast line";
     private static final int END_OF_ALL_TEXT = THREE_LINES_TEXT.length();
     private static final int END_OF_1ST_LINE = THREE_LINES_TEXT.indexOf('\n');
@@ -51,46 +71,47 @@
     private static final int END_OF_2ND_LINE = THREE_LINES_TEXT.indexOf('\n', START_OF_2ND_LINE);
     private static final int START_OF_3RD_LINE = END_OF_2ND_LINE + 1;
     private static final int SPACE_IN_2ND_LINE = THREE_LINES_TEXT.indexOf(' ', START_OF_2ND_LINE);
+
+    private Instrumentation mInstrumentation;
     private TextView mTextView;
     private ArrowKeyMovementMethod mArrowKeyMovementMethod;
     private Editable mEditable;
     private MyMetaKeyKeyListener mMetaListener;
 
-    public ArrowKeyMovementMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mMetaListener = new MyMetaKeyKeyListener();
         mArrowKeyMovementMethod = new ArrowKeyMovementMethod();
 
-        initTextViewWithNullLayout();
+        mActivityRule.runOnUiThread(() -> {;
+            initTextViewWithNullLayout();
 
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
-                        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+            Activity activity = mActivityRule.getActivity();
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
+                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
 
-                getActivity().setContentView(mTextView);
-                mTextView.setFocusable(true);
-                mTextView.requestFocus();
-            }
+            activity.setContentView(mTextView);
+            mTextView.setFocusable(true);
+            mTextView.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
-        assertNotNull(mTextView.getLayout());
-        assertTrue(mTextView.isFocused());
+        PollingCheck.waitFor(() -> mTextView.isFocused() && (mTextView.getLayout() != null));
     }
 
+    @Test
     public void testConstructor() {
         new ArrowKeyMovementMethod();
     }
 
+    @Test
     public void testCanSelectArbitrarily() {
         assertTrue(new ArrowKeyMovementMethod().canSelectArbitrarily());
     }
 
+    @Test
     public void testGetInstance() {
         MovementMethod method0 = ArrowKeyMovementMethod.getInstance();
         assertNotNull(method0);
@@ -100,6 +121,7 @@
         assertSame(method0, method1);
     }
 
+    @Test
     public void testOnTakeFocus() throws Throwable {
         /*
          * The following assertions depend on whether the TextView has a layout.
@@ -110,75 +132,64 @@
          * into several steps, setting the content at first, waiting the layout,
          * and checking the assertion at last.
          */
-        assertSelection(-1);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
-            }
+        verifySelection(-1);
+        mActivityRule.runOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
         });
-        getInstrumentation().waitForIdleSync();
-        assertSelection(END_OF_ALL_TEXT);
+        mInstrumentation.waitForIdleSync();
+        verifySelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
         });
-        getInstrumentation().waitForIdleSync();
-        assertSelection(END_OF_ALL_TEXT);
+        mInstrumentation.waitForIdleSync();
+        verifySelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setSingleLine();
-            }
-        });
+        mActivityRule.runOnUiThread(mTextView::setSingleLine);
         // wait until the textView gets layout
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
         });
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Selection.removeSelection(mEditable);
-                mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Selection.removeSelection(mEditable);
+            mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
         });
-        assertSelection(END_OF_ALL_TEXT);
-    }
-
-    public void testOnTakeFoucusWithNullLayout() {
-        initTextViewWithNullLayout();
-        assertSelectEndOfContent();
-    }
-
-    public void testOnTakeFocusWithNullParameters() {
-        initTextViewWithNullLayout();
-        try {
-            mArrowKeyMovementMethod.onTakeFocus(null, mEditable, View.FOCUS_DOWN);
-            fail("The method did not throw NullPointerException when param textView is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mArrowKeyMovementMethod.onTakeFocus(mTextView, null, View.FOCUS_DOWN);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        verifySelection(END_OF_ALL_TEXT);
     }
 
     @UiThreadTest
+    @Test
+    public void testOnTakeFocusWithNullLayout() {
+        initTextViewWithNullLayout();
+        verifySelectEndOfContent();
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTakeFocusNullView() {
+        // Should throw NullPointerException when param textView is null
+        mArrowKeyMovementMethod.onTakeFocus(null, mEditable, View.FOCUS_DOWN);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTakeFocusNullSpannable() {
+        initTextViewWithNullLayout();
+        // Should throw NullPointerException when param spannable is null
+        mArrowKeyMovementMethod.onTakeFocus(mTextView, null, View.FOCUS_DOWN);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeUp() {
         // shift+alt tests
         final KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -194,7 +205,7 @@
         // |first line
         // second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, 0);
+        verifySelection(SPACE_IN_2ND_LINE, 0);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0,
@@ -218,7 +229,7 @@
         // |first line
         // second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, 0);
+        verifySelection(SPACE_IN_2ND_LINE, 0);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0,
@@ -231,7 +242,7 @@
         // |first line
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP,
@@ -244,7 +255,7 @@
         // first lin|e
         // second line
         // last line
-        assertSelection(correspondingIn1stLine);
+        verifySelection(correspondingIn1stLine);
 
         // Move to beginning of first line (behavior changed in L)
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -252,17 +263,18 @@
         // |first line
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
 
         assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
                 KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
         // first lin|e
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeDown() {
         // shift+alt tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -278,7 +290,7 @@
         // first line
         // second |line
         // last line|
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
@@ -302,7 +314,7 @@
         // first line
         // second |line
         // last line|
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, 0,
@@ -315,7 +327,7 @@
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
@@ -328,7 +340,7 @@
         // first line
         // second line
         // last lin|e
-        assertSelection(correspondingIn3rdLine);
+        verifySelection(correspondingIn3rdLine);
 
         // move to end of last line (behavior changed in L)
         Selection.setSelection(mEditable, END_OF_ALL_TEXT - 1);
@@ -337,17 +349,18 @@
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
                 KeyEvent.KEYCODE_DPAD_DOWN, noMetaEvent));
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeLeft() {
         // shift+alt tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -363,7 +376,7 @@
         // first line
         // |second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
 
         pressBothShiftAlt();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -371,7 +384,7 @@
         // first line
         // |second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
@@ -384,7 +397,7 @@
         // first line
         // second| |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 1);
+        verifySelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 1);
 
         pressShift();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -392,7 +405,7 @@
         // first line
         // secon|d |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 2);
+        verifySelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE - 2);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, 0,
@@ -405,7 +418,7 @@
         // first line
         // |second line
         // last line
-        assertSelection(START_OF_2ND_LINE);
+        verifySelection(START_OF_2ND_LINE);
 
         pressAlt();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -413,7 +426,7 @@
         // first line
         // |second line
         // last line
-        assertSelection(START_OF_2ND_LINE);
+        verifySelection(START_OF_2ND_LINE);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
@@ -426,7 +439,7 @@
         // first line
         // second| line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE - 1);
+        verifySelection(SPACE_IN_2ND_LINE - 1);
 
         Selection.setSelection(mEditable, START_OF_2ND_LINE);
         // first line
@@ -437,10 +450,11 @@
         // first line|
         // second line
         // last line
-        assertSelection(END_OF_1ST_LINE);
+        verifySelection(END_OF_1ST_LINE);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeRight() {
         // shift+alt tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -456,7 +470,7 @@
         // first line
         // second |line|
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
 
         pressBothShiftAlt();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -464,7 +478,7 @@
         // first line
         // second |line|
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
@@ -477,7 +491,7 @@
         // first line
         // second |l|ine
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 1);
+        verifySelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 1);
 
         pressShift();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -485,7 +499,7 @@
         // first line
         // second |li|ne
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 2);
+        verifySelection(SPACE_IN_2ND_LINE, SPACE_IN_2ND_LINE + 2);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
@@ -498,7 +512,7 @@
         // first line
         // second line|
         // last line
-        assertSelection(END_OF_2ND_LINE);
+        verifySelection(END_OF_2ND_LINE);
 
         pressAlt();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -506,7 +520,7 @@
         // first line
         // second line|
         // last line
-        assertSelection(END_OF_2ND_LINE);
+        verifySelection(END_OF_2ND_LINE);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -519,7 +533,7 @@
         // first line
         // second l|ine
         // last line
-        assertSelection(SPACE_IN_2ND_LINE + 1);
+        verifySelection(SPACE_IN_2ND_LINE + 1);
 
         Selection.setSelection(mEditable, END_OF_2ND_LINE);
         // first line
@@ -530,10 +544,11 @@
         // first line
         // second line
         // |last line
-        assertSelection(START_OF_3RD_LINE);
+        verifySelection(START_OF_3RD_LINE);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodePageUp() {
         // shift+alt tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -549,7 +564,7 @@
         // |first line
         // second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, 0);
+        verifySelection(SPACE_IN_2ND_LINE, 0);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_UP,
@@ -562,7 +577,7 @@
         // |first line
         // second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, 0);
+        verifySelection(SPACE_IN_2ND_LINE, 0);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_UP, 0,
@@ -575,7 +590,7 @@
         // |first line
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_UP,
@@ -588,10 +603,11 @@
         // |first line
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodePageDown() {
         // shift+alt tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -607,7 +623,7 @@
         // first line
         // second |line
         // last line|
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_DOWN,
@@ -620,7 +636,7 @@
         // first line
         // second |line
         // last line|
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
 
         // alt tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_DOWN, 0,
@@ -633,7 +649,7 @@
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_DOWN,
@@ -646,10 +662,11 @@
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeMoveHome() {
         // shift+ctrl tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -665,7 +682,7 @@
         // |first line
         // second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, 0);
+        verifySelection(SPACE_IN_2ND_LINE, 0);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_HOME,
@@ -678,7 +695,7 @@
         // first line
         // |second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
 
         pressShift();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -686,7 +703,7 @@
         // first line
         // |second |line
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, START_OF_2ND_LINE);
 
         // ctrl tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_HOME, 0,
@@ -699,7 +716,7 @@
         // |first line
         // second line
         // last line
-        assertSelection(0);
+        verifySelection(0);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_HOME,
@@ -712,7 +729,7 @@
         // first line
         // |second line
         // last line
-        assertSelection(START_OF_2ND_LINE);
+        verifySelection(START_OF_2ND_LINE);
 
         MetaKeyKeyListener.resetMetaState(mEditable);
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -720,10 +737,11 @@
         // first line
         // |second line
         // last line
-        assertSelection(START_OF_2ND_LINE);
+        verifySelection(START_OF_2ND_LINE);
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithKeyCodeMoveEnd() {
         // shift+ctrl tests
         KeyEvent shiftAltEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
@@ -739,7 +757,7 @@
         // first line
         // second |line
         // last line|
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_ALL_TEXT);
 
         // shift tests
         KeyEvent shiftEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_END,
@@ -752,7 +770,7 @@
         // first line
         // second |line|
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
 
         pressShift();
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -760,7 +778,7 @@
         // first line
         // second |line|
         // last line
-        assertSelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE, END_OF_2ND_LINE);
 
         // ctrl tests
         KeyEvent altEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_END, 0,
@@ -773,7 +791,7 @@
         // first line
         // second line
         // last line|
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         // no-meta tests
         KeyEvent noMetaEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_END,
@@ -786,7 +804,7 @@
         // first line
         // second line|
         // last line
-        assertSelection(END_OF_2ND_LINE);
+        verifySelection(END_OF_2ND_LINE);
 
         MetaKeyKeyListener.resetMetaState(mEditable);
         assertTrue(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
@@ -794,21 +812,19 @@
         // first line
         // second line|
         // last line
-        assertSelection(END_OF_2ND_LINE);
-    }
-
-    public void testOnKeyDownWithNullLayout() {
-        initTextViewWithNullLayout();
-        try {
-            mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable, KeyEvent.KEYCODE_DPAD_RIGHT,
-                    null);
-            fail("The method did not throw NullPointerException when layout of the view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        verifySelection(END_OF_2ND_LINE);
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnKeyDownWithNullLayout() {
+        initTextViewWithNullLayout();
+        // Should throw NullPointerException when layout of the view is null
+        mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable, KeyEvent.KEYCODE_DPAD_RIGHT, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnKeyOther() {
         // first line
         // second |line
@@ -861,6 +877,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnKeyDownWithOtherKeyCode() {
         // first line
         // second |line
@@ -880,19 +897,22 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnTouchEvent() throws Throwable {
         long now = SystemClock.currentThreadTimeMillis();
         Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
         assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
                 MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1, 0)));
-        assertSelection(SPACE_IN_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE);
 
         assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
                 MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1,
                         KeyEvent.META_SHIFT_ON)));
-        assertSelection(SPACE_IN_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnTouchEventWithNullLayout() {
         initTextViewWithNullLayout();
         mTextView.setFocusable(true);
@@ -905,40 +925,39 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnTouchEventWithoutFocus() {
         long now = SystemClock.currentThreadTimeMillis();
         Selection.setSelection(mEditable, SPACE_IN_2ND_LINE);
         assertFalse(mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable,
                 MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1, 1, 0)));
-        assertSelection(SPACE_IN_2ND_LINE);
+        verifySelection(SPACE_IN_2ND_LINE);
     }
 
-    public void testOnTouchEventWithNullParameters() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEventNullView() {
+        // Should throw NullPointerException when param textView is null
+        mArrowKeyMovementMethod.onTouchEvent(null, mEditable, MotionEvent.obtain(0, 0, 0, 1, 1, 0));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEventNullSpannable() {
         initTextViewWithNullLayout();
-        try {
-            mArrowKeyMovementMethod.onTouchEvent(null, mEditable,
-                    MotionEvent.obtain(0, 0, 0, 1, 1, 0));
-            fail("The method did not throw NullPointerException when param textView is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mArrowKeyMovementMethod.onTouchEvent(mTextView, null,
-                    MotionEvent.obtain(0, 0, 0, 1, 1, 0));
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable, null);
-            fail("The method did not throw NullPointerException when param motionEvent is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        // Should throw NullPointerException when param spannable is null
+        mArrowKeyMovementMethod.onTouchEvent(mTextView, null, MotionEvent.obtain(0, 0, 0, 1, 1, 0));
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEventNullEvent() {
+        initTextViewWithNullLayout();
+        // Should throw NullPointerException when param motionEvent is null
+        mArrowKeyMovementMethod.onTouchEvent(mTextView, mEditable, null);
+    }
+
+    @Test
     public void testInitialize() {
         Spannable spannable = new SpannableString("test content");
         ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
@@ -955,15 +974,17 @@
         method.initialize(null, spannable);
         assertEquals(0, Selection.getSelectionStart(spannable));
         assertEquals(0, Selection.getSelectionEnd(spannable));
-
-        try {
-            method.initialize(mTextView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testIntializeNullSpannable() {
+        ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
+        // Should throw NullPointerException when param spannable is null
+        method.initialize(mTextView, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnTrackballEven() {
         assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable,
                 MotionEvent.obtain(0, 0, 0, 1, 1, 0)));
@@ -979,11 +1000,13 @@
         assertFalse(mArrowKeyMovementMethod.onTrackballEvent(mTextView, mEditable, null));
     }
 
+    @UiThreadTest
+    @Test
     public void testOnKeyUp() {
         ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
         SpannableString spannable = new SpannableString("Test Content");
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        TextView view = new TextViewNoIme(getActivity());
+        TextView view = new TextViewNoIme(mActivityRule.getActivity());
         view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
 
         assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
@@ -1000,6 +1023,7 @@
             + "lectus porta consequ\u00e4t...  LOReM iPSuM";
 
     @UiThreadTest
+    @Test
     public void testFollowingWordStartToEnd() {
 
         // NOTE: there seems to be much variation in how word boundaries are
@@ -1010,92 +1034,93 @@
 
         // |Lorem ipsum; dolor sit $met,
         Selection.setSelection(mEditable, 0);
-        assertSelection(0);
+        verifySelection(0);
 
         // Lorem| ipsum; dolor sit $met,
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(5);
+        verifySelection(5);
 
         // Lorem ipsum|; dolor sit $met,
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(11);
+        verifySelection(11);
 
         // Lorem ipsum; dolor| sit $met,
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(18);
+        verifySelection(18);
 
         // Lorem ipsum; dolor sit| $met,
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(22);
+        verifySelection(22);
 
         // $met|, conse$_$ctetur$       Adipiscing.elit.integ$r.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(27);
+        verifySelection(27);
 
         // $met, conse$_$ctetur|$       Adipiscing.elit.integ$r.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(43);
+        verifySelection(43);
 
         // TODO: enable these two additional word breaks when implemented
 //        // $met, conse$_$ctetur$       Adipiscing|.elit.integ$r.
 //        assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-//        assertSelection(61);
+//        verifySelection(61);
 //
 //        // $met, conse$_$ctetur$       Adipiscing.elit|.integ$r.
 //        assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-//        assertSelection(66);
+//        verifySelection(66);
 
         // $met, conse$_$ctetur$       Adipiscing.elit.integ$r|.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(74);
+        verifySelection(74);
 
         // integ$r. Etiam|    tristique$tortor nec   ?:?    $$lectus porta
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(81);
+        verifySelection(81);
 
         // integ$r. Etiam    tristique|$tortor nec   ?:?    $$lectus porta
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(94);
+        verifySelection(94);
 
         // integ$r. Etiam    tristique$tortor| nec   ?:?    $$lectus porta
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(101);
+        verifySelection(101);
 
         // integ$r. Etiam    tristique$tortor nec|   ?:?    $$lectus porta
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(105);
+        verifySelection(105);
 
         // integ$r. Etiam    tristique$tortor nec   ?:?    $$lectus| porta
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(123);
+        verifySelection(123);
 
         // $$lectus porta| consequ$t...  LOReM iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(129);
+        verifySelection(129);
 
         // $$lectus porta consequ$t|...  LOReM iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(139);
+        verifySelection(139);
 
         // $$lectus porta consequ$t...  LOReM| iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(149);
+        verifySelection(149);
 
         // $$lectus porta consequ$t...  LOReM iPSuM|
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(155);
+        verifySelection(155);
 
         // keep trying to push beyond end, which should fail
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(155);
+        verifySelection(155);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(155);
+        verifySelection(155);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(155);
+        verifySelection(155);
 
     }
 
     @UiThreadTest
+    @Test
     public void testPrecedingWordEndToStart() {
 
         // NOTE: there seems to be much variation in how word boundaries are
@@ -1106,88 +1131,88 @@
 
         // $$lectus porta consequ$t...  LOReM iPSuM|
         Selection.setSelection(mEditable, mEditable.length());
-        assertSelection(155);
+        verifySelection(155);
 
         // $$lectus porta consequ$t...  LOReM |iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(150);
+        verifySelection(150);
 
         // $$lectus porta consequ$t...  |LOReM iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(144);
+        verifySelection(144);
 
         // $$lectus porta |consequ$t...  LOReM iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(130);
+        verifySelection(130);
 
         // $$lectus |porta consequ$t...  LOReM iPSuM
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(124);
+        verifySelection(124);
 
         // integ$r. Etiam    tristique$tortor nec   ?:?    $$|lectus
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(117);
+        verifySelection(117);
 
         // integ$r. Etiam    tristique$tortor |nec   ?:?    $$lectus
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(102);
+        verifySelection(102);
 
         // integ$r. Etiam    tristique$|tortor nec   ?:?    $$lectus
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(95);
+        verifySelection(95);
 
         // integ$r. Etiam    |tristique$tortor nec   ?:?    $$lectus
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(85);
+        verifySelection(85);
 
         // integ$r. |Etiam    tristique$tortor nec   ?:?    $$lectus
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(76);
+        verifySelection(76);
 
         // TODO: enable these two additional word breaks when implemented
 //        // dolor sit $met, conse$_$ctetur$       Adipiscing.elit.|integ$r.
 //        assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-//        assertSelection(67);
+//        verifySelection(67);
 //
 //        // dolor sit $met, conse$_$ctetur$       Adipiscing.|elit.integ$r.
 //        assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-//        assertSelection(62);
+//        verifySelection(62);
 
         // dolor sit $met, conse$_$ctetur$       |Adipiscing.elit.integ$r.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(51);
+        verifySelection(51);
 
         // dolor sit $met, |conse$_$ctetur$       Adipiscing.elit.integ$r.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(29);
+        verifySelection(29);
 
         // dolor sit |$met, conse$_$ctetur$       Adipiscing.elit.integ$r.
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(23);
+        verifySelection(23);
 
         // Lorem ipsum; dolor |sit $met
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(19);
+        verifySelection(19);
 
         // Lorem ipsum; |dolor sit $met
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(13);
+        verifySelection(13);
 
         // Lorem |ipsum; dolor sit $met
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(6);
+        verifySelection(6);
 
         // |Lorem ipsum; dolor sit $met
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
 
         // keep trying to push before beginning, which should fail
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
 
     }
 
@@ -1195,176 +1220,181 @@
             "Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4";
 
     @UiThreadTest
+    @Test
     public void testFollowingWordStartToEndWithNumbers() {
 
         initTextViewWithNullLayout(TEXT_WORDS_WITH_NUMBERS);
 
         // |Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4
         Selection.setSelection(mEditable, 0);
-        assertSelection(0);
+        verifySelection(0);
 
         // Lorem| ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(5);
+        verifySelection(5);
 
         // Lorem ipsum123,456.90|   dolor sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(21);
+        verifySelection(21);
 
         // Lorem ipsum123,456.90   dolor| sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(29);
+        verifySelection(29);
 
         // Lorem ipsum123,456.90   dolor sit|.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(33);
+        verifySelection(33);
 
         // Lorem ipsum123,456.90   dolor sit.. 4|-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(37);
+        verifySelection(37);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0|=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(41);
+        verifySelection(41);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0=2| ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(43);
+        verifySelection(43);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4|
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(55);
+        verifySelection(55);
 
         // keep trying to push beyond end, which should fail
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(55);
+        verifySelection(55);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(55);
+        verifySelection(55);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(55);
+        verifySelection(55);
 
     }
 
     @UiThreadTest
+    @Test
     public void testFollowingWordEndToStartWithNumbers() {
 
         initTextViewWithNullLayout(TEXT_WORDS_WITH_NUMBERS);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4|
         Selection.setSelection(mEditable, mEditable.length());
-        assertSelection(55);
+        verifySelection(55);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 |ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(44);
+        verifySelection(44);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-0.0=|2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(42);
+        verifySelection(42);
 
         // Lorem ipsum123,456.90   dolor sit.. 4-|0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(38);
+        verifySelection(38);
 
         // Lorem ipsum123,456.90   dolor sit.. |4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(36);
+        verifySelection(36);
 
         // Lorem ipsum123,456.90   dolor |sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(30);
+        verifySelection(30);
 
         // Lorem ipsum123,456.90   |dolor sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(24);
+        verifySelection(24);
 
         // Lorem |ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(6);
+        verifySelection(6);
 
         // |Lorem ipsum123,456.90   dolor sit.. 4-0.0=2 ADipiscing4
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
 
         // keep trying to push before beginning, which should fail
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
 
     }
 
     private static final String TEXT_WORDS_WITH_1CHAR_FINAL_WORD = "abc d";
 
     @UiThreadTest
+    @Test
     public void testFollowingWordStartToEndWithOneCharFinalWord() {
 
         initTextViewWithNullLayout(TEXT_WORDS_WITH_1CHAR_FINAL_WORD);
 
         // |abc d
         Selection.setSelection(mEditable, 0);
-        assertSelection(0);
+        verifySelection(0);
 
         // abc| d
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(3);
+        verifySelection(3);
 
         // abc d|
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertSelection(mEditable.length());
+        verifySelection(mEditable.length());
 
     }
 
     @UiThreadTest
+    @Test
     public void testFollowingWordEndToStartWithOneCharFinalWord() {
 
         initTextViewWithNullLayout(TEXT_WORDS_WITH_1CHAR_FINAL_WORD);
 
         // abc d|
         Selection.setSelection(mEditable, mEditable.length());
-        assertSelection(5);
+        verifySelection(5);
 
         // abc |d
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(4);
+        verifySelection(4);
 
         // |abc d
         assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertSelection(0);
+        verifySelection(0);
 
     }
 
     @UiThreadTest
+    @Test
     public void testMovementFromMiddleOfWord() {
 
         initTextViewWithNullLayout("before word after");
-        checkMoveFromInsideWord(7, 10);
+        verifyMoveFromInsideWord(7, 10);
 
         // Surrogate characters: bairkan should be considered as a standard letter
         final String BAIRKAN = "\uD800\uDF31";
 
         initTextViewWithNullLayout("before wo" + BAIRKAN + "rd after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
 
         initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + "xx after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
 
         initTextViewWithNullLayout("before xx" + BAIRKAN + BAIRKAN + " after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
 
         initTextViewWithNullLayout("before x" + BAIRKAN + "x" + BAIRKAN + " after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
 
         initTextViewWithNullLayout("before " + BAIRKAN + "x" + BAIRKAN + "x after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
 
         initTextViewWithNullLayout("before " + BAIRKAN + BAIRKAN + BAIRKAN + " after");
-        checkMoveFromInsideWord(7, 12);
+        verifyMoveFromInsideWord(7, 12);
     }
 
-    private void checkMoveFromInsideWord(int wordStart, int wordEnd) {
+    private void verifyMoveFromInsideWord(int wordStart, int wordEnd) {
 
         CharSequence text = mTextView.getText();
 
@@ -1376,7 +1406,7 @@
             }
             Selection.setSelection(mEditable, offset);
             assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_RIGHT));
-            assertSelection(wordEnd + 1);
+            verifySelection(wordEnd + 1);
         }
 
         // Check preceding always goes at the beginning of the word
@@ -1386,7 +1416,7 @@
             }
             Selection.setSelection(mEditable, offset);
             assertTrue(pressCtrlChord(KeyEvent.KEYCODE_DPAD_LEFT));
-            assertSelection(wordStart);
+            verifySelection(wordStart);
         }
     }
 
@@ -1395,7 +1425,7 @@
     }
 
     private void initTextViewWithNullLayout(CharSequence text) {
-        mTextView = new TextViewNoIme(getActivity());
+        mTextView = new TextViewNoIme(mActivityRule.getActivity());
         mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
         mTextView.setText(text, BufferType.EDITABLE);
         assertNull(mTextView.getLayout());
@@ -1430,19 +1460,19 @@
         return mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable, keyCode, keyEvent);
     }
 
-    private void assertSelection(int expectedPosition) {
-        assertSelection(expectedPosition, expectedPosition);
+    private void verifySelection(int expectedPosition) {
+        verifySelection(expectedPosition, expectedPosition);
     }
 
-    private void assertSelection(int expectedStart, int expectedEnd) {
+    private void verifySelection(int expectedStart, int expectedEnd) {
         final int actualStart = Selection.getSelectionStart(mEditable);
         final int actualEnd = Selection.getSelectionEnd(mEditable);
 
-        assertCharSequenceIndexEquals(mEditable, expectedStart, actualStart);
-        assertCharSequenceIndexEquals(mEditable, expectedEnd, actualEnd);
+        verifyCharSequenceIndexEquals(mEditable, expectedStart, actualStart);
+        verifyCharSequenceIndexEquals(mEditable, expectedEnd, actualEnd);
     }
 
-    private static void assertCharSequenceIndexEquals(CharSequence text, int expected, int actual) {
+    private static void verifyCharSequenceIndexEquals(CharSequence text, int expected, int actual) {
         final String message = "expected <" + getCursorSnippet(text, expected) + "> but was <"
                 + getCursorSnippet(text, actual) + ">";
         assertEquals(message, expected, actual);
@@ -1457,26 +1487,26 @@
         }
     }
 
-    private void assertSelectEndOfContent() {
+    private void verifySelectEndOfContent() {
         Selection.removeSelection(mEditable);
         mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_DOWN);
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         Selection.removeSelection(mEditable);
         mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_RIGHT);
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
-        assertSelectEndOfContentExceptFocusForward();
+        verifySelectEndOfContentExceptFocusForward();
     }
 
-    private void assertSelectEndOfContentExceptFocusForward() {
+    private void verifySelectEndOfContentExceptFocusForward() {
         Selection.removeSelection(mEditable);
         mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
 
         Selection.removeSelection(mEditable);
         mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_LEFT);
-        assertSelection(END_OF_ALL_TEXT);
+        verifySelection(END_OF_ALL_TEXT);
     }
 
     private static class MyMetaKeyKeyListener extends MetaKeyKeyListener {
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..3f35371 100644
--- a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
@@ -16,15 +16,23 @@
 
 package android.text.method.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.method.BaseKeyListener;
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test backspace key handling of {@link android.text.method.BaseKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class BackspaceTest extends KeyListenerTestCase {
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
@@ -34,23 +42,17 @@
 
     // 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);
-            }
+    private void backspace(final EditorState state, int modifiers) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent));
         mInstrumentation.waitForIdleSync();
 
         state.mText = mTextView.getText();
@@ -58,8 +60,33 @@
         state.mSelectionEnd = mTextView.getSelectionEnd();
     }
 
-    @SmallTest
-    public void testSurrogatePairs() {
+    @Test
+    public void testCRLF() throws Throwable {
+        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("|");
+    }
+
+    @Test
+    public void testSurrogatePairs() throws Throwable {
         EditorState state = new EditorState();
 
         state.setByString("U+1F441 |");
@@ -73,8 +100,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testReplacementSpan() {
+    @Test
+    public void testReplacementSpan() throws Throwable {
         EditorState state = new EditorState();
 
         // ReplacementSpan will be set to "()" region.
@@ -115,8 +142,8 @@
         state.assertEquals("| 'g'");
     }
 
-    @SmallTest
-    public void testCombiningEnclosingKeycaps() {
+    @Test
+    public void testCombiningEnclosingKeycaps() throws Throwable {
         EditorState state = new EditorState();
 
         // U+20E3 is COMBINING ENCLOSING KEYCAP.
@@ -130,8 +157,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testVariationSelector() {
+    @Test
+    public void testVariationSelector() throws Throwable {
         EditorState state = new EditorState();
 
         // U+FE0F is VARIATION SELECTOR-16.
@@ -145,8 +172,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testFlags() {
+    @Test
+    public void testFlags() throws Throwable {
         EditorState state = new EditorState();
 
         // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
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..91618b9 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -16,37 +16,43 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 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;
 import android.widget.TextView.BufferType;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link android.text.method.BaseKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 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());
+    @Test
+    public void testBackspace() throws Throwable {
+        verifyBackspace(0);
     }
 
-    public void testBackspace() {
-        testBackspace(0);
-    }
-
-    private void testBackspace(int modifiers) {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    private void verifyBackspace(int modifiers) throws Throwable {
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
         final KeyEvent event = getKey(KeyEvent.KEYCODE_DEL, modifiers);
         Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
 
@@ -103,12 +109,14 @@
         assertEquals("\u05D6\u05D4\u0020Anroid\u0020\u05E2\u05D5\u05D1", content.toString());
     }
 
-    public void testBackspace_withShift() {
-        testBackspace(KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
+    @Test
+    public void testBackspace_withShift() throws Throwable {
+        verifyBackspace(KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
     }
 
-    public void testBackspace_withAlt() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    @Test
+    public void testBackspace_withAlt() throws Throwable {
+        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...
@@ -131,42 +139,46 @@
         assertEquals("", content.toString());
     }
 
-    public void testBackspace_withSendKeys() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    @Test
+    public void testBackspace_withSendKeys() throws Throwable {
+        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());
     }
 
-    private void assertCursorPosition(Editable content, int offset) {
+    private void verifyCursorPosition(Editable content, int offset) {
         assertEquals(offset, Selection.getSelectionStart(content));
         assertEquals(offset, Selection.getSelectionEnd(content));
     }
 
-    public void testBackspace_withCtrl() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    @Test
+    public void testBackspace_withCtrl() throws Throwable {
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // If the contents only having symbolic characters, delete all characters.
         String testText = "!#$%&'()`{*}_?+";
@@ -174,7 +186,7 @@
         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Latin ASCII text
         testText = "Hello, World. This is Android.";
@@ -184,32 +196,32 @@
         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World. This is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World. This is ", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World. This ", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World. ", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, ", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Latin ASCII, cursor is middle of the text.
         testText = "Hello, World. This is Android.";
@@ -220,19 +232,19 @@
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World.  is Android.", content.toString());
-        assertCursorPosition(content, content.toString().length() - charsFromTail);
+        verifyCursorPosition(content, content.toString().length() - charsFromTail);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello,  is Android.", content.toString());
-        assertCursorPosition(content, content.toString().length() - charsFromTail);
+        verifyCursorPosition(content, content.toString().length() - charsFromTail);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals(" is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals(" is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Latin ASCII, cursor is inside word.
         testText = "Hello, World. This is Android.";
@@ -244,19 +256,19 @@
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, World. is is Android.", content.toString());
-        assertCursorPosition(content, content.toString().length() - charsFromTail);
+        verifyCursorPosition(content, content.toString().length() - charsFromTail);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("Hello, is is Android.", content.toString());
-        assertCursorPosition(content, content.toString().length() - charsFromTail);
+        verifyCursorPosition(content, content.toString().length() - charsFromTail);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("is is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("is is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Hebrew Text
         // The deletion works on a Logical direction basis.
@@ -268,24 +280,24 @@
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020" +
                      "\u05D6\u05D4\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020",
                      content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05E9\u05DC\u05D5\u05DD\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // BiDi Text
         // The deletion works on a Logical direction basis.
@@ -297,31 +309,32 @@
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1" +
                      "\u05D3\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020\u0041Android\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05D6\u05D4\u0020\u05DC\u002D\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("\u05D6\u05D4\u0020", content.toString());
-        assertCursorPosition(content, content.toString().length());
+        verifyCursorPosition(content, content.toString().length());
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlBackspace(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
     }
 
-    public void testForwardDelete_withCtrl() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    @Test
+    public void testForwardDelete_withCtrl() throws Throwable {
+        final BaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // If the contents only having symbolic characters, delete all characters.
         String testText = "!#$%&'()`{*}_?+";
@@ -329,7 +342,7 @@
         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Latin ASCII text
         testText = "Hello, World. This is Android.";
@@ -339,36 +352,36 @@
         prepTextViewSync(content, mockBaseKeyListener, false, testText.length(), testText.length());
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. This is Android.", content.toString());
-        assertCursorPosition(content, testText.length());
+        verifyCursorPosition(content, testText.length());
 
         prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals(", World. This is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals(". This is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals(" is Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals(" Android.", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals(".", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // Latin ASCII, cursor is middle of the text.
         testText = "Hello, World. This is Android.";
@@ -378,23 +391,23 @@
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World.  is Android.", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World.  Android.", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. .", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. ", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. ", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         // Latin ASCII, cursor is inside word.
         testText = "Hello, World. This is Android.";
@@ -404,23 +417,23 @@
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. Th is Android.", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. Th Android.", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. Th.", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. Th", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("Hello, World. Th", content.toString());
-        assertCursorPosition(content, charsFromHead);
+        verifyCursorPosition(content, charsFromHead);
 
         // Hebrew Text
         // The deletion works on a Logical direction basis.
@@ -432,29 +445,29 @@
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u0020\u05D4\u05E2\u05D5\u05DC\u05DD\u002E\u0020\u05D6\u05D4\u0020\u05D0" +
                      "\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u002E\u0020\u05D6\u05D4\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9" +
                 "\u05D3\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u0020\u05D0\u05E0\u05D3\u05E8\u05D5\u05D0\u05D9\u05D3\u002E",
                      content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         // BiDi Text
         // The deletion works on a Logical direction basis.
@@ -466,33 +479,33 @@
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u0020\u05DC\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020" +
                      "\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u002D\u0020\u0041Android\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9" +
                      "\u05D8\u05D1\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u0020\u05E2\u05D5\u05D1\u05D3\u0020\u05D4\u05D9\u05D8\u05D1\u002E",
                      content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u0020\u05D4\u05D9\u05D8\u05D1\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("\u002E", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
 
         executeCtrlForwardDelete(content, mockBaseKeyListener);
         assertEquals("", content.toString());
-        assertCursorPosition(content, 0);
+        verifyCursorPosition(content, 0);
     }
 
     /*
@@ -501,42 +514,67 @@
      * 2. Set a selection and press DEL key, the selection is deleted.
      * 3. ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting the event's text into the content.
      */
-    public void testPressKey() {
-        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+    @Test
+    public void testPressKey() throws Throwable {
+        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) {
+    @Test
+    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);
@@ -547,35 +585,20 @@
      * the UI thread.
      */
     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);
-            }
+            final boolean selectInTextView, final int selectionStart, final int selectionEnd)
+                    throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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..aeff39d
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.Instrumentation;
+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 com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link BaseMovementMethod}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BaseMovementMethodTest {
+    private Instrumentation mInstrumentation;
+    private BaseMovementMethod mMovementMethod;
+    private TextView mTextView;
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mMovementMethod = new BaseMovementMethod();
+    }
+
+    @Test
+    public void testOnGenericMotionEvent_horizontalScroll() throws Throwable {
+        final String testLine = "some text some text";
+        final String testString = testLine + "\n" + testLine;
+
+        mActivityRule.runOnUiThread(() -> mTextView = createTextView());
+        // limit lines for horizontal scroll
+        mTextView.setSingleLine();
+        mTextView.setText(testString, EDITABLE);
+
+        // limit width for horizontal scroll
+
+        setContentView(mTextView, (int) mTextView.getPaint().measureText(testLine) / 3);
+        // assert the default scroll position
+        assertEquals(0, mTextView.getScrollX());
+
+        final Spannable text = (Spannable) mTextView.getText();
+        final double lineSpacing = Math.ceil(mTextView.getPaint().getFontSpacing());
+
+        // scroll right
+        MotionEvent event = createScrollEvent(1, 0);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(lineSpacing, mTextView.getScrollX(), lineSpacing / 4);
+        event.recycle();
+
+        // scroll left
+        event = createScrollEvent(-1, 0);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(0, mTextView.getScrollX());
+        event.recycle();
+
+        // cannot scroll to left
+        event = createScrollEvent(-1, 0);
+        assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        event.recycle();
+
+        // cannot scroll to right
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
+                () -> mTextView.scrollTo((int) mTextView.getLayout().getLineWidth(0), 0));
+        event = createScrollEvent(1, 0);
+        assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        event.recycle();
+
+        // meta shift on
+        // reset scroll
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
+                () -> mTextView.scrollTo(0, 0));
+
+        // scroll top becomes scroll right
+        event = createScrollEvent(0, 1, KeyEvent.META_SHIFT_ON);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(lineSpacing, mTextView.getScrollX(), lineSpacing / 4);
+        event.recycle();
+
+        // scroll down becomes scroll left
+        event = createScrollEvent(0, -1, KeyEvent.META_SHIFT_ON);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(0, mTextView.getScrollX());
+        event.recycle();
+    }
+
+    @Test
+    public void testOnGenericMotionEvent_verticalScroll() throws Throwable {
+        final String testLine = "some text some text";
+        final String testString = testLine + "\n" + testLine;
+
+        mActivityRule.runOnUiThread(() -> mTextView = createTextView());
+        // limit lines for vertical scroll
+        mTextView.setMaxLines(1);
+        mTextView.setText(testString, EDITABLE);
+        setContentView(mTextView, WRAP_CONTENT);
+        // assert the default scroll positions
+        assertEquals(0, mTextView.getScrollY());
+
+        final Spannable text = (Spannable) mTextView.getText();
+        final int lineHeight = mTextView.getLineHeight();
+
+        // scroll down
+        MotionEvent event = createScrollEvent(0, -1);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(lineHeight, mTextView.getScrollY(), lineHeight / 4);
+        event.recycle();
+
+        // scroll up
+        event = createScrollEvent(0, 1);
+        assertTrue(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView, null);
+        assertEquals(0, mTextView.getScrollY());
+        event.recycle();
+
+        // cannot scroll up
+        event = createScrollEvent(0, 1);
+        assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, text, event));
+        event.recycle();
+
+        // cannot scroll down
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mTextView,
+                () -> mTextView.scrollTo(0, mTextView.getLayout().getHeight()));
+        event = createScrollEvent(0, -1);
+        assertFalse(mMovementMethod.onGenericMotionEvent(mTextView, 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) throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
+        final FrameLayout layout = new FrameLayout(activity);
+        layout.addView(textView, new ViewGroup.LayoutParams(textWidth, WRAP_CONTENT));
+
+        mActivityRule.runOnUiThread(() -> {
+            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/CharacterPickerDialogTest.java b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
index b348c28..fda8469 100644
--- a/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
+++ b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
@@ -16,50 +16,59 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.method.CharacterPickerDialog;
 import android.view.View;
 import android.widget.Gallery;
 
-public class CharacterPickerDialogTest extends
-        ActivityInstrumentationTestCase2<CtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CharacterPickerDialogTest {
     private Activity mActivity;
 
-    public CharacterPickerDialogTest() {
-        super("android.text.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() {
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         final CharSequence str = "123456";
         final Editable content = Editable.Factory.getInstance().newEditable(str);
         final View view = new TextViewNoIme(mActivity);
         new CharacterPickerDialog(view.getContext(), view, content, "\u00A1", false);
-
-        try {
-            new CharacterPickerDialog(null, view, content, "\u00A1", false);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected.
-        }
-    }
-
-    public void testOnCreate() {
-        // Do not test. Implementation details.
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        final CharSequence str = "123456";
+        final Editable content = Editable.Factory.getInstance().newEditable(str);
+        final View view = new TextViewNoIme(mActivity);
+        new CharacterPickerDialog(null, view, content, "\u00A1", false);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnItemClick() {
         final Gallery parent = new Gallery(mActivity);
         final CharSequence str = "123456";
@@ -102,6 +111,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnClick() {
         final CharSequence str = "123456";
         final Editable content = Editable.Factory.getInstance().newEditable(str);
@@ -114,6 +124,5 @@
 
         // nothing to test here, just make sure onClick does not throw exception
         characterPickerDialog.onClick(view);
-
     }
 }
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..397b6f7 100644
--- a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
@@ -16,28 +16,34 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.method.DateKeyListener;
 import android.view.KeyEvent;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link android.text.method.DateKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class DateKeyListenerTest extends KeyListenerTestCase {
-
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
+    @Test
     public void testConstructor() {
         new DateKeyListener();
     }
 
+    @Test
     public void testGetInstance() {
         DateKeyListener listener1 = DateKeyListener.getInstance();
         DateKeyListener listener2 = DateKeyListener.getInstance();
@@ -47,13 +53,14 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetAcceptedChars() {
         MockDateKeyListener mockDateKeyListener = new MockDateKeyListener();
 
-        TextMethodUtils.assertEquals(DateKeyListener.CHARACTERS,
-                mockDateKeyListener.getAcceptedChars());
+        assertArrayEquals(DateKeyListener.CHARACTERS, mockDateKeyListener.getAcceptedChars());
     }
 
+    @Test
     public void testGetInputType() {
         DateKeyListener dateKeyListener = new DateKeyListener();
 
@@ -70,6 +77,7 @@
      * 5. Press '/' key and check if the content of TextView becomes "12-/"
      * 6. remove DateKeyListener and Press '/' key, this key will not be accepted
      */
+    @Test
     public void testDateTimeKeyListener() {
         final DateKeyListener dateKeyListener = DateKeyListener.getInstance();
 
@@ -77,26 +85,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 +112,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..e0647f5 100644
--- a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
@@ -16,29 +16,35 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.method.DateTimeKeyListener;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link android.text.method.DateTimeKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class DateTimeKeyListenerTest extends KeyListenerTestCase {
-
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
+    @Test
     public void testConstructor() {
         new DateTimeKeyListener();
     }
 
+    @Test
     public void testGetInstance() {
         DateTimeKeyListener listener1 = DateTimeKeyListener.getInstance();
         DateTimeKeyListener listener2 = DateTimeKeyListener.getInstance();
@@ -48,13 +54,15 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetAcceptedChars() {
         MockDateTimeKeyListener mockDateTimeKeyListener = new MockDateTimeKeyListener();
 
-        TextMethodUtils.assertEquals(DateTimeKeyListener.CHARACTERS,
+        assertArrayEquals(DateTimeKeyListener.CHARACTERS,
                 mockDateTimeKeyListener.getAcceptedChars());
     }
 
+    @Test
     public void testGetInputType() {
         DateTimeKeyListener listener = DateTimeKeyListener.getInstance();
 
@@ -73,6 +81,7 @@
      * 6. Press an unaccepted key if it exists. and this key will not be accepted.
      * 7. Remove DateKeyListener and Press '1' key, this key will not be accepted
      */
+    @Test
     public void testDateTimeKeyListener() {
         final DateTimeKeyListener dateTimeKeyListener = DateTimeKeyListener.getInstance();
         setKeyListenerSync(dateTimeKeyListener);
@@ -80,12 +89,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 +102,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 +131,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/DialerKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
index 219869c..7808824 100644
--- a/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
@@ -16,25 +16,40 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.method.DialerKeyListener;
 import android.view.KeyEvent;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link android.text.method.DialerKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class DialerKeyListenerTest extends KeyListenerTestCase {
+    @Test
     public void testConstructor() {
         new DialerKeyListener();
     }
 
+    @Test
     public void testLookup() {
         MockDialerKeyListener mockDialerKeyListener = new MockDialerKeyListener();
-        final int[] events = { KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_A };
+        final int[] events = {KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_A};
         SpannableString span = new SpannableString(""); // no meta spans
-        for (int event: events) {
+        for (int event : events) {
             KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, event);
             int keyChar = keyEvent.getNumber();
             if (keyChar != 0) {
@@ -43,14 +58,16 @@
                 // cannot make any assumptions how the key code gets translated
             }
         }
-
-        try {
-            mockDialerKeyListener.lookup(null, span);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testLookupNull() {
+        MockDialerKeyListener mockDialerKeyListener = new MockDialerKeyListener();
+        SpannableString span = new SpannableString(""); // no meta spans
+        mockDialerKeyListener.lookup(null, span);
+    }
+
+    @Test
     public void testGetInstance() {
         assertNotNull(DialerKeyListener.getInstance());
 
@@ -62,13 +79,15 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetAcceptedChars() {
         MockDialerKeyListener mockDialerKeyListener = new MockDialerKeyListener();
 
-        TextMethodUtils.assertEquals(DialerKeyListener.CHARACTERS,
+        assertArrayEquals(DialerKeyListener.CHARACTERS,
                 mockDialerKeyListener.getAcceptedChars());
     }
 
+    @Test
     public void testGetInputType() {
         DialerKeyListener listener = DialerKeyListener.getInstance();
 
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..7ea5f7e 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,14 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -24,19 +31,18 @@
 import android.text.method.DigitsKeyListener;
 import android.view.KeyEvent;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link DigitsKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class DigitsKeyListenerTest extends KeyListenerTestCase {
-
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
+    @Test
     public void testConstructor() {
         new DigitsKeyListener();
 
@@ -53,6 +59,7 @@
      * 5. filter Spanned("-a1.b2c3d"), return Spanned("123") and copy spans.
      * 6. filter "", return null
      */
+    @Test
     public void testFilter1() {
         String source = "123456";
         String destString = "dest string";
@@ -110,6 +117,7 @@
      * 13. filter "-123456" but dest has '-' before dstart, return "123456"
      * 14. filter "+123456" but dest has '-' before dstart, return "123456"
      */
+    @Test
     public void testFilter2() {
         String source = "-123456";
         String destString = "dest string without sign and decimal";
@@ -208,6 +216,7 @@
      * 8. filter "123.456" but dest has '.' after dend, return "123456"
      * 9. filter "123.456" but dest has '.' before dstart, return "123456"
      */
+    @Test
     public void testFilter3() {
         String source = "123.456";
         String destString = "dest string without sign and decimal";
@@ -287,6 +296,7 @@
      * 16. filter "-123.456" but dest has '-' before dstart, return "123.456"
      * 17. filter "+123.456" but dest has '-' before dstart, return "123.456"
      */
+    @Test
     public void testFilter4() {
         String source = "-123.456";
         String destString = "dest string without sign and decimal";
@@ -396,6 +406,7 @@
      *  3. Press '.' key and this key could not be accepted.
      *  4. Press '2' key and check if the content of TextView becomes "12"
      */
+    @Test
     public void testDigitsKeyListener1() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance();
 
@@ -403,19 +414,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());
     }
 
@@ -430,6 +441,7 @@
      *  6. Press '-' key and this key could not be accepted,
      *     because text view accepts minus sign iff it at the beginning.
      */
+    @Test
     public void testDigitsKeyListener2() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(true, false);
 
@@ -437,27 +449,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());
     }
 
@@ -472,6 +484,7 @@
      *  6. Press '.' key and this key could not be accepted,
      *     because text view accepts only one decimal point per field.
      */
+    @Test
     public void testDigitsKeyListener3() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(false, true);
 
@@ -479,27 +492,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());
     }
 
@@ -516,6 +529,7 @@
      *  6. Press '.' key and this key could not be accepted,
      *     because text view accepts only one decimal point per field.
      */
+    @Test
     public void testDigitsKeyListener4() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(true, true);
 
@@ -523,27 +537,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());
     }
 
@@ -556,7 +570,8 @@
      *  4. Press '-' key and this key could not be accepted.
      *  5. remove DigitsKeyListener and Press '5' key, this key will not be accepted
      */
-    public void testDigitsKeyListener5() {
+    @Test
+    public void testDigitsKeyListener5() throws Throwable {
         final String accepted = "56789";
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(accepted);
 
@@ -564,36 +579,35 @@
         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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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());
     }
 
+    @Test
     public void testGetInstance1() {
         DigitsKeyListener listener1 = DigitsKeyListener.getInstance();
         DigitsKeyListener listener2 = DigitsKeyListener.getInstance();
@@ -603,6 +617,7 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetInstance2() {
         DigitsKeyListener listener1 = DigitsKeyListener.getInstance(true, true);
         DigitsKeyListener listener2 = DigitsKeyListener.getInstance(true, true);
@@ -619,6 +634,7 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetInstance3() {
         DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance("abcdefg");
         assertNotNull(digitsKeyListener);
@@ -627,6 +643,7 @@
         assertNotNull(digitsKeyListener);
     }
 
+    @Test
     public void testGetAcceptedChars() {
         MockDigitsKeyListener mockDigitsKeyListener = new MockDigitsKeyListener();
 
@@ -637,18 +654,19 @@
             new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+', '.' },
         };
 
-        TextMethodUtils.assertEquals(expected[0], mockDigitsKeyListener.getAcceptedChars());
+        assertArrayEquals(expected[0], mockDigitsKeyListener.getAcceptedChars());
 
         mockDigitsKeyListener = new MockDigitsKeyListener(true, false);
-        TextMethodUtils.assertEquals(expected[1], mockDigitsKeyListener.getAcceptedChars());
+        assertArrayEquals(expected[1], mockDigitsKeyListener.getAcceptedChars());
 
         mockDigitsKeyListener = new MockDigitsKeyListener(false, true);
-        TextMethodUtils.assertEquals(expected[2], mockDigitsKeyListener.getAcceptedChars());
+        assertArrayEquals(expected[2], mockDigitsKeyListener.getAcceptedChars());
 
         mockDigitsKeyListener = new MockDigitsKeyListener(true, true);
-        TextMethodUtils.assertEquals(expected[3], mockDigitsKeyListener.getAcceptedChars());
+        assertArrayEquals(expected[3], mockDigitsKeyListener.getAcceptedChars());
     }
 
+    @Test
     public void testGetInputType() {
         DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(false, false);
         int expected = InputType.TYPE_CLASS_NUMBER;
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..12ce7a6 100644
--- a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
@@ -16,15 +16,23 @@
 
 package android.text.method.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.method.BaseKeyListener;
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test forward delete key handling of  {@link android.text.method.BaseKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ForwardDeleteTest extends KeyListenerTestCase {
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
@@ -34,23 +42,17 @@
 
     // 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);
-            }
+    private void forwardDelete(final EditorState state, int modifiers) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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();
@@ -58,8 +60,32 @@
         state.mSelectionEnd = mTextView.getSelectionEnd();
     }
 
-    @SmallTest
-    public void testSurrogatePairs() {
+    @Test
+    public void testCRLF() throws Throwable {
+        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);
+    }
+
+    @Test
+    public void testSurrogatePairs() throws Throwable {
         EditorState state = new EditorState();
 
         // U+1F441 is EYE
@@ -75,8 +101,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testReplacementSpan() {
+    @Test
+    public void testReplacementSpan() throws Throwable {
         EditorState state = new EditorState();
 
         state.setByString("| 'abc' ( 'de' ) 'fg'");
@@ -112,8 +138,8 @@
         state.assertEquals("'ab' |");
     }
 
-    @SmallTest
-    public void testCombiningEnclosingKeycaps() {
+    @Test
+    public void testCombiningEnclosingKeycaps() throws Throwable {
         EditorState state = new EditorState();
 
         // U+20E3 is COMBINING ENCLOSING KEYCAP.
@@ -126,8 +152,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testVariationSelector() {
+    @Test
+    public void testVariationSelector() throws Throwable {
         EditorState state = new EditorState();
 
         // U+FE0F is VARIATION SELECTOR-16.
@@ -141,8 +167,8 @@
         state.assertEquals("|");
     }
 
-    @SmallTest
-    public void testFlags() {
+    @Test
+    public void testFlags() throws Throwable {
         EditorState state = new EditorState();
 
         // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
diff --git a/tests/tests/text/src/android/text/method/cts/HideReturnsTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/HideReturnsTransformationMethodTest.java
index d789c92..df48458 100644
--- a/tests/tests/text/src/android/text/method/cts/HideReturnsTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/HideReturnsTransformationMethodTest.java
@@ -16,24 +16,35 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.HideReturnsTransformationMethod;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link HideReturnsTransformationMethod}.
  */
-public class HideReturnsTransformationMethodTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HideReturnsTransformationMethodTest {
+    @Test
     public void testConstructor() {
         new HideReturnsTransformationMethod();
     }
 
+    @Test
     public void testGetOriginal() {
         MyHideReturnsTranformationMethod method = new MyHideReturnsTranformationMethod();
-        TextMethodUtils.assertEquals(new char[] { '\r' }, method.getOriginal());
+        assertArrayEquals(new char[] { '\r' }, method.getOriginal());
     }
 
+    @Test
     public void testGetInstance() {
         HideReturnsTransformationMethod method0 = HideReturnsTransformationMethod.getInstance();
         assertNotNull(method0);
@@ -42,9 +53,10 @@
         assertSame(method0, method1);
     }
 
+    @Test
     public void testGetReplacement() {
         MyHideReturnsTranformationMethod method = new MyHideReturnsTranformationMethod();
-        TextMethodUtils.assertEquals(new char[] { '\uFEFF' }, method.getReplacement());
+        assertArrayEquals(new char[] { '\uFEFF' }, method.getReplacement());
     }
 
     private static class MyHideReturnsTranformationMethod extends HideReturnsTransformationMethod {
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
index c14f463..9c96519 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
@@ -16,11 +16,10 @@
 
 package android.text.method.cts;
 
-import android.text.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.text.cts.R;
 import android.text.method.BaseKeyListener;
 import android.text.method.DateKeyListener;
 import android.text.method.DateTimeKeyListener;
@@ -57,7 +56,7 @@
 
 public class KeyListenerCtsActivity extends Activity {
     private boolean mHasWindowFocus = false;
-    private Object mHasWindowFocusLock = new Object();
+    private final Object mHasWindowFocusLock = new Object();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
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..8d47c57 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
@@ -16,72 +16,45 @@
 
 package android.text.method.cts;
 
-import android.text.cts.R;
-
 import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
-import android.text.format.DateUtils;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.text.cts.R;
 import android.text.method.KeyListener;
 import android.view.KeyEvent;
 import android.widget.EditText;
 
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+
 /**
  * Base class for various KeyListener tests.
- * {@link BaseKeyListenerTest}
- * {@link DateKeyListenerTest}
- * {@link DateTimeKeyListenerTest}
- * {@link DigitsKeyListenerTest}
- * {@link MultiTapKeyListenerTest}
- * {@link NumberKeyListenerTest}
- * {@link QwertyKeyListenerTest}
- * {@link TextKeyKeyListenerTest}
- *
- * @see BaseKeyListenerTest
- * @see DateKeyListenerTest
- * @see DateTimeKeyListenerTest
- * @see DigitsKeyListenerTest
- * @see MultiTapKeyListenerTest
- * @see NumberKeyListenerTest
- * @see QwertyKeyListenerTest
- * @see TextKeyKeyListenerTest
  */
-public abstract class KeyListenerTestCase extends
-        ActivityInstrumentationTestCase2<KeyListenerCtsActivity> {
+public abstract class KeyListenerTestCase {
     protected KeyListenerCtsActivity mActivity;
     protected Instrumentation mInstrumentation;
     protected EditText mTextView;
 
-    public KeyListenerTestCase() {
-        super("com.android.cts.text", KeyListenerCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<KeyListenerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(KeyListenerCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         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);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
+        PollingCheck.waitFor(5000, mActivity::hasWindowFocus);
     }
 
     /**
      * 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..31bc16b 100644
--- a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
@@ -16,10 +16,25 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+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 android.app.Activity;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -34,6 +49,11 @@
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link LinkMovementMethod}. The class is an implementation of interface
  * {@link MovementMethod}. The typical usage of {@link MovementMethod} is tested in
@@ -42,39 +62,33 @@
  *
  * @see android.widget.cts.TextViewTest
  */
-public class LinkMovementMethodTest extends
-        ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LinkMovementMethodTest {
     private static final String CONTENT = "clickable\nunclickable\nclickable";
 
+    private Activity mActivity;
     private LinkMovementMethod mMethod;
-
     private TextView mView;
-
     private Spannable mSpannable;
+    private ClickableSpan mClickable0;
+    private ClickableSpan mClickable1;
 
-    private MockClickableSpan mClickable0;
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
 
-    private MockClickableSpan mClickable1;
-
-    public LinkMovementMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() throws Throwable {
+        mActivity = mActivityRule.getActivity();
         mMethod = new LinkMovementMethod();
 
         // Set the content view with a text view which contains 3 lines,
-        mView = new TextViewNoIme(getActivity());
+        mActivityRule.runOnUiThread(() -> mView = new TextViewNoIme(mActivity));
         mView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
         mView.setText(CONTENT, BufferType.SPANNABLE);
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mView);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(mView));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         mSpannable = (Spannable) mView.getText();
         // make first line clickable
@@ -83,10 +97,12 @@
         mClickable1 = markClickable(CONTENT.lastIndexOf('\n'), CONTENT.length());
     }
 
+    @Test
     public void testConstructor() {
         new LinkMovementMethod();
     }
 
+    @Test
     public void testGetInstance() {
         MovementMethod method0 = LinkMovementMethod.getInstance();
         assertTrue(method0 instanceof LinkMovementMethod);
@@ -96,13 +112,15 @@
         assertSame(method0, method1);
     }
 
+    @Test
     public void testOnTakeFocus() {
         LinkMovementMethod method = new LinkMovementMethod();
         Spannable spannable = new SpannableString("test sequence");
         Selection.setSelection(spannable, 0, spannable.length());
 
         assertSelection(spannable, 0, spannable.length());
-        assertTrue("Expected at least 2 spans", 2 <= spannable.getSpans(0, spannable.length(), Object.class).length);
+        assertTrue("Expected at least 2 spans",
+                2 <= spannable.getSpans(0, spannable.length(), Object.class).length);
         method.onTakeFocus(null, spannable, View.FOCUS_UP);
         assertSelection(spannable, -1);
         assertEquals(1, spannable.getSpans(0, spannable.length(), Object.class).length);
@@ -114,7 +132,8 @@
         // focus forwards
         Selection.setSelection(spannable, 0, spannable.length());
         assertSelection(spannable, 0, spannable.length());
-        assertTrue("Expected at least 3 spans", 3 <= spannable.getSpans(0, spannable.length(), Object.class).length);
+        assertTrue("Expected at least 3 spans",
+                3 <= spannable.getSpans(0, spannable.length(), Object.class).length);
         method.onTakeFocus(null, spannable, View.FOCUS_RIGHT);
         assertSelection(spannable, -1);
         assertEquals(0, spannable.getSpans(0, spannable.length(), Object.class).length);
@@ -124,69 +143,70 @@
         // param direction is unknown(0)
         Selection.setSelection(spannable, 0, spannable.length());
         assertSelection(spannable, 0, spannable.length());
-        assertTrue("Expected at least 3 spans", 3 <= spannable.getSpans(0, spannable.length(), Object.class).length);
+        assertTrue("Expected at least 3 spans",
+                3 <= spannable.getSpans(0, spannable.length(), Object.class).length);
         method.onTakeFocus(null, spannable, 0);
         assertSelection(spannable, -1);
         assertEquals(0, spannable.getSpans(0, spannable.length(), Object.class).length);
-
-        // null parameters
-        try {
-            method.onTakeFocus(new TextViewNoIme(getActivity()), null, View.FOCUS_RIGHT);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTakeFocusNullSpannable() {
+        LinkMovementMethod method = new LinkMovementMethod();
+        method.onTakeFocus(new TextViewNoIme(mActivity), null, View.FOCUS_RIGHT);
+    }
+
+    @UiThreadTest
+    @Test
     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,48 +215,47 @@
         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());
-
-        // null parameters
-        try {
-            mMethod.onKeyDown(null, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER,
-                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mMethod.onKeyDown(mView, null, KeyEvent.KEYCODE_DPAD_CENTER,
-                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER, null);
-            fail("The method did not throw NullPointerException when param keyEvent is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        verify(mClickable0, never()).onClick(any());
+        verify(mClickable1, never()).onClick(any());
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnKeyDown_nullViewParam() {
+        mMethod.onKeyDown(null, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnKeyDown_nullSpannableParam() {
+        mMethod.onKeyDown(mView, null, KeyEvent.KEYCODE_DPAD_CENTER,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnKeyDown_nullKeyEventParam() {
+        mMethod.onKeyDown(mView, mSpannable, KeyEvent.KEYCODE_DPAD_CENTER, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnKeyUp() {
         LinkMovementMethod method = new LinkMovementMethod();
         // always returns false
         assertFalse(method.onKeyUp(null, null, 0, null));
-        assertFalse(method.onKeyUp(new TextViewNoIme(getActivity()), null, 0, null));
+        assertFalse(method.onKeyUp(new TextViewNoIme(mActivity), null, 0, null));
         assertFalse(method.onKeyUp(null, new SpannableString("blahblah"), 0, null));
         assertFalse(method.onKeyUp(null, null, KeyEvent.KEYCODE_0,
                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0)));
     }
 
     @UiThreadTest
+    @Test
     public void testOnTouchEvent() {
         assertSelection(mSpannable, -1);
 
@@ -245,9 +264,9 @@
         assertSelectClickableLeftToRight(mSpannable, mClickable0);
 
         // release on first line
-        assertFalse(mClickable0.hasCalledOnClick());
-        assertTrue(releaseOnLine(0));
-        assertTrue(mClickable0.hasCalledOnClick());
+        verify(mClickable0, never()).onClick(any());
+        assertFalse(releaseOnLine(0));
+        verify(mClickable0, never()).onClick(any());
 
         // press on second line (unclickable)
         assertSelectClickableLeftToRight(mSpannable, mClickable0);
@@ -260,44 +279,43 @@
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
 
         // release on last line
-        assertFalse(mClickable1.hasCalledOnClick());
-        assertTrue(releaseOnLine(2));
-        assertTrue(mClickable1.hasCalledOnClick());
+        verify(mClickable1, never()).onClick(any());
+        assertFalse(releaseOnLine(2));
+        verify(mClickable1, never()).onClick(any());
 
         // release on second line (unclickable)
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
         // just clear selection
-        releaseOnLine(1);
+        pressOnLine(1);
         assertSelection(mSpannable, -1);
-
-        // null parameters
-        long now = SystemClock.uptimeMillis();
-        int y = (mView.getLayout().getLineTop(1) + mView.getLayout().getLineBottom(1)) / 2;
-        try {
-            mMethod.onTouchEvent(null, mSpannable,
-                    MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 5, y, 0));
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mMethod.onTouchEvent(mView, null,
-                    MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 5, y, 0));
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            mMethod.onTouchEvent(mView, mSpannable, null);
-            fail("The method did not throw NullPointerException when param keyEvent is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEvent_nullViewParam() {
+        long now = SystemClock.uptimeMillis();
+        int y = (mView.getLayout().getLineTop(1) + mView.getLayout().getLineBottom(1)) / 2;
+        mMethod.onTouchEvent(null, mSpannable,
+                MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 5, y, 0));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEvent_nullSpannableParam() {
+        long now = SystemClock.uptimeMillis();
+        int y = (mView.getLayout().getLineTop(1) + mView.getLayout().getLineBottom(1)) / 2;
+        mMethod.onTouchEvent(mView, null,
+                MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 5, y, 0));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testOnTouchEvent_nullKeyEventParam() {
+        mMethod.onTouchEvent(mView, mSpannable, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testUp() {
         final MyLinkMovementMethod method = new MyLinkMovementMethod();
         assertSelection(mSpannable, -1);
@@ -310,24 +328,24 @@
 
         assertFalse(method.up(mView, mSpannable));
         assertSelectClickableRightToLeft(mSpannable, mClickable0);
-
-        // null parameters
-        try {
-            method.up(null, mSpannable);
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            method.up(mView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testUp_nullViewParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.up(null, mSpannable);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testUp_nullSpannableParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.up(mView, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testDown() {
         final MyLinkMovementMethod method = new MyLinkMovementMethod();
         assertSelection(mSpannable, -1);
@@ -340,24 +358,24 @@
 
         assertFalse(method.down(mView, mSpannable));
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
-
-        // null parameters
-        try {
-            method.down(null, mSpannable);
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            method.down(mView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testDown_nullViewParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.down(null, mSpannable);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testDown_nullSpannableParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.down(mView, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testLeft() {
         final MyLinkMovementMethod method = new MyLinkMovementMethod();
         assertSelection(mSpannable, -1);
@@ -370,24 +388,24 @@
 
         assertFalse(method.left(mView, mSpannable));
         assertSelectClickableRightToLeft(mSpannable, mClickable0);
-
-        // null parameters
-        try {
-            method.left(null, mSpannable);
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            method.left(mView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testLeft_nullViewParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.left(null, mSpannable);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testLeft_nullSpannableParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.left(mView, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testRight() {
         final MyLinkMovementMethod method = new MyLinkMovementMethod();
         assertSelection(mSpannable, -1);
@@ -400,24 +418,24 @@
 
         assertFalse(method.right(mView, mSpannable));
         assertSelectClickableLeftToRight(mSpannable, mClickable1);
-
-        // null parameters
-        try {
-            method.right(null, mSpannable);
-            fail("The method did not throw NullPointerException when param view is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            method.right(mView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testRight_nullViewParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.right(null, mSpannable);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testRight_nullSpannableParam() {
+        final MyLinkMovementMethod method = new MyLinkMovementMethod();
+        method.right(mView, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testMoveAroundUnclickable() {
         final MyLinkMovementMethod method = new MyLinkMovementMethod();
         mSpannable.removeSpan(mClickable0);
@@ -437,6 +455,7 @@
         assertSelection(mSpannable, -1);
     }
 
+    @Test
     public void testInitialize() {
         LinkMovementMethod method = new LinkMovementMethod();
         Spannable spannable = new SpannableString("test sequence");
@@ -449,22 +468,19 @@
         assertSelection(spannable, -1);
         assertEquals(0, spannable.getSpans(0, spannable.length(), Object.class).length);
 
-        try {
-            method.initialize(mView, null);
-            fail("The method did not throw NullPointerException when param spannable is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
-    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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+    @Test(expected=NullPointerException.class)
+    public void testInitialize_nullViewParam() {
+        final LinkMovementMethod method = new LinkMovementMethod();
+        method.initialize(mView, null);
+    }
+
+    private ClickableSpan markClickable(final int start, final int end) throws Throwable {
+        final ClickableSpan clickableSpan = spy(new MockClickableSpan());
+        mActivityRule.runOnUiThread(() -> mSpannable.setSpan(clickableSpan, start, end,
+                Spanned.SPAN_MARK_MARK));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         return clickableSpan;
     }
 
@@ -495,13 +511,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 +544,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..2f80106 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,21 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 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;
@@ -28,10 +38,16 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link MetaKeyKeyListener}.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class MetaKeyKeyListenerTest extends KeyListenerTestCase {
+    @Test
     public void testPressKey() {
         final CharSequence str = "123456";
         final MetaKeyKeyListener numberKeyListener = new DateKeyListener();
@@ -57,6 +73,7 @@
         assertEquals('3', content.charAt(3));
     }
 
+    @Test
     public void testReleaseKey() {
         final CharSequence str = "123456";
         final MetaKeyKeyListener numberKeyListener = new DateKeyListener();
@@ -82,6 +99,7 @@
         assertEquals(str.charAt(3), content.charAt(3));
     }
 
+    @Test
     public void testAdjustMetaAfterKeypress() {
         CharSequence str = "123456";
         Spannable content = Editable.Factory.getInstance().newEditable(str);
@@ -111,6 +129,7 @@
         assertEquals(Spanned.SPAN_POINT_POINT, content.getSpanFlags(Selection.SELECTION_END));
     }
 
+    @Test
     public void testAdjustMetaAfterKeypress2() {
         long state = MetaKeyKeyListener.adjustMetaAfterKeypress(MetaKeyKeyListener.META_SHIFT_ON);
         assertEquals(MetaKeyKeyListener.META_SHIFT_ON, state);
@@ -125,6 +144,7 @@
         assertEquals(0, state);
     }
 
+    @Test
     public void testResetMetaState() {
         CharSequence str = "123456";
         Spannable text = Editable.Factory.getInstance().newEditable(str);
@@ -151,6 +171,7 @@
         assertEquals(Spanned.SPAN_POINT_POINT, text.getSpanFlags(Selection.SELECTION_END));
     }
 
+    @Test
     public void testGetMetaState() {
         assertEquals(0, MetaKeyKeyListener.getMetaState("123456"));
         assertEquals(0, MetaKeyKeyListener.getMetaState("abc"));
@@ -177,6 +198,7 @@
                 MetaKeyKeyListener.getMetaState("@#$$#^$^", MetaKeyKeyListener.META_SYM_ON));
     }
 
+    @Test
     public void testGetMetaState2() {
         assertEquals(0, MetaKeyKeyListener.getMetaState(0));
         assertEquals(MetaKeyKeyListener.META_SHIFT_ON,
@@ -191,33 +213,69 @@
                 MetaKeyKeyListener.META_SYM_ON));
     }
 
+    @Test
+    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));
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
     public void testIsMetaTracker() {
         assertFalse(MetaKeyKeyListener.isMetaTracker("123456", new Object()));
         assertFalse(MetaKeyKeyListener.isMetaTracker("abc", new Object()));
         assertFalse(MetaKeyKeyListener.isMetaTracker("@#$$#^$^", new Object()));
     }
 
+    @Test
     public void testIsSelectingMetaTracker() {
         assertFalse(MetaKeyKeyListener.isSelectingMetaTracker("123456", new Object()));
         assertFalse(MetaKeyKeyListener.isSelectingMetaTracker("abc", new Object()));
         assertFalse(MetaKeyKeyListener.isSelectingMetaTracker("@#$$#^$^", new Object()));
     }
 
+    @Test
     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);
@@ -226,6 +284,7 @@
         }
     }
 
+    @Test
     public void testResetLockedMeta2() {
         long state = MetaKeyKeyListener.resetLockedMeta(MetaKeyKeyListener.META_CAP_LOCKED);
         assertEquals(0, state);
@@ -246,6 +305,7 @@
         assertEquals(MetaKeyKeyListener.META_SYM_ON, state);
     }
 
+    @Test
     public void testClearMetaKeyState() {
         final MetaKeyKeyListener numberKeyListener = new DateKeyListener();
         CharSequence str = "123456";
@@ -273,6 +333,7 @@
         assertEquals(Spanned.SPAN_POINT_POINT, text.getSpanFlags(Selection.SELECTION_END));
     }
 
+    @Test
     public void testClearMetaKeyState2() {
         CharSequence str = "123456";
         Editable text = Editable.Factory.getInstance().newEditable(str);
@@ -299,6 +360,7 @@
         assertEquals(Spanned.SPAN_POINT_POINT, text.getSpanFlags(Selection.SELECTION_END));
     }
 
+    @Test
     public void testClearMetaKeyState3() {
         final MetaKeyKeyListener metaKeyKeyListener = new MetaKeyKeyListener() {};
         long state = metaKeyKeyListener.clearMetaKeyState(MetaKeyKeyListener.META_CAP_LOCKED,
@@ -326,6 +388,7 @@
         assertEquals(MetaKeyKeyListener.META_SYM_ON, state);
     }
 
+    @Test
     public void testHandleKeyDown() {
         KeyEvent fullEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT,
                 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0);
@@ -334,6 +397,7 @@
         assertEquals(0, state);
     }
 
+    @Test
     public void testHandleKeyUp() {
         KeyEvent fullEvent = new KeyEvent(0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT,
                 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0);
@@ -357,20 +421,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..c73b7fa 100644
--- a/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
@@ -16,25 +16,41 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 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;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@LargeTest
+@RunWith(AndroidJUnit4.class)
 public class MultiTapKeyListenerTest extends KeyListenerTestCase {
     /**
      * time out of MultiTapKeyListener. longer than 2000ms in case the system is sluggish.
      */
     private static final long TIME_OUT = 3000;
 
+    @Test
     public void testConstructor() {
         new MultiTapKeyListener(Capitalize.NONE, true);
 
@@ -43,23 +59,24 @@
         new MultiTapKeyListener(null, false);
     }
 
-    public void testOnSpanAdded() {
-        final MockMultiTapKeyListener mockMultiTapKeyListener
-                = new MockMultiTapKeyListener(Capitalize.CHARACTERS, true);
+    @Test
+    public void testOnSpanAdded() throws Throwable {
+        final MultiTapKeyListener mockMultiTapKeyListener
+                = spy(new MultiTapKeyListener(Capitalize.CHARACTERS, true));
         final Spannable text = new SpannableStringBuilder("123456");
 
-        assertFalse(mockMultiTapKeyListener.hadAddedSpan());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(mockMultiTapKeyListener);
-                mTextView.setText(text, BufferType.EDITABLE);
-            }
+        verify(mockMultiTapKeyListener, never()).onSpanAdded(any(), any(), anyInt(), anyInt());
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(mockMultiTapKeyListener);
+            mTextView.setText(text, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
 
-        assertTrue(mockMultiTapKeyListener.hadAddedSpan());
+        verify(mockMultiTapKeyListener, atLeastOnce()).onSpanAdded(
+                any(), any(), anyInt(), anyInt());
     }
 
+    @Test
     public void testOnSpanChanged() {
         final MultiTapKeyListener multiTapKeyListener
                 = MultiTapKeyListener.getInstance(true, Capitalize.CHARACTERS);
@@ -74,7 +91,8 @@
         }
     }
 
-    public void testOnKeyDown_capitalizeNone() {
+    @Test
+    public void testOnKeyDown_capitalizeNone() throws Throwable {
         MultiTapKeyListener keyListener = MultiTapKeyListener.getInstance(false, Capitalize.NONE);
 
         prepareEmptyTextView();
@@ -95,7 +113,8 @@
         assertEquals("hello", mTextView.getText().toString());
     }
 
-    public void testOnKeyDown_capitalizeCharacters() {
+    @Test
+    public void testOnKeyDown_capitalizeCharacters() throws Throwable {
         MultiTapKeyListener keyListener = MultiTapKeyListener.getInstance(false,
                 Capitalize.CHARACTERS);
 
@@ -117,7 +136,8 @@
         assertEquals("HELLO", mTextView.getText().toString());
     }
 
-    public void testOnKeyDown_capitalizeSentences() {
+    @Test
+    public void testOnKeyDown_capitalizeSentences() throws Throwable {
         MultiTapKeyListener keyListener = MultiTapKeyListener.getInstance(false,
                 Capitalize.SENTENCES);
 
@@ -144,7 +164,8 @@
         assertEquals("Hi. Bye", mTextView.getText().toString());
     }
 
-    public void testOnKeyDown_capitalizeWords() {
+    @Test
+    public void testOnKeyDown_capitalizeWords() throws Throwable {
         MultiTapKeyListener keyListener = MultiTapKeyListener.getInstance(false,
                 Capitalize.WORDS);
 
@@ -168,25 +189,21 @@
         assertEquals("Hi Bye", mTextView.getText().toString());
     }
 
-    private void prepareEmptyTextView() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText("", BufferType.EDITABLE);
-                Selection.setSelection(mTextView.getEditableText(), 0, 0);
-            }
+    private void prepareEmptyTextView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getEditableText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
     }
 
     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));
-                }
+            final int numTimes) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            for (int i = 0; i < numTimes; i++) {
+                keyListener.onKeyDown(mTextView, mTextView.getEditableText(), keyCode,
+                        new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
             }
         });
         mInstrumentation.waitForIdleSync();
@@ -199,15 +216,12 @@
         }
     }
 
-    private void addSpace() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.append(" ");
-            }
-        });
+    private void addSpace() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.append(" "));
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testGetInstance() {
         MultiTapKeyListener listener1 = MultiTapKeyListener.getInstance(false, Capitalize.NONE);
         MultiTapKeyListener listener2 = MultiTapKeyListener.getInstance(false, Capitalize.NONE);
@@ -223,6 +237,7 @@
         assertNotSame(listener4, listener1);
     }
 
+    @Test
     public void testOnSpanRemoved() {
         MultiTapKeyListener multiTapKeyListener =
                 new MultiTapKeyListener(Capitalize.CHARACTERS, true);
@@ -230,6 +245,7 @@
         multiTapKeyListener.onSpanRemoved(text, new Object(), 0, 0);
     }
 
+    @Test
     public void testGetInputType() {
         MultiTapKeyListener listener = MultiTapKeyListener.getInstance(false, Capitalize.NONE);
         int expected = InputType.TYPE_CLASS_TEXT;
@@ -241,27 +257,4 @@
                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
         assertEquals(expected, listener.getInputType());
     }
-
-    /**
-     * A mocked {@link android.text.method.MultiTapKeyListener} for testing purposes.
-     *
-     * Tracks whether {@link MockMultiTapKeyListener#onSpanAdded()} has been called.
-     */
-    private class MockMultiTapKeyListener extends MultiTapKeyListener {
-        private boolean mHadAddedSpan;
-
-        public MockMultiTapKeyListener(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/NumberKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
index 09053f1..c4a7944 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,14 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
-import android.text.Editable;
+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.junit.Assert.fail;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -26,18 +32,16 @@
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 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 "".
@@ -46,6 +50,7 @@
      * 4. Filter "12345 Android", return "12345".
      * 5. Filter Spanned("12345 Android"), return Spanned("12345") and copy spans.
      */
+    @Test
     public void testFilter() {
         mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
         String source = "Android test";
@@ -90,6 +95,7 @@
      * If one of the chars in the getAcceptedChars() can be generated by the keyCode of this
      * key event, return the char; otherwise return '\0'.
      */
+    @Test
     public void testLookup() {
         mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
         KeyEvent event1 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
@@ -109,6 +115,7 @@
         }
     }
 
+    @Test
     public void testOk() {
         mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
 
@@ -128,42 +135,39 @@
      * 2. Press an unaccepted key if it exists, it will not be added.
      * 3. remove NumberKeyListener and press '0' key, '0' will not be added.
      */
+    @Test
     public void testPressKey() {
         final CharSequence text = "123456";
         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();
-            }
+        mActivity.runOnUiThread(() -> {
+            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..3ed0ad4 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -16,24 +16,46 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+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.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
-import android.cts.util.KeyEventUtil;
-import android.cts.util.PollingCheck;
-import android.graphics.Rect;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
 import android.os.ParcelFileDescriptor;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings.System;
-import android.test.ActivityInstrumentationTestCase2;
-import android.text.Editable;
+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.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;
 import android.widget.LinearLayout.LayoutParams;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.util.Scanner;
@@ -41,8 +63,9 @@
 /**
  * Test {@link PasswordTransformationMethod}.
  */
-public class PasswordTransformationMethodTest extends
-        ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PasswordTransformationMethodTest {
     private static final int EDIT_TXT_ID = 1;
 
     /** original text */
@@ -52,85 +75,72 @@
     private static final String TEST_CONTENT_TRANSFORMED =
         "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
 
-    private int mPasswordPrefBackUp;
-
-    private boolean isPasswordPrefSaved;
-
+    private Instrumentation mInstrumentation;
     private CtsActivity mActivity;
-
-    private MockPasswordTransformationMethod mMethod;
-
+    private int mPasswordPrefBackUp;
+    private boolean isPasswordPrefSaved;
+    private PasswordTransformationMethod mMethod;
     private EditText mEditText;
-
     private CharSequence mTransformedText;
 
-    public PasswordTransformationMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
 
-    private KeyEventUtil mKeyEventUtil;
+    @Before
+    public void setup() throws Throwable {
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(1000, mActivity::hasWindowFocus);
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mMethod = spy(new PasswordTransformationMethod());
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mMethod = new MockPasswordTransformationMethod();
-        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();
-                }
-            });
-        } catch (Throwable e) {
-            fail("Exception thrown is UI thread:" + e.getMessage());
-        }
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> {
+            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();
+        });
+        mInstrumentation.waitForIdleSync();
 
-        mEditText = (EditText) getActivity().findViewById(EDIT_TXT_ID);
+        mEditText = (EditText) mActivity.findViewById(EDIT_TXT_ID);
         assertTrue(mEditText.isFocused());
 
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-
         enableAppOps();
         savePasswordPref();
         switchShowPassword(true);
     }
 
+    @After
+    public void teardown() {
+        resumePasswordPref();
+    }
+
     private void enableAppOps() {
+        UiAutomation uiAutomation = mInstrumentation.getUiAutomation();
+
         StringBuilder cmd = new StringBuilder();
         cmd.append("appops set ");
-        cmd.append(getInstrumentation().getContext().getPackageName());
+        cmd.append(mActivity.getPackageName());
         cmd.append(" android:write_settings allow");
-        getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
+        uiAutomation.executeShellCommand(cmd.toString());
 
         StringBuilder query = new StringBuilder();
         query.append("appops get ");
-        query.append(getInstrumentation().getContext().getPackageName());
+        query.append(mActivity.getPackageName());
         query.append(" android:write_settings");
         String queryStr = query.toString();
 
         String result = "No operations.";
         while (result.contains("No operations")) {
-            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
-                                        queryStr);
+            ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(queryStr);
             InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
             result = convertStreamToString(inputStream);
         }
@@ -142,63 +152,49 @@
         }
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        resumePasswordPref();
-        super.tearDown();
-    }
-
+    @Test
     public void testConstructor() {
         new PasswordTransformationMethod();
     }
 
+    @Test
     public void testTextChangedCallBacks() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTransformedText = mMethod.getTransformation(mEditText.getText(), mEditText);
-            }
-        });
+        mActivityRule.runOnUiThread(() ->
+            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(" ");
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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"));
     }
 
+    @Test
     public void testGetTransformation() {
         PasswordTransformationMethod method = new PasswordTransformationMethod();
 
@@ -215,6 +211,7 @@
         }
     }
 
+    @Test
     public void testGetInstance() {
         PasswordTransformationMethod method0 = PasswordTransformationMethod.getInstance();
         assertNotNull(method0);
@@ -224,20 +221,21 @@
         assertSame(method0, method1);
     }
 
+    @Test
     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 +259,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..c2e684a 100644
--- a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
@@ -16,6 +16,13 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -25,7 +32,13 @@
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class QwertyKeyListenerTest extends KeyListenerTestCase {
+    @Test
     public void testConstructor() {
         new QwertyKeyListener(Capitalize.NONE, false);
 
@@ -34,8 +47,9 @@
         new QwertyKeyListener(null, true);
     }
 
+    @Test
     public void testOnKeyDown_capitalizeNone() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false, Capitalize.NONE);
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false, Capitalize.NONE);
 
         prepareEmptyTextView();
 
@@ -55,8 +69,9 @@
         assertEquals("hello", mTextView.getText().toString());
     }
 
+    @Test
     public void testOnKeyDown_capitalizeCharacters() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.CHARACTERS);
 
         prepareEmptyTextView();
@@ -77,8 +92,9 @@
         assertEquals("HELLO", mTextView.getText().toString());
     }
 
+    @Test
     public void testOnKeyDown_capitalizeSentences() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.SENTENCES);
 
         prepareEmptyTextView();
@@ -105,8 +121,9 @@
         assertEquals("Hi. Bye", mTextView.getText().toString());
     }
 
+    @Test
     public void testOnKeyDown_capitalizeWords() {
-        QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
+        final QwertyKeyListener keyListener = QwertyKeyListener.getInstance(false,
                 Capitalize.WORDS);
 
         prepareEmptyTextView();
@@ -131,31 +148,28 @@
     }
 
     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();
     }
 
+    @Test
     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 +180,18 @@
         assertNotSame(listener4, listener3);
     }
 
+    @Test
+    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());
+    }
+
+    @Test
     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);
@@ -185,27 +209,25 @@
         assertEquals(1, content.getSpanStart(repl[0]));
         assertEquals(2, content.getSpanEnd(repl[0]));
         assertEquals(Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, content.getSpanFlags(repl[0]));
-
-        try {
-            QwertyKeyListener.markAsReplaced(null, 1, 2, "abcd");
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            QwertyKeyListener.markAsReplaced(content, 1, 2, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testMarkAsReplacedNullContent() {
+        QwertyKeyListener.markAsReplaced(null, 1, 2, "abcd");
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testMarkAsReplacedNullOriginal() {
+        QwertyKeyListener.markAsReplaced(new SpannableStringBuilder("123456"), 1, 2, null);
+    }
+
+    @Test
     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/ReplacementTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
index ef7de09..e75271e 100644
--- a/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
@@ -16,36 +16,48 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.ReplacementTransformationMethod;
 import android.util.TypedValue;
 import android.widget.EditText;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ReplacementTransformationMethod}.
  */
-public class ReplacementTransformationMethodTest extends
-        ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ReplacementTransformationMethodTest {
     private final char[] ORIGINAL = new char[] { '0', '1' };
     private final char[] ORIGINAL_WITH_MORE_CHARS = new char[] { '0', '1', '2' };
     private final char[] ORIGINAL_WITH_SAME_CHARS = new char[] { '0', '0' };
     private final char[] REPLACEMENT = new char[] { '3', '4' };
     private final char[] REPLACEMENT_WITH_MORE_CHARS = new char[] { '3', '4', '5' };
     private final char[] REPLACEMENT_WITH_SAME_CHARS = new char[] { '3', '3' };
+
     private EditText mEditText;
 
-    public ReplacementTransformationMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mEditText = new EditTextNoIme(getActivity());
+    @UiThreadTest
+    @Before
+    public void setup() throws Throwable {
+        mEditText = new EditTextNoIme(mActivityRule.getActivity());
         mEditText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
     }
 
+    @Test
     public void testGetTransformation() {
         MyReplacementTransformationMethod method =
             new MyReplacementTransformationMethod(ORIGINAL, REPLACEMENT);
@@ -57,6 +69,7 @@
         // TODO cannot get transformed text from the view
     }
 
+    @Test
     public void testGetTransformationWithAbnormalCharSequence() {
         ReplacementTransformationMethod method = new MyReplacementTransformationMethod(ORIGINAL,
                 REPLACEMENT);
@@ -71,6 +84,7 @@
         assertEquals("", method.getTransformation("", null).toString());
     }
 
+    @Test
     public void testGetTransformationWithAbmornalReplacement() {
         // replacement has same chars
         ReplacementTransformationMethod method =
@@ -90,26 +104,27 @@
         // TODO cannot get transformed text from the view
     }
 
-    public void testGetTransformationWithAbmornalOriginal() {
+    @Test
+    public void testGetTransformationWithAbnormalOriginal() {
         // original has same chars
         ReplacementTransformationMethod method =
-            new MyReplacementTransformationMethod(ORIGINAL_WITH_SAME_CHARS, REPLACEMENT);
+                new MyReplacementTransformationMethod(ORIGINAL_WITH_SAME_CHARS, REPLACEMENT);
         assertEquals("414141", method.getTransformation("010101", null).toString());
 
         mEditText.setTransformationMethod(method);
         mEditText.setText("010101");
         // TODO cannot get transformed text from the view
-
-        // original has more chars than replacement
-        method = new MyReplacementTransformationMethod(ORIGINAL_WITH_MORE_CHARS, REPLACEMENT);
-        try {
-            method.getTransformation("012012012", null);
-            fail("Threre is more chars in the original than replacement.");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // expected
-        }
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testGetTransformationMismatchCharCount() {
+        // original has more chars than replacement
+        ReplacementTransformationMethod method =
+                new MyReplacementTransformationMethod(ORIGINAL_WITH_MORE_CHARS, REPLACEMENT);
+        method.getTransformation("012012012", null);
+    }
+
+    @Test
     public void testOnFocusChanged() {
         ReplacementTransformationMethod method = new MyReplacementTransformationMethod(ORIGINAL,
                 REPLACEMENT);
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..32c6e5e 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -16,9 +16,21 @@
 
 package android.text.method.cts;
 
-import android.cts.util.WidgetTestUtils;
+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 android.app.Activity;
+import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -30,11 +42,17 @@
 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;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ScrollingMovementMethod}. The class is an implementation of interface
  * {@link MovementMethod}. The typical usage of {@link MovementMethod} is tested in
@@ -43,68 +61,64 @@
  *
  * @see android.widget.cts.TextViewTest
  */
-public class ScrollingMovementMethodTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScrollingMovementMethodTest {
     private static final int LITTLE_SPACE = 20;
 
     private static final String THREE_LINES_TEXT = "first line\nsecond line\nlast line";
 
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private TextView mTextView;
-
     private Spannable mSpannable;
-
     private int mScaledTouchSlop;
 
-    public ScrollingMovementMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTextView = new TextViewNoIme(getActivity());
+    @UiThreadTest
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTextView = new TextViewNoIme(mActivity);
         mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
         mTextView.setText(THREE_LINES_TEXT, BufferType.EDITABLE);
         mSpannable = (Spannable) mTextView.getText();
-        mScaledTouchSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop();
+        mScaledTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop();
     }
 
+    @Test
     public void testConstructor() {
         new ScrollingMovementMethod();
     }
 
+    @Test
     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);
     }
 
+    @Test
     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(mActivity, LITTLE_SPACE);
+            mActivity.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() {
@@ -186,28 +200,19 @@
         }));
     }
 
+    @Test
     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);
+            mActivity.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() {
@@ -289,230 +294,158 @@
         }));
     }
 
+    @Test
     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(mActivity, LITTLE_SPACE);
+            mActivity.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
             }
         });
     }
 
+    @Test
     public void testCanSelectArbitrarily() {
         assertFalse(new ScrollingMovementMethod().canSelectArbitrarily());
     }
 
+    @Test
     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(() -> mActivity.setContentView(mTextView));
         assertNotNull(mTextView.getLayout());
 
-        assertVisibleLineInTextView(0);
+        verifyVisibleLineInTextView(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));
-            }
-        });
-        assertVisibleLineInTextView(1);
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_DOWN,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN)));
+        verifyVisibleLineInTextView(1);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_UP,
-                        new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
-            }
-        });
-        assertVisibleLineInTextView(0);
+        runActionOnUiThread(() -> method.onKeyDown(mTextView, null, KeyEvent.KEYCODE_DPAD_UP,
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP)));
+        verifyVisibleLineInTextView(0);
     }
 
+    @Test
     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(mActivity, LITTLE_SPACE);
+            mActivity.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)));
-            }
-        });
+        verifyVisibleLineInTextView(0);
+        runActionOnUiThread(() -> assertFalse(method.onKeyDown(mTextView, mSpannable, 0,
+                new KeyEvent(KeyEvent.ACTION_DOWN, 0))));
         assertEquals(previousScrollX, mTextView.getScrollX());
-        assertVisibleLineInTextView(0);
+        verifyVisibleLineInTextView(0);
     }
 
+    @Test
     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(() -> mActivity.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
             }
         });
     }
 
+    @Test
     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);
+            mActivity.setContentView(mTextView,
+                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
@@ -521,72 +454,71 @@
                 mResult = method.down(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(1);
+        verifyVisibleLineInTextView(1);
 
         assertTrue(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 mResult = method.down(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(2);
+        verifyVisibleLineInTextView(2);
 
         assertFalse(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 mResult = method.down(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(2);
+        verifyVisibleLineInTextView(2);
 
         assertTrue(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 mResult = method.up(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(1);
+        verifyVisibleLineInTextView(1);
 
         assertTrue(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 mResult = method.up(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(0);
+        verifyVisibleLineInTextView(0);
 
         assertFalse(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 mResult = method.up(mTextView, mSpannable);
             }
         }));
-        assertVisibleLineInTextView(0);
+        verifyVisibleLineInTextView(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
             }
         });
     }
 
+    @Test
     public void testMovementWithNullLayout() {
         assertNull(mTextView.getLayout());
         try {
@@ -613,7 +545,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,
@@ -632,14 +564,16 @@
         }
     }
 
+    @Test
     public void testInitialize() {
         new ScrollingMovementMethod().initialize(null, null);
     }
 
+    @Test
     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));
@@ -647,11 +581,13 @@
         assertFalse(mockMethod.onTrackballEvent(mTextView, null, event));
     }
 
+    @UiThreadTest
+    @Test
     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(mActivity);
         view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
 
         assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
@@ -662,15 +598,8 @@
         assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, null));
     }
 
+    @Test
     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 +609,50 @@
             // 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(mActivity, LITTLE_SPACE);
+            mActivity.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);
+        verifyVisibleLineInTextView(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);
+        verifyVisibleLineInTextView(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
             }
         });
     }
 
+    @Test
     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 = mActivity.getResources().getDisplayMetrics();
+            final int width = (int) (LITTLE_SPACE * dm.scaledDensity);
+            mActivity.setContentView(mTextView,
+                    new LayoutParams(width, LayoutParams.WRAP_CONTENT));
         });
         assertNotNull(mTextView.getLayout());
 
@@ -782,39 +690,28 @@
         assertEquals(previousScrollX, mTextView.getScrollX());
     }
 
+    @Test
     public void testOnKeyOther() throws Throwable {
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                getActivity().setContentView(mTextView);
-            }
-        });
+        runActionOnUiThread(() -> mActivity.setContentView(mTextView));
         assertNotNull(mTextView.getLayout());
 
-        assertVisibleLineInTextView(0);
+        verifyVisibleLineInTextView(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));
-            }
-        });
-        assertVisibleLineInTextView(1);
+        runActionOnUiThread(() -> method.onKeyOther(mTextView, null,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
+                        KeyEvent.KEYCODE_DPAD_DOWN, 2)));
+        verifyVisibleLineInTextView(1);
 
-        runActionOnUiThread(new Runnable() {
-            public void run() {
-                method.onKeyOther(mTextView, null,
-                        new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
-                                KeyEvent.KEYCODE_DPAD_UP, 2));
-            }
-        });
-        assertVisibleLineInTextView(0);
+        runActionOnUiThread(() -> method.onKeyOther(mTextView, null,
+                new KeyEvent(0, 0, KeyEvent.ACTION_MULTIPLE,
+                        KeyEvent.KEYCODE_DPAD_UP, 2)));
+        verifyVisibleLineInTextView(0);
     }
 
-    private void assertVisibleLineInTextView(int line) {
-        Layout layout = mTextView.getLayout();
-        int scrollY = mTextView.getScrollY();
-        int padding = mTextView.getTotalPaddingTop() + mTextView.getTotalPaddingBottom();
+    private void verifyVisibleLineInTextView(int line) {
+        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);
     }
@@ -825,8 +722,8 @@
     }
 
     private void runActionOnUiThread(Runnable actionRunner) throws Throwable {
-        runTestOnUiThread(actionRunner);
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(actionRunner);
+        mInstrumentation.waitForIdleSync();
     }
 
     private static abstract class ActionRunnerWithResult implements Runnable {
diff --git a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
index 0eec6bf..5db4a6f 100644
--- a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
@@ -16,25 +16,34 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.SingleLineTransformationMethod;
 import android.util.TypedValue;
 import android.widget.EditText;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link SingleLineTransformationMethod}.
  */
-public class SingleLineTransformationMethodTest
-        extends ActivityInstrumentationTestCase2<CtsActivity> {
-    public SingleLineTransformationMethodTest() {
-        super("android.text.cts", CtsActivity.class);
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SingleLineTransformationMethodTest {
+    @Test
     public void testConstructor() {
         new SingleLineTransformationMethod();
     }
 
+    @Test
     public void testGetInstance() {
         SingleLineTransformationMethod method0 = SingleLineTransformationMethod.getInstance();
         assertNotNull(method0);
@@ -43,26 +52,26 @@
         assertSame(method0, method1);
     }
 
+    @Test
     public void testGetReplacement() {
         MySingleLineTranformationMethod method = new MySingleLineTranformationMethod();
-        TextMethodUtils.assertEquals(new char[] { ' ', '\uFEFF' }, method.getReplacement());
-        TextMethodUtils.assertEquals(new char[] { '\n', '\r' }, method.getOriginal());
+        assertArrayEquals(new char[] { ' ', '\uFEFF' }, method.getReplacement());
+        assertArrayEquals(new char[] { '\n', '\r' }, method.getOriginal());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetTransformation() {
         SingleLineTransformationMethod method = SingleLineTransformationMethod.getInstance();
         CharSequence result = method.getTransformation("hello\nworld\r", null);
         assertEquals("hello world\uFEFF", result.toString());
 
-        EditText editText = new EditTextNoIme(getActivity());
+        EditText editText = new EditTextNoIme(InstrumentationRegistry.getTargetContext());
         editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
         editText.setText("hello\nworld\r");
         // TODO cannot get transformed text from the view
     }
 
-    /**
-     * The Class MySingleLineTranformationMethod.
-     */
     private static class MySingleLineTranformationMethod extends SingleLineTransformationMethod {
         @Override
         protected char[] getOriginal() {
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..7851ded 100644
--- a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
@@ -16,8 +16,23 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+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.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.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
 import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.UiThreadTest;
 import android.text.Editable;
 import android.text.InputType;
@@ -30,26 +45,27 @@
 import android.view.KeyEvent;
 import android.widget.TextView.BufferType;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 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());
-    }
-
+    @Test
     public void testConstructor() {
         new TextKeyListener(Capitalize.NONE, true);
 
         new TextKeyListener(null, true);
     }
 
+    @Test
     public void testShouldCap() {
         String str = "hello world! man";
 
@@ -74,33 +90,31 @@
         assertFalse(TextKeyListener.shouldCap(Capitalize.SENTENCES, str, 14));
         assertFalse(TextKeyListener.shouldCap(Capitalize.WORDS, str, 14));
         assertTrue(TextKeyListener.shouldCap(Capitalize.CHARACTERS, str, 14));
-
-        try {
-            TextKeyListener.shouldCap(Capitalize.WORDS, null, 16);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
-    public void testOnSpanAdded() {
-        final MockTextKeyListener mockTextKeyListener
-                = new MockTextKeyListener(Capitalize.CHARACTERS, true);
+    @Test(expected=NullPointerException.class)
+    public void testShouldCapNull() {
+        TextKeyListener.shouldCap(Capitalize.WORDS, null, 16);
+    }
+
+    @Test
+    public void testOnSpanAdded() throws Throwable {
+        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());
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(mockTextKeyListener);
+            mTextView.setText(text, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
-
-        assertTrue(mockTextKeyListener.hadAddedSpan());
+        verify(mockTextKeyListener, atLeastOnce()).onSpanAdded(any(), any(), anyInt(), anyInt());
 
         mockTextKeyListener.release();
     }
 
+    @Test
     public void testGetInstance1() {
         TextKeyListener listener1 = TextKeyListener.getInstance(true, Capitalize.WORDS);
         TextKeyListener listener2 = TextKeyListener.getInstance(true, Capitalize.WORDS);
@@ -121,6 +135,7 @@
         listener4.release();
     }
 
+    @Test
     public void testGetInstance2() {
         TextKeyListener listener1 = TextKeyListener.getInstance();
         TextKeyListener listener2 = TextKeyListener.getInstance();
@@ -133,32 +148,35 @@
         listener2.release();
     }
 
+    @Test
     public void testOnSpanChanged() {
         TextKeyListener textKeyListener = TextKeyListener.getInstance();
         final Spannable text = new SpannableStringBuilder("123456");
         textKeyListener.onSpanChanged(text, Selection.SELECTION_END, 0, 0, 0, 0);
 
-        try {
-            textKeyListener.onSpanChanged(null, Selection.SELECTION_END, 0, 0, 0, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
         textKeyListener.release();
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testOnSpanChangedNull() {
+        TextKeyListener textKeyListener = TextKeyListener.getInstance();
+        textKeyListener.onSpanChanged(null, Selection.SELECTION_END, 0, 0, 0, 0);
+    }
+
     @UiThreadTest
+    @Test
     public void testClear() {
         CharSequence text = "123456";
         mTextView.setText(text, BufferType.EDITABLE);
 
-        Editable content = (Editable) mTextView.getText();
+        Editable content = mTextView.getText();
         assertEquals(text, content.toString());
 
         TextKeyListener.clear(content);
         assertEquals("", content.toString());
     }
 
+    @Test
     public void testOnSpanRemoved() {
         TextKeyListener textKeyListener = new TextKeyListener(Capitalize.CHARACTERS, true);
         final Spannable text = new SpannableStringBuilder("123456");
@@ -183,22 +201,21 @@
      * 1. press KEYCODE_4 once. if it's ALPHA key board, text will be "4", if it's
      *    NUMERIC key board, text will be "g", else text will be "".
      */
-    public void testPressKey() {
+    @Test
+    public void testPressKey() throws Throwable {
         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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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();
@@ -214,17 +231,16 @@
         textKeyListener.release();
     }
 
-    public void testOnKeyOther() {
+    @Test
+    public void testOnKeyOther() throws Throwable {
         final String text = "abcd";
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setText("", BufferType.EDITABLE);
+            Selection.setSelection(mTextView.getText(), 0, 0);
+            mTextView.setKeyListener(textKeyListener);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals("", mTextView.getText().toString());
@@ -232,7 +248,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
@@ -240,6 +256,7 @@
         textKeyListener.release();
     }
 
+    @Test
     public void testGetInputType() {
         TextKeyListener listener = TextKeyListener.getInstance(false, Capitalize.NONE);
         int expected = InputType.TYPE_CLASS_TEXT;
@@ -252,28 +269,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/TextMethodUtils.java b/tests/tests/text/src/android/text/method/cts/TextMethodUtils.java
index 0785cff..dbeb1e8 100644
--- a/tests/tests/text/src/android/text/method/cts/TextMethodUtils.java
+++ b/tests/tests/text/src/android/text/method/cts/TextMethodUtils.java
@@ -18,26 +18,8 @@
 
 import android.view.KeyEvent;
 
-import junit.framework.Assert;
-
 public class TextMethodUtils {
     /**
-     * Assert that two char arrays are equal.
-     *
-     * @param expected the expected char array.
-     * @param actual the actual char array.
-     */
-    public static void assertEquals(char[] expected, char[] actual) {
-        if (expected != actual) {
-            if (expected == null || actual == null) {
-                Assert.fail("the char arrays are not equal");
-            }
-
-            Assert.assertEquals(String.valueOf(expected), String.valueOf(actual));
-        }
-    }
-
-    /**
      * Get an unaccepted key code.
      *
      * @param acceptedChars accepted chars array.
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..6701515 100644
--- a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
@@ -16,26 +16,32 @@
 
 package android.text.method.cts;
 
-import android.cts.util.KeyEventUtil;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.text.method.TimeKeyListener;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TimeKeyListenerTest extends KeyListenerTestCase {
-
-    private KeyEventUtil mKeyEventUtil;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mKeyEventUtil = new KeyEventUtil(getInstrumentation());
-    }
-
+    @Test
     public void testConstructor() {
         new TimeKeyListener();
     }
 
+    @Test
     public void testGetInstance() {
         TimeKeyListener listener1 = TimeKeyListener.getInstance();
         TimeKeyListener listener2 = TimeKeyListener.getInstance();
@@ -45,12 +51,13 @@
         assertSame(listener1, listener2);
     }
 
+    @Test
     public void testGetAcceptedChars() {
         MockTimeKeyListener mockTimeKeyListener = new MockTimeKeyListener();
-        TextMethodUtils.assertEquals(TimeKeyListener.CHARACTERS,
-                mockTimeKeyListener.getAcceptedChars());
+        assertArrayEquals(TimeKeyListener.CHARACTERS, mockTimeKeyListener.getAcceptedChars());
     }
 
+    @Test
     public void testGetInputType() {
         TimeKeyListener listener = TimeKeyListener.getInstance();
         int expected = InputType.TYPE_CLASS_DATETIME
@@ -68,6 +75,7 @@
      * 6. Press an unaccepted key if it exists and this key could not be entered.
      * 7. Remove TimeKeyListener, '1' key will not be accepted.
      */
+    @Test
     public void testTimeKeyListener() {
         final TimeKeyListener timeKeyListener = TimeKeyListener.getInstance();
         String expectedText = "";
@@ -76,12 +84,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 +97,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..8bd4fda 100644
--- a/tests/tests/text/src/android/text/method/cts/TouchTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java
@@ -16,10 +16,17 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout;
 import android.text.SpannableString;
 import android.text.TextPaint;
@@ -29,8 +36,14 @@
 import android.view.MotionEvent;
 import android.widget.TextView;
 
-public class TouchTest extends ActivityInstrumentationTestCase2<CtsActivity> {
-    private Activity mActivity;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TouchTest {
     private static final String LONG_TEXT = "Scrolls the specified widget to the specified " +
             "coordinates, except constrains the X scrolling position to the horizontal regions " +
             "of the text that will be visible after scrolling to the specified Y position." +
@@ -40,80 +53,64 @@
             "of the text that will be visible after scrolling to the specified Y position." +
             "This is the description of the test.";
 
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private boolean mReturnFromTouchEvent;
+    private TextView mTextView;
 
-    public TouchTest() {
-        super("android.text.cts", CtsActivity.class);
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
+
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTextView = new TextViewNoIme(mActivity);
+        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testScrollTo() throws Throwable {
-        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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mTextView);
+            mTextView.setSingleLine(true);
+            mTextView.setLines(2);
         });
-        getInstrumentation().waitForIdleSync();
-        TextPaint paint = tv.getPaint();
-        final Layout layout = tv.getLayout();
+        mInstrumentation.waitForIdleSync();
+        TextPaint paint = mTextView.getPaint();
+        final Layout layout = mTextView.getLayout();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                tv.setText(LONG_TEXT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mTextView.setText(LONG_TEXT));
+        mInstrumentation.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(width - tv.getWidth() - 1, tv.getScrollX());
-        assertEquals(0, tv.getScrollY());
+        mActivityRule.runOnUiThread(
+                () -> Touch.scrollTo(mTextView, layout, width - mTextView.getWidth() - 1, 0));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(width - mTextView.getWidth() - 1, mTextView.getScrollX());
+        assertEquals(0, mTextView.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(width - tv.getWidth(), tv.getScrollX(), 1.0f);
-        assertEquals(5, tv.getScrollY());
+        mActivityRule.runOnUiThread(() -> Touch.scrollTo(mTextView, layout, width + 100, 5));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(width - mTextView.getWidth(), mTextView.getScrollX(), 1.0f);
+        assertEquals(5, mTextView.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                Touch.scrollTo(tv, layout, width - 10, 5);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(width - tv.getWidth(), tv.getScrollX(), 1.0f);
-        assertEquals(5, tv.getScrollY());
+        mActivityRule.runOnUiThread(() -> Touch.scrollTo(mTextView, layout, width - 10, 5));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(width - mTextView.getWidth(), mTextView.getScrollX(), 1.0f);
+        assertEquals(5, mTextView.getScrollY());
     }
 
+    @Test
     public void testOnTouchEvent() throws Throwable {
-        final TextView tv = new TextViewNoIme(mActivity);
-        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
-
         // Create a string that is wider than the screen.
         DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
         int screenWidth = metrics.widthPixels;
-        TextPaint paint = tv.getPaint();
+        TextPaint paint = mTextView.getPaint();
         String text = LONG_TEXT;
         int textWidth = Math.round(paint.measureText(text));
         while (textWidth < screenWidth) {
@@ -126,14 +123,12 @@
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(mTextView);
+            mTextView.setSingleLine(true);
+            mTextView.setText(finalText);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
@@ -143,49 +138,40 @@
                 MotionEvent.ACTION_MOVE, 0, 0, 0);
         final MotionEvent event3 = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_UP, 0, 0, 0);
-        assertEquals(0, tv.getScrollX());
-        assertEquals(0, tv.getScrollY());
+        assertEquals(0, mTextView.getScrollX());
+        assertEquals(0, mTextView.getScrollY());
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event1);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event1));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has not been scrolled.
-        assertEquals(0, tv.getScrollX());
-        assertEquals(0, tv.getScrollY());
-        assertEquals(0, Touch.getInitialScrollX(tv, spannable));
-        assertEquals(0, Touch.getInitialScrollY(tv, spannable));
+        assertEquals(0, mTextView.getScrollX());
+        assertEquals(0, mTextView.getScrollY());
+        assertEquals(0, Touch.getInitialScrollX(mTextView, spannable));
+        assertEquals(0, Touch.getInitialScrollY(mTextView, spannable));
 
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event2);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event2));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has been scrolled.
-        assertEquals(dragAmount, tv.getScrollX());
-        assertEquals(0, tv.getScrollY());
-        assertEquals(0, Touch.getInitialScrollX(tv, spannable));
-        assertEquals(0, Touch.getInitialScrollY(tv, spannable));
+        assertEquals(dragAmount, mTextView.getScrollX());
+        assertEquals(0, mTextView.getScrollY());
+        assertEquals(0, Touch.getInitialScrollX(mTextView, spannable));
+        assertEquals(0, Touch.getInitialScrollY(mTextView, spannable));
 
         mReturnFromTouchEvent = false;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mReturnFromTouchEvent = Touch.onTouchEvent(tv, spannable, event3);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> mReturnFromTouchEvent = Touch.onTouchEvent(mTextView, spannable, event3));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mReturnFromTouchEvent);
         // TextView has not been scrolled.
-        assertEquals(dragAmount, tv.getScrollX());
-        assertEquals(0, tv.getScrollY());
-        assertEquals(-1, Touch.getInitialScrollX(tv, spannable));
-        assertEquals(-1, Touch.getInitialScrollY(tv, spannable));
+        assertEquals(dragAmount, mTextView.getScrollX());
+        assertEquals(0, mTextView.getScrollY());
+        assertEquals(-1, Touch.getInitialScrollX(mTextView, spannable));
+        assertEquals(-1, Touch.getInitialScrollY(mTextView, spannable));
     }
 
     private int getTextWidth(String str, TextPaint paint) {
diff --git a/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java b/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java
index 2954087..ab524a7 100644
--- a/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java
+++ b/tests/tests/text/src/android/text/method/cts/WordIteratorTest.java
@@ -16,117 +16,128 @@
 
 package android.text.method.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.WordIterator;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.text.BreakIterator;
 
-import junit.framework.TestCase;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WordIteratorTest {
+    private WordIterator mWordIterator = new WordIterator();
 
-public class WordIteratorTest extends TestCase {
-
-    WordIterator wi = new WordIterator();
-
-    private void checkIsWordWithSurrogate(int beginning, int end, int surrogateIndex) {
+    private void verifyIsWordWithSurrogate(int beginning, int end, int surrogateIndex) {
         for (int i = beginning; i <= end; i++) {
             if (i == surrogateIndex) continue;
-            assertEquals(beginning, wi.getBeginning(i));
-            assertEquals(end, wi.getEnd(i));
+            assertEquals(beginning, mWordIterator.getBeginning(i));
+            assertEquals(end, mWordIterator.getEnd(i));
         }
     }
 
     private void setCharSequence(String string) {
-        wi.setCharSequence(string, 0, string.length());
+        mWordIterator.setCharSequence(string, 0, string.length());
     }
 
-    private void checkIsWord(int beginning, int end) {
-        checkIsWordWithSurrogate(beginning, end, -1);
+    private void verifyIsWord(int beginning, int end) {
+        verifyIsWordWithSurrogate(beginning, end, -1);
     }
 
-    private void checkIsNotWord(int beginning, int end) {
+    private void verifyIsNotWord(int beginning, int end) {
         for (int i = beginning; i <= end; i++) {
-            assertEquals(BreakIterator.DONE, wi.getBeginning(i));
-            assertEquals(BreakIterator.DONE, wi.getEnd(i));
+            assertEquals(BreakIterator.DONE, mWordIterator.getBeginning(i));
+            assertEquals(BreakIterator.DONE, mWordIterator.getEnd(i));
         }
     }
 
+    @Test
     public void testEmptyString() {
         setCharSequence("");
-        assertEquals(BreakIterator.DONE, wi.following(0));
-        assertEquals(BreakIterator.DONE, wi.preceding(0));
+        assertEquals(BreakIterator.DONE, mWordIterator.following(0));
+        assertEquals(BreakIterator.DONE, mWordIterator.preceding(0));
 
-        assertEquals(BreakIterator.DONE, wi.getBeginning(0));
-        assertEquals(BreakIterator.DONE, wi.getEnd(0));
+        assertEquals(BreakIterator.DONE, mWordIterator.getBeginning(0));
+        assertEquals(BreakIterator.DONE, mWordIterator.getEnd(0));
     }
 
+    @Test
     public void testOneWord() {
         setCharSequence("I");
-        checkIsWord(0, 1);
+        verifyIsWord(0, 1);
 
         setCharSequence("am");
-        checkIsWord(0, 2);
+        verifyIsWord(0, 2);
 
         setCharSequence("zen");
-        checkIsWord(0, 3);
+        verifyIsWord(0, 3);
     }
 
+    @Test
     public void testSpacesOnly() {
         setCharSequence(" ");
-        checkIsNotWord(0, 1);
+        verifyIsNotWord(0, 1);
 
         setCharSequence(", ");
-        checkIsNotWord(0, 2);
+        verifyIsNotWord(0, 2);
 
         setCharSequence(":-)");
-        checkIsNotWord(0, 3);
+        verifyIsNotWord(0, 3);
     }
 
+    @Test
     public void testBeginningEnd() {
         setCharSequence("Well hello,   there! ");
         //                  0123456789012345678901
-        checkIsWord(0, 4);
-        checkIsWord(5, 10);
-        checkIsNotWord(11, 13);
-        checkIsWord(14, 19);
-        checkIsNotWord(20, 21);
+        verifyIsWord(0, 4);
+        verifyIsWord(5, 10);
+        verifyIsNotWord(11, 13);
+        verifyIsWord(14, 19);
+        verifyIsNotWord(20, 21);
 
         setCharSequence("  Another - sentence");
         //                  012345678901234567890
-        checkIsNotWord(0, 1);
-        checkIsWord(2, 9);
-        checkIsNotWord(10, 11);
-        checkIsWord(12, 20);
+        verifyIsNotWord(0, 1);
+        verifyIsWord(2, 9);
+        verifyIsNotWord(10, 11);
+        verifyIsWord(12, 20);
 
         setCharSequence("This is \u0644\u0627 tested"); // Lama-aleph
         //                  012345678     9     01234567
-        checkIsWord(0, 4);
-        checkIsWord(5, 7);
-        checkIsWord(8, 10);
-        checkIsWord(11, 17);
+        verifyIsWord(0, 4);
+        verifyIsWord(5, 7);
+        verifyIsWord(8, 10);
+        verifyIsWord(11, 17);
     }
 
+    @Test
     public void testSurrogate() {
         final String BAIRKAN = "\uD800\uDF31";
 
         setCharSequence("one we" + BAIRKAN + "ird word");
         //                  012345    67         890123456
 
-        checkIsWord(0, 3);
+        verifyIsWord(0, 3);
         // Skip index 7 (there is no point in starting between the two surrogate characters)
-        checkIsWordWithSurrogate(4, 11, 7);
-        checkIsWord(12, 16);
+        verifyIsWordWithSurrogate(4, 11, 7);
+        verifyIsWord(12, 16);
 
         setCharSequence("one " + BAIRKAN + "xxx word");
         //                  0123    45         678901234
 
-        checkIsWord(0, 3);
-        checkIsWordWithSurrogate(4, 9, 5);
-        checkIsWord(10, 14);
+        verifyIsWord(0, 3);
+        verifyIsWordWithSurrogate(4, 9, 5);
+        verifyIsWord(10, 14);
 
         setCharSequence("one xxx" + BAIRKAN + " word");
         //                  0123456    78         901234
 
-        checkIsWord(0, 3);
-        checkIsWordWithSurrogate(4, 9, 8);
-        checkIsWord(10, 14);
+        verifyIsWord(0, 3);
+        verifyIsWordWithSurrogate(4, 9, 8);
+        verifyIsWord(10, 14);
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java b/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
index e825bd1..ac04619 100644
--- a/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/AbsoluteSizeSpanTest.java
@@ -16,14 +16,22 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.AbsoluteSizeSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class AbsoluteSizeSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsoluteSizeSpanTest {
+    @Test
     public void testConstructor() {
         new AbsoluteSizeSpan(0);
         new AbsoluteSizeSpan(-5);
@@ -39,6 +47,7 @@
         }
     }
 
+    @Test
     public void testGetSize() {
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(5);
         assertEquals(5, absoluteSizeSpan.getSize());
@@ -47,64 +56,73 @@
         assertEquals(-5, absoluteSizeSpan.getSize());
     }
 
+    @Test
     public void testGetDip() {
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(5);
         assertEquals(false, absoluteSizeSpan.getDip());
 
         absoluteSizeSpan = new AbsoluteSizeSpan(5, true);
-        assertEquals(true, absoluteSizeSpan.getDip());
+        assertTrue(absoluteSizeSpan.getDip());
     }
 
+    @Test
     public void testUpdateMeasureState() {
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(1);
 
         TextPaint tp = new TextPaint();
         absoluteSizeSpan.updateMeasureState(tp);
-        assertEquals(1.0f, tp.getTextSize());
+        assertEquals(1.0f, tp.getTextSize(), 0.0f);
 
         absoluteSizeSpan = new AbsoluteSizeSpan(10);
         absoluteSizeSpan.updateMeasureState(tp);
-        assertEquals(10.0f, tp.getTextSize());
-
-        try {
-            absoluteSizeSpan.updateMeasureState(null);
-            fail("should throw NullPointerException when TextPaint is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(10.0f, tp.getTextSize(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        // Should throw NullPointerException when TextPaint is null
+        AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(1);
+
+        absoluteSizeSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         // new the AbsoluteSizeSpan instance
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(2);
 
         TextPaint tp = new TextPaint();
         absoluteSizeSpan.updateDrawState(tp);
-        assertEquals(2.0f, tp.getTextSize());
+        assertEquals(2.0f, tp.getTextSize(), 0.0f);
 
         // new the AbsoluteSizeSpan instance
         absoluteSizeSpan = new AbsoluteSizeSpan(20);
         absoluteSizeSpan.updateDrawState(tp);
-        assertEquals(20.0f, tp.getTextSize());
-
-        try {
-            absoluteSizeSpan.updateDrawState(null);
-            fail("should throw NullPointerException when TextPaint is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(20.0f, tp.getTextSize(), 0.0f);
     }
 
+
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        // Should throw NullPointerException when TextPaint is null
+        AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(2);
+
+        absoluteSizeSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(2);
         absoluteSizeSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(2);
         absoluteSizeSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/AlignmentSpan_StandardTest.java b/tests/tests/text/src/android/text/style/cts/AlignmentSpan_StandardTest.java
index 26ed21e..78bcd6a 100644
--- a/tests/tests/text/src/android/text/style/cts/AlignmentSpan_StandardTest.java
+++ b/tests/tests/text/src/android/text/style/cts/AlignmentSpan_StandardTest.java
@@ -16,17 +16,24 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.style.AlignmentSpan.Standard;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Standard}.
  */
-public class AlignmentSpan_StandardTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlignmentSpan_StandardTest {
+    @Test
     public void testConstructor() {
         new Standard(Alignment.ALIGN_CENTER);
 
@@ -41,6 +48,7 @@
         }
     }
 
+    @Test
     public void testGetAlignment() {
         Standard standard = new Standard(Alignment.ALIGN_NORMAL);
         assertEquals(Alignment.ALIGN_NORMAL, standard.getAlignment());
@@ -52,16 +60,19 @@
         assertEquals(Alignment.ALIGN_CENTER, standard.getAlignment());
     }
 
+    @Test
     public void testDescribeContents() {
         Standard standard = new Standard(Alignment.ALIGN_NORMAL);
         standard.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         Standard standard = new Standard(Alignment.ALIGN_NORMAL);
         standard.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/BackgroundColorSpanTest.java b/tests/tests/text/src/android/text/style/cts/BackgroundColorSpanTest.java
index 690da5d..2724dfe 100644
--- a/tests/tests/text/src/android/text/style/cts/BackgroundColorSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/BackgroundColorSpanTest.java
@@ -16,15 +16,22 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Color;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.BackgroundColorSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class BackgroundColorSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BackgroundColorSpanTest {
+    @Test
     public void testConstructor() {
         BackgroundColorSpan b = new BackgroundColorSpan(Color.GREEN);
 
@@ -38,6 +45,7 @@
         }
     }
 
+    @Test
     public void testUpdateDrawState() {
         BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.BLACK);
 
@@ -48,15 +56,16 @@
         backgroundColorSpan = new BackgroundColorSpan(Color.BLUE);
         backgroundColorSpan.updateDrawState(tp);
         assertEquals(Color.BLUE, tp.bgColor);
-
-        try {
-            backgroundColorSpan.updateDrawState(null);
-            fail("did not throw NullPointerException when TextPaint is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.BLACK);
+
+        backgroundColorSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testGetBackgroundColor() {
         BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.CYAN);
         assertEquals(Color.CYAN, backgroundColorSpan.getBackgroundColor());
@@ -65,16 +74,19 @@
         assertEquals(Color.GRAY, backgroundColorSpan.getBackgroundColor());
     }
 
+    @Test
     public void testDescribeContents() {
         BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.RED);
         backgroundColorSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.RED);
         backgroundColorSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/BulletSpanTest.java b/tests/tests/text/src/android/text/style/cts/BulletSpanTest.java
index 18add4e..4d1985b 100644
--- a/tests/tests/text/src/android/text/style/cts/BulletSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/BulletSpanTest.java
@@ -16,18 +16,25 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
 import android.text.Spanned;
 import android.text.style.BulletSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class BulletSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BulletSpanTest {
+    @Test
     public void testConstructor() {
         new BulletSpan();
         new BulletSpan(BulletSpan.STANDARD_GAP_WIDTH);
@@ -43,6 +50,7 @@
         }
     }
 
+    @Test
     public void testGetLeadingMargin() {
         BulletSpan bulletSpan = new BulletSpan(1);
         int leadingMargin1 = bulletSpan.getLeadingMargin(true);
@@ -53,6 +61,7 @@
         assertTrue(leadingMargin2 > leadingMargin1);
     }
 
+    @Test
     public void testDrawLeadingMargin() {
         BulletSpan bulletSpan = new BulletSpan(10, 20);
 
@@ -63,36 +72,36 @@
         bulletSpan.drawLeadingMargin(canvas, paint, 10, 0, 10, 0, 20, text, 0, 0, true, null);
     }
 
-    public void testDrawLeadingMarginFailure() {
-        // new the BulletSpan instance
+    @Test(expected=ClassCastException.class)
+    public void testDrawLeadingMarginString() {
         BulletSpan bulletSpan = new BulletSpan(10, 20);
 
-        try {
-            String text = "cts test.";
-            bulletSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, text, 0, 0, true, null);
-            fail("did not throw ClassCastException when use a String as text");
-        } catch (ClassCastException e) {
-            // expected, test success.
-        }
-
-        try {
-            bulletSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, null, 0, 0, false, null);
-            fail("did not throw NullPointerException when text is null");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        String text = "cts test.";
+        // Should throw ClassCastException when use a String as text
+        bulletSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, text, 0, 0, true, null);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawLeadingMarginNull() {
+        BulletSpan bulletSpan = new BulletSpan(10, 20);
+
+        // Should throw NullPointerException when text is null
+        bulletSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, null, 0, 0, false, null);
+    }
+
+    @Test
     public void testDescribeContents() {
         BulletSpan bulletSpan = new BulletSpan();
         bulletSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         BulletSpan bulletSpan = new BulletSpan();
         bulletSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         int leadingMargin1 = 0;
         int leadingMargin2 = 0;
diff --git a/tests/tests/text/src/android/text/style/cts/CharacterStyleTest.java b/tests/tests/text/src/android/text/style/cts/CharacterStyleTest.java
index 49a811f..791f362 100644
--- a/tests/tests/text/src/android/text/style/cts/CharacterStyleTest.java
+++ b/tests/tests/text/src/android/text/style/cts/CharacterStyleTest.java
@@ -16,15 +16,25 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.CharacterStyle;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.SuperscriptSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class CharacterStyleTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CharacterStyleTest {
+    @Test
     public void testWrap() {
         // use a MetricAffectingSpan
         MetricAffectingSpan metricAffectingSpan = new SuperscriptSpan();
@@ -51,6 +61,7 @@
         assertTrue(result instanceof CharacterStyle);
     }
 
+    @Test
     public void testGetUnderlying() {
         CharacterStyle expected = new MyCharacterStyle();
         assertSame(expected, expected.getUnderlying());
@@ -62,13 +73,9 @@
         assertSame(metricAffectingSpan, result.getUnderlying());
     }
 
-    /**
-     * MyCharacterStyle for test.
-     */
     private class MyCharacterStyle extends CharacterStyle {
         @Override
         public void updateDrawState(TextPaint tp) {
-            // implement abstract method.
         }
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/ClickableSpanTest.java b/tests/tests/text/src/android/text/style/cts/ClickableSpanTest.java
index 3ef6562..a00a28d 100644
--- a/tests/tests/text/src/android/text/style/cts/ClickableSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ClickableSpanTest.java
@@ -16,15 +16,24 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Color;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.ClickableSpan;
 import android.view.View;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ClickableSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClickableSpanTest {
+    @Test
     public void testUpdateDrawState() {
         ClickableSpan clickableSpan = new MyClickableSpan();
 
@@ -41,22 +50,19 @@
         clickableSpan.updateDrawState(tp);
         assertEquals(Color.BLUE, tp.getColor());
         assertTrue(tp.isUnderlineText());
-
-        try {
-            clickableSpan.updateDrawState(null);
-            fail("should throw NullPointerException when TextPaint is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
-    /**
-     * MyClickableSpan for test.
-     */
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        ClickableSpan clickableSpan = new MyClickableSpan();
+
+        // Should throw NullPointerException when TextPaint is null
+        clickableSpan.updateDrawState(null);
+    }
+
     private class MyClickableSpan extends ClickableSpan {
         @Override
         public void onClick(View widget) {
-            // implement abstract method.
         }
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java b/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
index 775f035..4ccf3bd 100644
--- a/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/DrawableMarginSpanTest.java
@@ -16,53 +16,72 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
-
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint.FontMetricsInt;
 import android.graphics.drawable.Drawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
 import android.text.Layout;
 import android.text.Spanned;
 import android.text.StaticLayout;
 import android.text.TextPaint;
+import android.text.cts.R;
 import android.text.style.DrawableMarginSpan;
 
-public class DrawableMarginSpanTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DrawableMarginSpanTest {
+    private Context mContext;
+    private Drawable mDrawable;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mDrawable = mContext.getDrawable(R.drawable.scenery);
+    }
+
+    @Test
     public void testConstructor() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
 
         new DrawableMarginSpan(d);
         new DrawableMarginSpan(d, 1);
         new DrawableMarginSpan(null, -1);
     }
 
+    @Test
     public void testGetLeadingMargin() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
-
-        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(drawable, 1);
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 1);
         int leadingMargin1 = drawableMarginSpan.getLeadingMargin(true);
 
-        drawableMarginSpan = new DrawableMarginSpan(drawable, 10);
+        drawableMarginSpan = new DrawableMarginSpan(mDrawable, 10);
         int leadingMargin2 = drawableMarginSpan.getLeadingMargin(true);
 
         assertTrue(leadingMargin2 > leadingMargin1);
     }
 
+    @Test
     public void testDrawLeadingMargin() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
-        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(drawable, 0);
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
 
-        assertEquals(0, drawable.getBounds().top);
-        assertEquals(0, drawable.getBounds().bottom);
-        assertEquals(0, drawable.getBounds().left);
-        assertEquals(0, drawable.getBounds().right);
+        assertEquals(0, mDrawable.getBounds().top);
+        assertEquals(0, mDrawable.getBounds().bottom);
+        assertEquals(0, mDrawable.getBounds().left);
+        assertEquals(0, mDrawable.getBounds().right);
 
         Canvas canvas = new Canvas();
         Spanned text = Html.fromHtml("<b>hello</b>");
-        TextPaint paint= new TextPaint();
+        TextPaint paint = new TextPaint();
         Layout layout = new StaticLayout("cts test.", paint, 200,
                 Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
 
@@ -71,31 +90,32 @@
                 0, 0, text, 0, 0, true, layout);
 
         // 0 means the top location
-        assertEquals(0, drawable.getBounds().top);
-        assertEquals(0 + drawable.getIntrinsicHeight(), drawable.getBounds().bottom);
-        assertEquals(x, drawable.getBounds().left);
-        assertEquals(x + drawable.getIntrinsicWidth(), drawable.getBounds().right);
-
-        try {
-            drawableMarginSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0,
-                    null, 0, 0, false, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            drawableMarginSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0,
-                    "cts test.", 0, 0, false, null);
-            fail("When try to use a String as the text, should throw ClassCastException.");
-        } catch (ClassCastException e) {
-            // expected, test success.
-        }
+        assertEquals(0, mDrawable.getBounds().top);
+        assertEquals(mDrawable.getIntrinsicHeight(), mDrawable.getBounds().bottom);
+        assertEquals(x, mDrawable.getBounds().left);
+        assertEquals(x + mDrawable.getIntrinsicWidth(), mDrawable.getBounds().right);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawLeadingMarginNull() {
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
+
+        drawableMarginSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0,
+                null, 0, 0, false, null);
+    }
+
+    @Test(expected=ClassCastException.class)
+    public void testDrawLeadingMarginString() {
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
+
+        // When try to use a String as the text, should throw ClassCastException
+        drawableMarginSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0,
+                "cts test.", 0, 0, false, null);
+    }
+
+    @Test
     public void testChooseHeight() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
-        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(drawable, 0);
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
 
         Spanned text = Html.fromHtml("cts test.");
         FontMetricsInt fm = new FontMetricsInt();
@@ -115,19 +135,21 @@
         assertTrue(fm.descent > 0);
         assertEquals(0, fm.leading);
         assertEquals(0, fm.top);
+    }
 
-        try {
-            drawableMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testChooseHeightNull() {
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
 
-        try {
-            drawableMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
-            fail("When try to use a String as the text, should throw ClassCastException.");
-        } catch (ClassCastException e) {
-            // expected, test success.
-        }
+        drawableMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
+    }
+
+
+    @Test(expected=ClassCastException.class)
+    public void testChooseHeightString() {
+        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(mDrawable, 0);
+
+        // When try to use a String as the text, should throw ClassCastException
+        drawableMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java b/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
index 8a178f8..5ad529b 100644
--- a/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/DynamicDrawableSpanTest.java
@@ -16,17 +16,25 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.cts.R;
 import android.text.style.DynamicDrawableSpan;
 
-public class DynamicDrawableSpanTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DynamicDrawableSpanTest {
+    @Test
     public void testConstructor() {
         DynamicDrawableSpan d = new MyDynamicDrawableSpan();
         assertEquals(DynamicDrawableSpan.ALIGN_BOTTOM, d.getVerticalAlignment());
@@ -38,6 +46,7 @@
         assertEquals(DynamicDrawableSpan.ALIGN_BOTTOM, d.getVerticalAlignment());
     }
 
+    @Test
     public void testGetSize() {
         DynamicDrawableSpan dynamicDrawableSpan = new MyDynamicDrawableSpan();
         FontMetricsInt fm = new FontMetricsInt();
@@ -60,22 +69,20 @@
         assertEquals(rect.right, dynamicDrawableSpan.getSize(null, null, 0, 0, null));
     }
 
+    @Test
     public void testDraw() {
         DynamicDrawableSpan dynamicDrawableSpan = new MyDynamicDrawableSpan();
         Canvas canvas = new Canvas();
         dynamicDrawableSpan.draw(canvas, null, 0, 0, 1.0f, 0, 0, 1, null);
-
-        try {
-            dynamicDrawableSpan.draw(null, null, 0, 0, 1.0f, 0, 0, 1, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
-    /**
-     * The MyDynamicDrawableSpan for test.
-     */
+    @Test(expected=NullPointerException.class)
+    public void testDrawNullCanvas() {
+        DynamicDrawableSpan dynamicDrawableSpan = new MyDynamicDrawableSpan();
+
+        dynamicDrawableSpan.draw(null, null, 0, 0, 1.0f, 0, 0, 1, null);
+    }
+
     private class MyDynamicDrawableSpan extends DynamicDrawableSpan {
         public MyDynamicDrawableSpan() {
             super();
@@ -87,8 +94,7 @@
 
         @Override
         public Drawable getDrawable() {
-            // implement abstract method
-            return getContext().getResources().getDrawable(R.drawable.scenery);
+            return InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.scenery);
         }
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java b/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java
index 7405107..831ce09 100644
--- a/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/EasyEditSpanTest.java
@@ -19,15 +19,23 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.EasyEditSpan;
 
-public class EasyEditSpanTest extends AndroidTestCase {
-    @SmallTest
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EasyEditSpanTest {
+    @Test
     public void testConstructor() {
         new EasyEditSpan();
-        new EasyEditSpan(PendingIntent.getActivity(getContext(), 0, new Intent(), 0));
+        new EasyEditSpan(PendingIntent.getActivity(
+                InstrumentationRegistry.getTargetContext(), 0, new Intent(), 0));
+
         Parcel p = Parcel.obtain();
         try {
             new EasyEditSpan(p);
@@ -36,19 +44,19 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testDescribeContents_doesNotThrowException() {
         EasyEditSpan easyEditSpan = new EasyEditSpan();
         easyEditSpan.describeContents();
     }
 
-    @SmallTest
+    @Test
     public void testGetSpanTypeId_doesNotThrowException() {
         EasyEditSpan easyEditSpan = new EasyEditSpan();
         easyEditSpan.getSpanTypeId();
     }
 
-    @SmallTest
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/ForegroundColorSpanTest.java b/tests/tests/text/src/android/text/style/cts/ForegroundColorSpanTest.java
index bacf89b..a259065 100644
--- a/tests/tests/text/src/android/text/style/cts/ForegroundColorSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ForegroundColorSpanTest.java
@@ -16,15 +16,22 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Color;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.ForegroundColorSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ForegroundColorSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ForegroundColorSpanTest {
+    @Test
     public void testConstructor() {
         ForegroundColorSpan f = new ForegroundColorSpan(Color.GREEN);
 
@@ -38,6 +45,7 @@
         }
     }
 
+    @Test
     public void testGetForegroundColor() {
         ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.BLUE);
         assertEquals(Color.BLUE, foregroundColorSpan.getForegroundColor());
@@ -46,6 +54,7 @@
         assertEquals(Color.BLACK, foregroundColorSpan.getForegroundColor());
     }
 
+    @Test
     public void testUpdateDrawState() {
         ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.CYAN);
 
@@ -58,25 +67,28 @@
         foregroundColorSpan = new ForegroundColorSpan(Color.DKGRAY);
         foregroundColorSpan.updateDrawState(tp);
         assertEquals(Color.DKGRAY, tp.getColor());
-
-        try {
-            foregroundColorSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.CYAN);
+
+        foregroundColorSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
         foregroundColorSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
         foregroundColorSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/IconMarginSpanTest.java b/tests/tests/text/src/android/text/style/cts/IconMarginSpanTest.java
index f9442ce..3ee2564 100644
--- a/tests/tests/text/src/android/text/style/cts/IconMarginSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/IconMarginSpanTest.java
@@ -16,11 +16,14 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint.FontMetricsInt;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
 import android.text.Layout;
 import android.text.Spanned;
@@ -28,19 +31,26 @@
 import android.text.TextPaint;
 import android.text.style.IconMarginSpan;
 
-public class IconMarginSpanTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IconMarginSpanTest {
     private static final int WIDTH = 80;
     private static final int HEIGHT = 120;
     private static final int[] COLOR = new int[WIDTH * HEIGHT];
     private static final Bitmap BITMAP_80X120 =
         Bitmap.createBitmap(COLOR, WIDTH, HEIGHT, Bitmap.Config.RGB_565);
 
+    @Test
     public void testConstructor() {
         new IconMarginSpan(BITMAP_80X120);
         new IconMarginSpan(BITMAP_80X120, 1);
         new IconMarginSpan(null, -1);
     }
 
+    @Test
     public void testGetLeadingMargin() {
         IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 1);
         int leadingMargin1 = iconMarginSpan.getLeadingMargin(true);
@@ -51,6 +61,7 @@
         assertTrue(leadingMargin2 > leadingMargin1);
     }
 
+    @Test
     public void testDrawLeadingMargin() {
         IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
         Canvas c = new Canvas();
@@ -59,22 +70,24 @@
         Layout layout = new StaticLayout("cts test.", p, 200, Layout.Alignment.ALIGN_NORMAL,
                 1, 0, true);
         iconMarginSpan.drawLeadingMargin(c, p, 0, 0, 0, 0, 0, text, 0, 0, true, layout);
-
-        try {
-            iconMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            iconMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
-            fail("When try to use a String as the text, should throw ClassCastException.");
-        } catch (ClassCastException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawLeadingMarginNull() {
+        IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
+
+        iconMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
+    }
+
+    @Test(expected=ClassCastException.class)
+    public void testDrawLeadingMarginString() {
+        IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
+
+        // When try to use a String as the text, should throw ClassCastException
+        iconMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
+    }
+
+    @Test
     public void testChooseHeight() {
         IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
 
@@ -94,19 +107,20 @@
         assertEquals(HEIGHT, fm.descent);
         assertEquals(0, fm.leading);
         assertEquals(0, fm.top);
+    }
 
-        try {
-            iconMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testChooseHeightNull() {
+        IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
 
-        try {
-            iconMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
-            fail("When try to use a String as the text, should throw ClassCastException.");
-        } catch (ClassCastException e) {
-            // expected, test success.
-        }
+        iconMarginSpan.chooseHeight(null, 0, 0, 0, 0, null);
+    }
+
+    @Test(expected=ClassCastException.class)
+    public void testChooseHeightString() {
+        IconMarginSpan iconMarginSpan = new IconMarginSpan(BITMAP_80X120, 0);
+
+        // When try to use a String as the text, should throw ClassCastException
+        iconMarginSpan.chooseHeight("cts test.", 0, 0, 0, 0, null);
     }
 }
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..130593b 100644
--- a/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ImageSpanTest.java
@@ -16,20 +16,39 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 
 import android.content.Context;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.cts.R;
 import android.text.style.DynamicDrawableSpan;
 import android.text.style.ImageSpan;
 
-public class ImageSpanTest extends AndroidTestCase {
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImageSpanTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() {
         int width = 80;
         int height = 120;
@@ -40,6 +59,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);
@@ -69,8 +92,9 @@
         new ImageSpan((Context) null, -1, -1);
     }
 
+    @Test
     public void testGetSource() {
-        Drawable d = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable d = mContext.getDrawable(R.drawable.pass);
 
         ImageSpan imageSpan = new ImageSpan(d);
         assertNull(imageSpan.getSource());
@@ -84,8 +108,9 @@
         assertEquals(source, imageSpan.getSource());
     }
 
+    @Test
     public void testGetDrawable() {
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.pass);
+        Drawable drawable = mContext.getDrawable(R.drawable.pass);
 
         ImageSpan imageSpan = new ImageSpan(drawable);
         assertSame(drawable, imageSpan.getDrawable());
diff --git a/tests/tests/text/src/android/text/style/cts/LeadingMarginSpan_StandardTest.java b/tests/tests/text/src/android/text/style/cts/LeadingMarginSpan_StandardTest.java
index cbca876..6679caf 100644
--- a/tests/tests/text/src/android/text/style/cts/LeadingMarginSpan_StandardTest.java
+++ b/tests/tests/text/src/android/text/style/cts/LeadingMarginSpan_StandardTest.java
@@ -16,14 +16,21 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.Standard;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class LeadingMarginSpan_StandardTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LeadingMarginSpan_StandardTest {
+    @Test
     public void testConstructor() {
         new Standard(1, 2);
         new Standard(3);
@@ -41,6 +48,7 @@
         }
     }
 
+    @Test
     public void testGetLeadingMargin() {
         int first = 4;
         int rest = 5;
@@ -54,21 +62,25 @@
         assertEquals(-1, standard.getLeadingMargin(false));
     }
 
+    @Test
     public void testDrawLeadingMargin() {
         Standard standard = new LeadingMarginSpan.Standard(10);
         standard.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, null, 0, 0, false, null);
     }
 
+    @Test
     public void testDescribeContents() {
         Standard standard = new Standard(1);
         standard.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         Standard standard = new Standard(1);
         standard.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java b/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
index bb7cdd9..bc07e0a 100644
--- a/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/LocaleSpanTest.java
@@ -16,17 +16,24 @@
 
 package android.text.style.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
 import android.annotation.NonNull;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.LocaleSpan;
 
-public class LocaleSpanTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private void checkGetLocales(@NonNull final LocaleList locales) {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocaleSpanTest {
+
+    private void verifyGetLocales(@NonNull final LocaleList locales) {
         final LocaleSpan span = new LocaleSpan(locales);
         assertEquals(locales.get(0), span.getLocale());
         assertEquals(locales, span.getLocales());
@@ -36,23 +43,17 @@
         assertEquals(locales, cloned.getLocales());
     }
 
-    @SmallTest
+    @Test
     public void testGetLocales() {
-        checkGetLocales(LocaleList.getEmptyLocaleList());
-        checkGetLocales(LocaleList.forLanguageTags("en"));
-        checkGetLocales(LocaleList.forLanguageTags("en-GB,en"));
-        checkGetLocales(LocaleList.forLanguageTags("de-DE-u-co-phonebk,en-GB,en"));
+        verifyGetLocales(LocaleList.getEmptyLocaleList());
+        verifyGetLocales(LocaleList.forLanguageTags("en"));
+        verifyGetLocales(LocaleList.forLanguageTags("en-GB,en"));
+        verifyGetLocales(LocaleList.forLanguageTags("de-DE-u-co-phonebk,en-GB,en"));
     }
 
-    @SmallTest
+    @Test(expected=NullPointerException.class)
     public void testConstructorWithLocaleList() {
-        try {
-            new LocaleSpan((LocaleList) null);
-        } catch (NullPointerException e) {
-            // Expected.
-            return;
-        }
-        fail("NullPointerException must have been thrown.");
+        new LocaleSpan((LocaleList) null);
     }
 
     @NonNull
@@ -70,19 +71,19 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testDescribeContents_doesNotThrowException() {
         LocaleSpan localeSpan = new LocaleSpan(LocaleList.getEmptyLocaleList());
         localeSpan.describeContents();
     }
 
-    @SmallTest
+    @Test
     public void testGetSpanTypeId_doesNotThrowException() {
         LocaleSpan localeSpan = new LocaleSpan(LocaleList.getEmptyLocaleList());
         localeSpan.getSpanTypeId();
     }
 
-    @SmallTest
+    @Test
     public void testUpdateDrawState() {
         LocaleList localeListForSpan = LocaleList.forLanguageTags("en");
         LocaleSpan localeSpan = new LocaleSpan(localeListForSpan);
@@ -98,7 +99,7 @@
         assertEquals(localeListForSpan.get(0), tp.getTextLocale());
     }
 
-    @SmallTest
+    @Test
     public void testUpdateMeasureState() {
         LocaleList localeListForSpan = LocaleList.forLanguageTags("en");
         LocaleSpan localeSpan = new LocaleSpan(localeListForSpan);
diff --git a/tests/tests/text/src/android/text/style/cts/MaskFilterSpanTest.java b/tests/tests/text/src/android/text/style/cts/MaskFilterSpanTest.java
index 0ed33c9..7b9f3d9 100644
--- a/tests/tests/text/src/android/text/style/cts/MaskFilterSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/MaskFilterSpanTest.java
@@ -16,20 +16,29 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 
 import android.graphics.MaskFilter;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.MaskFilterSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class MaskFilterSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MaskFilterSpanTest {
+    @Test
     public void testConstructor() {
         MaskFilter mf = new MaskFilter();
         new MaskFilterSpan(mf);
         new MaskFilterSpan(null);
     }
 
+    @Test
     public void testUpdateDrawState() {
         MaskFilter mf = new MaskFilter();
         MaskFilterSpan maskFilterSpan = new MaskFilterSpan(mf);
@@ -39,15 +48,17 @@
 
         maskFilterSpan.updateDrawState(tp);
         assertSame(mf, tp.getMaskFilter());
-
-        try {
-            maskFilterSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        MaskFilter mf = new MaskFilter();
+        MaskFilterSpan maskFilterSpan = new MaskFilterSpan(mf);
+
+        maskFilterSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testGetMaskFilter() {
         MaskFilter expected = new MaskFilter();
 
diff --git a/tests/tests/text/src/android/text/style/cts/MetricAffectingSpanTest.java b/tests/tests/text/src/android/text/style/cts/MetricAffectingSpanTest.java
index af6533c..cb8850e 100644
--- a/tests/tests/text/src/android/text/style/cts/MetricAffectingSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/MetricAffectingSpanTest.java
@@ -16,15 +16,24 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.CharacterStyle;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.SuperscriptSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class MetricAffectingSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MetricAffectingSpanTest {
+    @Test
     public void testGetUnderlying() {
         MetricAffectingSpan metricAffectingSpan = new MyMetricAffectingSpan();
         assertSame(metricAffectingSpan, metricAffectingSpan.getUnderlying());
@@ -36,18 +45,13 @@
         assertSame(metricAffectingSpan, result.getUnderlying());
     }
 
-    /**
-     * MyMetricAffectingSpan for test.
-     */
     private class MyMetricAffectingSpan extends MetricAffectingSpan {
         @Override
         public void updateMeasureState(TextPaint p) {
-            // implement abstract method.
         }
 
         @Override
         public void updateDrawState(TextPaint tp) {
-            // implement abstract method.
         }
     }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java b/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
index be06b0d..cfff271 100644
--- a/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
+++ b/tests/tests/text/src/android/text/style/cts/MockURLSpanTestActivity.java
@@ -16,10 +16,9 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.text.cts.R;
 
 /**
  * A Mock application for {@link URLSpan} test.
diff --git a/tests/tests/text/src/android/text/style/cts/QuoteSpanTest.java b/tests/tests/text/src/android/text/style/cts/QuoteSpanTest.java
index a19c926..358be07 100644
--- a/tests/tests/text/src/android/text/style/cts/QuoteSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/QuoteSpanTest.java
@@ -16,16 +16,23 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.QuoteSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class QuoteSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class QuoteSpanTest {
+    @Test
     public void testConstructor() {
         new QuoteSpan();
         QuoteSpan q = new QuoteSpan(Color.RED);
@@ -40,6 +47,7 @@
         }
     }
 
+    @Test
     public void testGetLeadingMargin() {
         QuoteSpan quoteSpan = new QuoteSpan();
 
@@ -47,6 +55,7 @@
         quoteSpan.getLeadingMargin(false);
     }
 
+    @Test
     public void testGetColor() {
         QuoteSpan quoteSpan = new QuoteSpan(Color.BLACK);
         assertEquals(Color.BLACK, quoteSpan.getColor());
@@ -55,31 +64,35 @@
         assertEquals(Color.BLUE, quoteSpan.getColor());
     }
 
+    @Test
     public void testDrawLeadingMargin() {
         QuoteSpan quoteSpan = new QuoteSpan();
 
         Canvas c = new Canvas();
         Paint p = new Paint();
         quoteSpan.drawLeadingMargin(c, p, 0, 0, 0, 0, 0, null, 0, 0, true, null);
-
-        try {
-            quoteSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, null, 0, 0, true, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testDrawLeadingMarginNull() {
+        QuoteSpan quoteSpan = new QuoteSpan();
+
+        quoteSpan.drawLeadingMargin(null, null, 0, 0, 0, 0, 0, null, 0, 0, true, null);
+    }
+
+    @Test
     public void testDescribeContents() {
         QuoteSpan quoteSpan = new QuoteSpan(Color.RED);
         quoteSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         QuoteSpan quoteSpan = new QuoteSpan(Color.RED);
         quoteSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/RasterizerSpanTest.java b/tests/tests/text/src/android/text/style/cts/RasterizerSpanTest.java
deleted file mode 100644
index 8c5f71e..0000000
--- a/tests/tests/text/src/android/text/style/cts/RasterizerSpanTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-package android.text.style.cts;
-
-
-import android.graphics.Rasterizer;
-import android.text.TextPaint;
-import android.text.style.RasterizerSpan;
-
-import junit.framework.TestCase;
-
-public class RasterizerSpanTest extends TestCase {
-    public void testConstructor() {
-        Rasterizer r = new Rasterizer();
-
-        new RasterizerSpan(r);
-        new RasterizerSpan(null);
-    }
-
-    public void testGetRasterizer() {
-        Rasterizer expected = new Rasterizer();
-
-        RasterizerSpan rasterizerSpan = new RasterizerSpan(expected);
-        assertSame(expected, rasterizerSpan.getRasterizer());
-
-        rasterizerSpan = new RasterizerSpan(null);
-        assertNull(rasterizerSpan.getRasterizer());
-    }
-
-    public void testUpdateDrawState() {
-        Rasterizer rasterizer = new Rasterizer();
-        RasterizerSpan rasterizerSpan = new RasterizerSpan(rasterizer);
-
-        TextPaint tp = new TextPaint();
-        assertNull(tp.getRasterizer());
-
-        rasterizerSpan.updateDrawState(tp);
-        assertSame(rasterizer, tp.getRasterizer());
-
-        try {
-            rasterizerSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-    }
-}
diff --git a/tests/tests/text/src/android/text/style/cts/RelativeSizeSpanTest.java b/tests/tests/text/src/android/text/style/cts/RelativeSizeSpanTest.java
index 5f67a0a..3cac62e 100644
--- a/tests/tests/text/src/android/text/style/cts/RelativeSizeSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/RelativeSizeSpanTest.java
@@ -16,14 +16,21 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.RelativeSizeSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class RelativeSizeSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelativeSizeSpanTest {
+    @Test
     public void testConstructor() {
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(1.0f);
 
@@ -39,14 +46,16 @@
         }
     }
 
+    @Test
     public void testGetSizeChange() {
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(2.0f);
-        assertEquals(2.0f, relativeSizeSpan.getSizeChange());
+        assertEquals(2.0f, relativeSizeSpan.getSizeChange(), 0.0f);
 
         relativeSizeSpan = new RelativeSizeSpan(-2.0f);
-        assertEquals(-2.0f, relativeSizeSpan.getSizeChange());
+        assertEquals(-2.0f, relativeSizeSpan.getSizeChange(), 0.0f);
     }
 
+    @Test
     public void testUpdateMeasureState() {
         float proportion = 3.0f;
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(proportion);
@@ -55,22 +64,23 @@
         tp.setTextSize(2.0f);
         float oldSize = tp.getTextSize();
         relativeSizeSpan.updateMeasureState(tp);
-        assertEquals(2.0f * proportion, tp.getTextSize());
+        assertEquals(2.0f * proportion, tp.getTextSize(), 0.0f);
 
         // setTextSize, the value must >0, so set to negative is useless.
         tp.setTextSize(-3.0f);
         oldSize = tp.getTextSize();
         relativeSizeSpan.updateMeasureState(tp);
-        assertEquals(oldSize * proportion, tp.getTextSize());
-
-        try {
-            relativeSizeSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(oldSize * proportion, tp.getTextSize(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(3.0f);
+
+        relativeSizeSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         float proportion = 3.0f;
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(proportion);
@@ -79,32 +89,35 @@
         tp.setTextSize(2.0f);
         float oldSize = tp.getTextSize();
         relativeSizeSpan.updateDrawState(tp);
-        assertEquals(oldSize * proportion, tp.getTextSize());
+        assertEquals(oldSize * proportion, tp.getTextSize(), 0.0f);
 
         // setTextSize, the value must >0, so set to negative is useless.
         tp.setTextSize(-3.0f);
         oldSize = tp.getTextSize();
         relativeSizeSpan.updateDrawState(tp);
-        assertEquals(oldSize * proportion, tp.getTextSize());
-
-        try {
-            relativeSizeSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(oldSize * proportion, tp.getTextSize(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(3.0f);
+
+        relativeSizeSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(2.0f);
         relativeSizeSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(2.0f);
         relativeSizeSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
@@ -113,7 +126,7 @@
             relativeSizeSpan.writeToParcel(p, 0);
             p.setDataPosition(0);
             RelativeSizeSpan newSpan = new RelativeSizeSpan(p);
-            assertEquals(proportion, newSpan.getSizeChange());
+            assertEquals(proportion, newSpan.getSizeChange(), 0.0f);
         } finally {
             p.recycle();
         }
diff --git a/tests/tests/text/src/android/text/style/cts/ReplacementSpanTest.java b/tests/tests/text/src/android/text/style/cts/ReplacementSpanTest.java
index 2af12a1..514e22b 100644
--- a/tests/tests/text/src/android/text/style/cts/ReplacementSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ReplacementSpanTest.java
@@ -16,38 +16,40 @@
 
 package android.text.style.cts;
 
-import junit.framework.TestCase;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
-import android.text.TextPaint;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.ReplacementSpan;
 
-public class ReplacementSpanTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ReplacementSpanTest {
+    @Test
     public void testUpdateMeasureState() {
         ReplacementSpan replacementSpan = new MockReplacementSpan();
         replacementSpan.updateMeasureState(null);
     }
 
+    @Test
     public void testUpdateDrawState() {
         ReplacementSpan replacementSpan = new MockReplacementSpan();
         replacementSpan.updateDrawState(null);
     }
 
-    /**
-     * 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) {
-            // implement abstract method
         }
 
         @Override
         public int getSize(Paint paint, CharSequence text, int start, int end,
                 FontMetricsInt fm) {
-            // implement abstract method
             return 0;
         }
     }
diff --git a/tests/tests/text/src/android/text/style/cts/ScaleXSpanTest.java b/tests/tests/text/src/android/text/style/cts/ScaleXSpanTest.java
index 2ec9f65..d243ef6 100644
--- a/tests/tests/text/src/android/text/style/cts/ScaleXSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/ScaleXSpanTest.java
@@ -16,14 +16,21 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.ScaleXSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ScaleXSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ScaleXSpanTest {
+    @Test
     public void testConstructor() {
         ScaleXSpan scaleXSpan = new ScaleXSpan(1.5f);
 
@@ -39,6 +46,7 @@
         }
     }
 
+    @Test
     public void testUpdateDrawState() {
         float proportion = 3.0f;
         ScaleXSpan scaleXSpan = new ScaleXSpan(proportion);
@@ -46,20 +54,21 @@
         TextPaint tp = new TextPaint();
         tp.setTextScaleX(2.0f);
         scaleXSpan.updateDrawState(tp);
-        assertEquals(2.0f * proportion, tp.getTextScaleX());
+        assertEquals(2.0f * proportion, tp.getTextScaleX(), 0.0f);
 
         tp.setTextScaleX(-3.0f);
         scaleXSpan.updateDrawState(tp);
-        assertEquals(-3.0f * proportion, tp.getTextScaleX());
-
-        try {
-            scaleXSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(-3.0f * proportion, tp.getTextScaleX(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        ScaleXSpan scaleXSpan = new ScaleXSpan(3.0f);
+
+        scaleXSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testUpdateMeasureState() {
         float proportion = 3.0f;
         ScaleXSpan scaleXSpan = new ScaleXSpan(proportion);
@@ -67,38 +76,42 @@
         TextPaint tp = new TextPaint();
         tp.setTextScaleX(2.0f);
         scaleXSpan.updateMeasureState(tp);
-        assertEquals(2.0f * proportion, tp.getTextScaleX());
+        assertEquals(2.0f * proportion, tp.getTextScaleX(), 0.0f);
 
         tp.setTextScaleX(-3.0f);
         scaleXSpan.updateMeasureState(tp);
-        assertEquals(-3.0f * proportion, tp.getTextScaleX());
-
-        try {
-            scaleXSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        assertEquals(-3.0f * proportion, tp.getTextScaleX(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        ScaleXSpan scaleXSpan = new ScaleXSpan(3.0f);
+
+        scaleXSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testGetScaleX() {
         ScaleXSpan scaleXSpan = new ScaleXSpan(5.0f);
-        assertEquals(5.0f, scaleXSpan.getScaleX());
+        assertEquals(5.0f, scaleXSpan.getScaleX(), 0.0f);
 
         scaleXSpan = new ScaleXSpan(-5.0f);
-        assertEquals(-5.0f, scaleXSpan.getScaleX());
+        assertEquals(-5.0f, scaleXSpan.getScaleX(), 0.0f);
     }
 
+    @Test
     public void testDescribeContents() {
         ScaleXSpan scaleXSpan = new ScaleXSpan(5.0f);
         scaleXSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         ScaleXSpan scaleXSpan = new ScaleXSpan(5.0f);
         scaleXSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
@@ -107,7 +120,7 @@
             scaleXSpan.writeToParcel(p, 0);
             p.setDataPosition(0);
             ScaleXSpan newSpan = new ScaleXSpan(p);
-            assertEquals(proportion, newSpan.getScaleX());
+            assertEquals(proportion, newSpan.getScaleX(), 0.0f);
         } finally {
             p.recycle();
         }
diff --git a/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java b/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
index a3c3d9d..aa4ccdd 100644
--- a/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/StrikethroughSpanTest.java
@@ -16,14 +16,22 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.StrikethroughSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class StrikethroughSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StrikethroughSpanTest {
+    @Test
     public void testConstructor() {
         StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
 
@@ -37,6 +45,7 @@
         }
     }
 
+    @Test
     public void testUpdateDrawState() {
         StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
 
@@ -46,25 +55,28 @@
 
         strikethroughSpan.updateDrawState(tp);
         assertTrue(tp.isStrikeThruText());
-
-        try {
-            strikethroughSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
+
+        strikethroughSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
         strikethroughSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
         strikethroughSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/StyleSpanTest.java b/tests/tests/text/src/android/text/style/cts/StyleSpanTest.java
index 753dca4..4b4fc7e 100644
--- a/tests/tests/text/src/android/text/style/cts/StyleSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/StyleSpanTest.java
@@ -16,15 +16,23 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.graphics.Typeface;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.StyleSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class StyleSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StyleSpanTest {
+    @Test
     public void testConstructor() {
         StyleSpan styleSpan = new StyleSpan(2);
 
@@ -40,6 +48,7 @@
         }
     }
 
+    @Test
     public void testGetStyle() {
         StyleSpan styleSpan = new StyleSpan(2);
         assertEquals(2, styleSpan.getStyle());
@@ -48,6 +57,7 @@
         assertEquals(-2, styleSpan.getStyle());
     }
 
+    @Test
     public void testUpdateMeasureState() {
         StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
 
@@ -62,15 +72,16 @@
 
         assertNotNull(tp.getTypeface());
         assertEquals(Typeface.BOLD, tp.getTypeface().getStyle());
-
-        try {
-            styleSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
+
+        styleSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
 
@@ -85,24 +96,28 @@
 
         assertNotNull(tp.getTypeface());
         assertEquals(Typeface.BOLD, tp.getTypeface().getStyle());
-
-        try {
-            styleSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
+
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
+
+        styleSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
         styleSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);
         styleSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/SubscriptSpanTest.java b/tests/tests/text/src/android/text/style/cts/SubscriptSpanTest.java
index 314b342..000be8d 100644
--- a/tests/tests/text/src/android/text/style/cts/SubscriptSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/SubscriptSpanTest.java
@@ -17,13 +17,21 @@
 package android.text.style.cts;
 
 
+import static org.junit.Assert.assertEquals;
+
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.SubscriptSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SubscriptSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SubscriptSpanTest {
+    @Test
     public void testConstructor() {
         SubscriptSpan subscriptSpan = new SubscriptSpan();
 
@@ -37,6 +45,7 @@
         }
     }
 
+    @Test
     public void testUpdateMeasureState() {
         // the expected result is: tp.baselineShift -= (int) (tp.ascent() / 2)
         SubscriptSpan subscriptSpan = new SubscriptSpan();
@@ -48,15 +57,16 @@
 
         subscriptSpan.updateMeasureState(tp);
         assertEquals(baselineShift - (int) (ascent / 2), tp.baselineShift);
-
-        try {
-            subscriptSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        SubscriptSpan subscriptSpan = new SubscriptSpan();
+
+        subscriptSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         // the expected result is: tp.baselineShift -= (int) (tp.ascent() / 2)
         SubscriptSpan subscriptSpan = new SubscriptSpan();
@@ -68,25 +78,28 @@
 
         subscriptSpan.updateDrawState(tp);
         assertEquals(baselineShift - (int) (ascent / 2), tp.baselineShift);
-
-        try {
-            subscriptSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        SubscriptSpan subscriptSpan = new SubscriptSpan();
+
+        subscriptSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         SubscriptSpan subscriptSpan = new SubscriptSpan();
         subscriptSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         SubscriptSpan subscriptSpan = new SubscriptSpan();
         subscriptSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
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..686f9c3 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,145 @@
 
 package android.text.style.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 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.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.SuggestionSpan;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Locale;
 
-public class SuggestionSpanTest extends TestCase {
+/**
+ * Test {@link SuggestionSpan}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SuggestionSpanTest {
+    @Test
+    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 = InstrumentationRegistry.getTargetContext().
+                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());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
+    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.
@@ -48,7 +177,7 @@
         return original.toString();
     }
 
-    private void checkGetLocaleObject(final Locale locale) {
+    private void verifyGetLocaleObject(final Locale locale) {
         final SuggestionSpan span = new SuggestionSpan(locale, new String[0],
                 SuggestionSpan.FLAG_AUTO_CORRECTION);
         // In the context of SuggestionSpan#getLocaleObject(), we do care only about subtags that
@@ -62,17 +191,18 @@
         assertEquals(getNonNullLocaleString(locale), cloned.getLocale());
     }
 
+    @Test
     public void testGetLocaleObject() {
-        checkGetLocaleObject(Locale.forLanguageTag("en"));
-        checkGetLocaleObject(Locale.forLanguageTag("en-GB"));
-        checkGetLocaleObject(Locale.forLanguageTag("EN-GB"));
-        checkGetLocaleObject(Locale.forLanguageTag("en-gb"));
-        checkGetLocaleObject(Locale.forLanguageTag("En-gB"));
-        checkGetLocaleObject(Locale.forLanguageTag("und"));
-        checkGetLocaleObject(Locale.forLanguageTag("de-DE-u-co-phonebk"));
-        checkGetLocaleObject(Locale.forLanguageTag(""));
-        checkGetLocaleObject(null);
-        checkGetLocaleObject(new Locale(" an  ", " i n v a l i d ", "data"));
+        verifyGetLocaleObject(Locale.forLanguageTag("en"));
+        verifyGetLocaleObject(Locale.forLanguageTag("en-GB"));
+        verifyGetLocaleObject(Locale.forLanguageTag("EN-GB"));
+        verifyGetLocaleObject(Locale.forLanguageTag("en-gb"));
+        verifyGetLocaleObject(Locale.forLanguageTag("En-gB"));
+        verifyGetLocaleObject(Locale.forLanguageTag("und"));
+        verifyGetLocaleObject(Locale.forLanguageTag("de-DE-u-co-phonebk"));
+        verifyGetLocaleObject(Locale.forLanguageTag(""));
+        verifyGetLocaleObject(null);
+        verifyGetLocaleObject(new Locale(" an  ", " i n v a l i d ", "data"));
     }
 
     @NonNull
diff --git a/tests/tests/text/src/android/text/style/cts/SuperscriptSpanTest.java b/tests/tests/text/src/android/text/style/cts/SuperscriptSpanTest.java
index 92a2db4..68fa8c8 100644
--- a/tests/tests/text/src/android/text/style/cts/SuperscriptSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/SuperscriptSpanTest.java
@@ -16,14 +16,21 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.SuperscriptSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SuperscriptSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SuperscriptSpanTest {
+    @Test
     public void testConstructor() {
         SuperscriptSpan superscriptSpan = new SuperscriptSpan();
 
@@ -37,6 +44,7 @@
         }
     }
 
+    @Test
     public void testUpdateMeasureState() {
         // the expected result is: tp.baselineShift += (int) (tp.ascent() / 2)
         SuperscriptSpan superscriptSpan = new SuperscriptSpan();
@@ -48,15 +56,16 @@
 
         superscriptSpan.updateMeasureState(tp);
         assertEquals(baselineShift + (int) (ascent / 2), tp.baselineShift);
-
-        try {
-            superscriptSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        SuperscriptSpan superscriptSpan = new SuperscriptSpan();
+
+        superscriptSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         // the expected result is: tp.baselineShift += (int) (tp.ascent() / 2)
         SuperscriptSpan superscriptSpan = new SuperscriptSpan();
@@ -68,25 +77,28 @@
 
         superscriptSpan.updateDrawState(tp);
         assertEquals(baselineShift + (int) (ascent / 2), tp.baselineShift);
-
-        try {
-            superscriptSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        SuperscriptSpan superscriptSpan = new SuperscriptSpan();
+
+        superscriptSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         SuperscriptSpan superscriptSpan = new SuperscriptSpan();
         superscriptSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         SuperscriptSpan superscriptSpan = new SuperscriptSpan();
         superscriptSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/TabStopSpan_StandardTest.java b/tests/tests/text/src/android/text/style/cts/TabStopSpan_StandardTest.java
index f9397f0..34c487e 100644
--- a/tests/tests/text/src/android/text/style/cts/TabStopSpan_StandardTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TabStopSpan_StandardTest.java
@@ -16,17 +16,27 @@
 
 package android.text.style.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.TabStopSpan;
 import android.text.style.TabStopSpan.Standard;
 
-public class TabStopSpan_StandardTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TabStopSpan_StandardTest {
+    @Test
     public void testConstructor() {
         new TabStopSpan.Standard(3);
 
         new TabStopSpan.Standard(-3);
     }
 
+    @Test
     public void testGetTabStop() {
         Standard standard = new Standard(3);
         assertEquals(3, standard.getTabStop());
diff --git a/tests/tests/text/src/android/text/style/cts/TextAppearanceSpanTest.java b/tests/tests/text/src/android/text/style/cts/TextAppearanceSpanTest.java
index 2d45566..5af81d8 100644
--- a/tests/tests/text/src/android/text/style/cts/TextAppearanceSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TextAppearanceSpanTest.java
@@ -16,24 +16,46 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.TextAppearanceSpan;
 
-public class TextAppearanceSpanTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextAppearanceSpanTest {
+    private Context mContext;
+    private ColorStateList mColorStateList;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+
+        int[][] states = new int[][] { new int[0], new int[0] };
+        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
+        mColorStateList = new ColorStateList(states, colors);
+    }
+
+    @Test
     public void testConstructor() {
         new TextAppearanceSpan(mContext, 1);
         new TextAppearanceSpan(mContext, 1, 1);
 
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         Parcel p = Parcel.obtain();
         try {
             textAppearanceSpan.writeToParcel(p, 0);
@@ -42,23 +64,22 @@
         } finally {
             p.recycle();
         }
-        try {
-            new TextAppearanceSpan(null, -1);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
-
-        try {
-            new TextAppearanceSpan(null, -1, -1);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
 
         new TextAppearanceSpan(null, -1, -1, null, null);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new TextAppearanceSpan(null, -1);
+    }
+
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new TextAppearanceSpan(null, -1, -1);
+    }
+
+    @Test
     public void testGetFamily() {
         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 1);
         assertNull(textAppearanceSpan.getFamily());
@@ -66,48 +87,41 @@
         textAppearanceSpan = new TextAppearanceSpan(mContext, 1, 1);
         assertNull(textAppearanceSpan.getFamily());
 
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         assertEquals("sans", textAppearanceSpan.getFamily());
     }
 
+    @Test
     public void testUpdateMeasureState() {
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         TextPaint tp = new TextPaint();
-        tp.setTextSize((float) 1);
-        assertEquals((float) 1, tp.getTextSize());
+        tp.setTextSize(1.0f);
+        assertEquals(1.0f, tp.getTextSize(), 0.0f);
 
         textAppearanceSpan.updateMeasureState(tp);
 
-        assertEquals((float) 6, tp.getTextSize());
-
-        try {
-            textAppearanceSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
+        assertEquals(6.0f, tp.getTextSize(), 0.0f);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
+        textAppearanceSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testGetTextColor() {
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
+        assertSame(mColorStateList, textAppearanceSpan.getTextColor());
 
-        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
-        assertSame(csl, textAppearanceSpan.getTextColor());
-
-        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, null, csl);
+        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, null, mColorStateList);
         assertNull(textAppearanceSpan.getTextColor());
     }
 
+    @Test
     public void testGetTextSize() {
         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 1);
         assertEquals(-1, textAppearanceSpan.getTextSize());
@@ -115,14 +129,11 @@
         textAppearanceSpan = new TextAppearanceSpan(mContext, 1, 1);
         assertEquals(-1, textAppearanceSpan.getTextSize());
 
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         assertEquals(6, textAppearanceSpan.getTextSize());
     }
 
+    @Test
     public void testGetTextStyle() {
         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 1);
         assertEquals(0, textAppearanceSpan.getTextStyle());
@@ -130,32 +141,24 @@
         textAppearanceSpan = new TextAppearanceSpan(mContext, 1, 1);
         assertEquals(0, textAppearanceSpan.getTextStyle());
 
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         assertEquals(1, textAppearanceSpan.getTextStyle());
     }
 
+    @Test
     public void testGetLinkTextColor() {
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
+        assertSame(mColorStateList, textAppearanceSpan.getLinkTextColor());
 
-        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
-        assertSame(csl, textAppearanceSpan.getLinkTextColor());
-
-        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, null);
+        textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, mColorStateList, null);
         assertNull(textAppearanceSpan.getLinkTextColor());
     }
 
+    @Test
     public void testUpdateDrawState() {
-        int[][] states = new int[][] { new int[0], new int[0] };
-        int[] colors = new int[] { Color.rgb(0, 0, 255), Color.BLACK };
-        ColorStateList csl = new ColorStateList(states, colors);
-
-        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans", 1, 6, csl, csl);
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
         TextPaint tp = new TextPaint();
         tp.setColor(0);
         tp.linkColor = 0;
@@ -163,28 +166,32 @@
 
         textAppearanceSpan.updateDrawState(tp);
 
-        int expected = csl.getColorForState(tp.drawableState, 0);
+        int expected = mColorStateList.getColorForState(tp.drawableState, 0);
         assertEquals(expected, tp.getColor());
         assertEquals(expected, tp.linkColor);
-
-        try {
-            textAppearanceSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        TextAppearanceSpan textAppearanceSpan =
+                new TextAppearanceSpan("sans", 1, 6, mColorStateList, mColorStateList);
+
+        textAppearanceSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 1);
         textAppearanceSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(mContext, 1);
         textAppearanceSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         String family = "sans";
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..c8a23fc 100644
--- a/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TtsSpanTest.java
@@ -16,29 +16,36 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.os.Parcel;
 import android.os.PersistableBundle;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.style.TtsSpan;
-import junit.framework.TestCase;
 
-public class TtsSpanTest extends TestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    PersistableBundle bundle;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TtsSpanTest {
+    private PersistableBundle mBundle;
 
-    @Override
-    protected void setUp() {
-        bundle = new PersistableBundle();
-        bundle.putString("argument.one", "value.one");
-        bundle.putString("argument.two", "value.two");
-        bundle.putLong("argument.three", 3);
-        bundle.putLong("argument.four", 4);
+    @Before
+    public void setup() {
+        mBundle = new PersistableBundle();
+        mBundle.putString("argument.one", "value.one");
+        mBundle.putString("argument.two", "value.two");
+        mBundle.putLong("argument.three", 3);
+        mBundle.putLong("argument.four", 4);
     }
 
-    @SmallTest
+    @Test
     public void testGetArgs() {
-        TtsSpan t = new TtsSpan("test.type.one", bundle);
-        PersistableBundle args = t.getArgs();
+        TtsSpan t = new TtsSpan("test.type.one", mBundle);
+        final PersistableBundle args = t.getArgs();
         assertEquals(4, args.size());
         assertEquals("value.one", args.getString("argument.one"));
         assertEquals("value.two", args.getString("argument.two"));
@@ -46,36 +53,36 @@
         assertEquals(4, args.getLong("argument.four"));
     }
 
-    @SmallTest
+    @Test
     public void testGetType() {
-        TtsSpan t = new TtsSpan("test.type.two", bundle);
+        TtsSpan t = new TtsSpan("test.type.two", mBundle);
         assertEquals("test.type.two", t.getType());
     }
 
-    @SmallTest
+    @Test
     public void testDescribeContents() {
-        TtsSpan span = new TtsSpan("test.type.three", bundle);
+        TtsSpan span = new TtsSpan("test.type.three", mBundle);
         span.describeContents();
     }
 
-    @SmallTest
+    @Test
     public void testGetSpanTypeId() {
-        TtsSpan span = new TtsSpan("test.type.four", bundle);
+        TtsSpan span = new TtsSpan("test.type.four", mBundle);
         span.getSpanTypeId();
     }
 
-    @SmallTest
+    @Test
     public void testWriteAndReadParcel() {
         Parcel p = Parcel.obtain();
         try {
-            TtsSpan span = new TtsSpan("test.type.five", bundle);
+            TtsSpan span = new TtsSpan("test.type.five", mBundle);
             span.writeToParcel(p, 0);
             p.setDataPosition(0);
 
             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"));
@@ -86,31 +93,31 @@
         }
     }
 
-    @SmallTest
+    @Test
     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"));
         assertEquals(Long.MAX_VALUE, args.getLong("argument.long"));
     }
 
-    @SmallTest
+    @Test
     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));
@@ -118,249 +125,362 @@
         assertEquals(TtsSpan.CASE_NOMINATIVE, args.getString(TtsSpan.ARG_CASE));
     }
 
-    @SmallTest
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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 +488,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,70 +498,86 @@
             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));
         }
     }
 
-    @SmallTest
+    @Test
     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
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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 +588,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));
@@ -465,41 +601,41 @@
         }
     }
 
-    @SmallTest
+    @Test
     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));
         }
     }
 
-    @SmallTest
+    @Test
     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/TypefaceSpanTest.java b/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
index 7a05167..ffc024a 100644
--- a/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
@@ -16,17 +16,26 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import android.graphics.Typeface;
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.TypefaceSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class TypefaceSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceSpanTest {
     private static final String FAMILY = "monospace";
 
+    @Test
     public void testConstructor() {
         TypefaceSpan t = new TypefaceSpan(FAMILY);
 
@@ -40,11 +49,13 @@
         }
     }
 
+    @Test
     public void testGetFamily() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
         assertEquals(FAMILY, typefaceSpan.getFamily());
     }
 
+    @Test
     public void testUpdateMeasureState() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
 
@@ -56,15 +67,16 @@
         assertNotNull(tp.getTypeface());
         // the style should be default style.
         assertEquals(Typeface.NORMAL, tp.getTypeface().getStyle());
-
-        try {
-            typefaceSpan.updateMeasureState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateMeasureStateNull() {
+        TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
+
+        typefaceSpan.updateMeasureState(null);
+    }
+
+    @Test
     public void testUpdateDrawState() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
 
@@ -76,25 +88,28 @@
         assertNotNull(tp.getTypeface());
         // the style should be default style.
         assertEquals(Typeface.NORMAL, tp.getTypeface().getStyle());
-
-        try {
-            typefaceSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
+
+        typefaceSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
         typefaceSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
         typefaceSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java b/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
index be6c8ae..09dff43 100644
--- a/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
+++ b/tests/tests/text/src/android/text/style/cts/URLSpanCtsActivity.java
@@ -16,10 +16,9 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.text.cts.R;
 
 /**
  * A minimal application for {@link URLSpan} test.
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..067b56b 100644
--- a/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/URLSpanTest.java
@@ -16,32 +16,45 @@
 
 package android.text.style.cts;
 
-import android.text.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
 import android.os.Parcel;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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";
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class URLSpanTest {
+    // 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() {
-        super("android.text.cts", URLSpanCtsActivity.class);
+    @Rule
+    public ActivityTestRule<URLSpanCtsActivity> mActivityRule =
+            new ActivityTestRule<>(URLSpanCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         URLSpan urlSpan = new URLSpan(TEST_URL);
 
@@ -55,55 +68,49 @@
         }
     }
 
+    @Test
     public void testGetURL() {
         URLSpan urlSpan = new URLSpan(TEST_URL);
         assertEquals(TEST_URL, urlSpan.getURL());
     }
 
-    public void testOnClick() {
+    @LargeTest
+    @Test
+    public void testOnClick() throws Throwable {
         final URLSpan urlSpan = new URLSpan(TEST_URL);
         final TextView textView = (TextView) mActivity.findViewById(R.id.url);
 
-        Instrumentation instrumentation = getInstrumentation();
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
                 null, false);
 
-        try {
-            runTestOnUiThread(new Runnable() {
-                public void run() {
-                    urlSpan.onClick(textView);
-                }
-            });
-        } catch (Throwable e) {
-            fail("Exception error!");
-        }
+        mActivityRule.runOnUiThread(() -> urlSpan.onClick(textView));
 
         Activity newActivity = am.waitForActivityWithTimeout(5000);
         assertNotNull(newActivity);
         newActivity.finish();
     }
 
+    @Test(expected=NullPointerException.class)
     public void testOnClickFailure() {
         URLSpan urlSpan = new URLSpan(TEST_URL);
 
-        try {
-            urlSpan.onClick(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        urlSpan.onClick(null);
     }
 
+    @Test
     public void testDescribeContents() {
         URLSpan urlSpan = new URLSpan(TEST_URL);
         urlSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         URLSpan urlSpan = new URLSpan(TEST_URL);
         urlSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
diff --git a/tests/tests/text/src/android/text/style/cts/UnderlineSpanTest.java b/tests/tests/text/src/android/text/style/cts/UnderlineSpanTest.java
index 4f200d2..0661833 100644
--- a/tests/tests/text/src/android/text/style/cts/UnderlineSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/UnderlineSpanTest.java
@@ -16,14 +16,22 @@
 
 package android.text.style.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextPaint;
 import android.text.style.UnderlineSpan;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class UnderlineSpanTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UnderlineSpanTest {
+    @Test
     public void testConstructor() {
         new UnderlineSpan();
 
@@ -35,6 +43,7 @@
         }
     }
 
+    @Test
     public void testUpdateDrawState() {
         UnderlineSpan underlineSpan = new UnderlineSpan();
 
@@ -44,25 +53,28 @@
 
         underlineSpan.updateDrawState(tp);
         assertTrue(tp.isUnderlineText());
-
-        try {
-            underlineSpan.updateDrawState(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testUpdateDrawStateNull() {
+        UnderlineSpan underlineSpan = new UnderlineSpan();
+
+        underlineSpan.updateDrawState(null);
+    }
+
+    @Test
     public void testDescribeContents() {
         UnderlineSpan underlineSpan = new UnderlineSpan();
         underlineSpan.describeContents();
     }
 
+    @Test
     public void testGetSpanTypeId() {
         UnderlineSpan underlineSpan = new UnderlineSpan();
         underlineSpan.getSpanTypeId();
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel p = Parcel.obtain();
         try {
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..d20792e 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -16,9 +16,15 @@
 
 package android.text.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.URLSpan;
@@ -28,6 +34,10 @@
 import android.util.Patterns;
 import android.widget.TextView;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -35,26 +45,26 @@
 /**
  * Test {@link Linkify}.
  */
-public class LinkifyTest extends AndroidTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LinkifyTest {
     private static final Pattern LINKIFY_TEST_PATTERN = Pattern.compile(
             "(test:)?[a-zA-Z0-9]+(\\.pattern)?");
 
-    private MatchFilter mMatchFilterStartWithDot = new MatchFilter() {
-        public final boolean acceptMatch(final CharSequence s, final int start, final int end) {
-            if (start == 0) {
+    private MatchFilter mMatchFilterStartWithDot =
+            (final CharSequence s, final int start, final int end) -> {
+                if (start == 0) {
+                    return true;
+                }
+
+                if (s.charAt(start - 1) == '.') {
+                    return false;
+                }
+
                 return true;
-            }
+            };
 
-            if (s.charAt(start - 1) == '.') {
-                return false;
-            }
-
-            return true;
-        }
-    };
-
-    private TransformFilter mTransformFilterUpperChar = new TransformFilter() {
-        public final String transformUrl(final Matcher match, String url) {
+    private TransformFilter mTransformFilterUpperChar = (final Matcher match, String url) -> {
             StringBuilder buffer = new StringBuilder();
             String matchingRegion = match.group();
 
@@ -67,14 +77,22 @@
                 }
             }
             return buffer.toString();
-        }
-    };
+        };
 
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() {
         new Linkify();
     }
 
-    public void testAddLinks1() {
+    @Test
+    public void testAddLinksToSpannable() {
         // Verify URLs including the ones that have new gTLDs, and the
         // ones that look like gTLDs (and so are accepted by linkify)
         // and the ones that should not be linkified due to non-compliant
@@ -101,44 +119,45 @@
         assertEquals(1, spans.length);
         assertEquals("mailto:name@gmail.com", spans[0].getURL());
 
-        try {
-            Linkify.addLinks((Spannable) null, Linkify.WEB_URLS);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
         assertFalse(Linkify.addLinks((Spannable) null, 0));
     }
 
-    public void testAddLinks2() {
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToSpannableNullWithWebUrls() {
+        Linkify.addLinks((Spannable) null, Linkify.WEB_URLS);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAddLinksToTextView() {
         String text = "www.google.com, name@gmail.com";
         TextView tv = new TextView(mContext);
         tv.setText(text);
 
         assertTrue(Linkify.addLinks(tv, Linkify.WEB_URLS));
-        URLSpan[] spans = ((Spannable)tv.getText()).getSpans(0, text.length(), URLSpan.class);
+        URLSpan[] spans = ((Spannable) tv.getText()).getSpans(0, text.length(), URLSpan.class);
         assertEquals(1, spans.length);
         assertEquals("http://www.google.com", spans[0].getURL());
 
         SpannableString spannable = SpannableString.valueOf(text);
         tv.setText(spannable);
         assertTrue(Linkify.addLinks(tv, Linkify.EMAIL_ADDRESSES));
-        spans = ((Spannable)tv.getText()).getSpans(0, text.length(), URLSpan.class);
+        spans = ((Spannable) tv.getText()).getSpans(0, text.length(), URLSpan.class);
         assertEquals(1, spans.length);
         assertEquals("mailto:name@gmail.com", spans[0].getURL());
 
-        try {
-            Linkify.addLinks((TextView)null, Linkify.WEB_URLS);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        assertFalse(Linkify.addLinks((TextView)null, 0));
+        assertFalse(Linkify.addLinks((TextView) null, 0));
     }
 
-    public void testAddLinks3() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToTextViewNullWithWebUrls() {
+        Linkify.addLinks((TextView) null, Linkify.WEB_URLS);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAddLinksToTextViewWithScheme() {
         String text = "Alan, Charlie";
         TextView tv = new TextView(mContext);
         tv.setText(text);
@@ -157,20 +176,6 @@
         assertEquals("test:google.pattern", spans[0].getURL());
         assertEquals("test:AZ0101.pattern", spans[1].getURL());
 
-        try {
-            Linkify.addLinks((TextView) null, LINKIFY_TEST_PATTERN, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        try {
-            Linkify.addLinks(tv, null, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
         tv = new TextView(mContext);
         tv.setText(text);
         Linkify.addLinks(tv, LINKIFY_TEST_PATTERN, null);
@@ -180,10 +185,26 @@
         assertEquals("test:AZ0101.pattern", spans[1].getURL());
     }
 
-    public void testAddLinks4() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToTextViewWithSchemeNullView() {
+        Linkify.addLinks((TextView) null, LINKIFY_TEST_PATTERN, "Test:");
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToTextViewWithSchemeNullPattern() {
+        TextView tv = new TextView(mContext);
+        tv.setText("Alan, Charlie");
+        Linkify.addLinks(tv, null, "Test:");
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAddLinksToTextViewWithSchemeAndFilter() {
         TextView tv = new TextView(mContext);
 
-        String text =  "FilterUpperCase.pattern, 12.345.pattern";
+        String text = "FilterUpperCase.pattern, 12.345.pattern";
         tv.setText(text);
         Linkify.addLinks(tv, LINKIFY_TEST_PATTERN, "Test:",
                 mMatchFilterStartWithDot, mTransformFilterUpperChar);
@@ -192,22 +213,6 @@
         assertEquals("test:ilterpperase.pattern", spans[0].getURL());
         assertEquals("test:12", spans[1].getURL());
 
-        try {
-            Linkify.addLinks((TextView) null, LINKIFY_TEST_PATTERN, "Test:",
-                    mMatchFilterStartWithDot, mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        try {
-            Linkify.addLinks(tv, null, "Test:",
-                    mMatchFilterStartWithDot, mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
         tv.setText(text);
         Linkify.addLinks(tv, LINKIFY_TEST_PATTERN, null,
                 mMatchFilterStartWithDot, mTransformFilterUpperChar);
@@ -232,7 +237,24 @@
         assertEquals("test:12", spans[1].getURL());
     }
 
-    public void testAddLinks5() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToTextViewWithSchemeAndFilterNullView() {
+        Linkify.addLinks((TextView) null, LINKIFY_TEST_PATTERN, "Test:",
+                mMatchFilterStartWithDot, mTransformFilterUpperChar);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToTextViewWithSchemeAndFilterNullPattern() {
+        TextView tv = new TextView(mContext);
+        tv.setText("FilterUpperCase.pattern, 12.345.pattern");
+        Linkify.addLinks(tv, null, "Test:",
+                mMatchFilterStartWithDot, mTransformFilterUpperChar);
+    }
+
+    @Test
+    public void testAddLinksToSpannableWithScheme() {
         String text = "google.pattern, test:AZ0101.pattern";
 
         SpannableString spannable = new SpannableString(text);
@@ -242,18 +264,6 @@
         assertEquals("test:google.pattern", spans[0].getURL());
         assertEquals("test:AZ0101.pattern", spans[1].getURL());
 
-        try {
-            Linkify.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            Linkify.addLinks(spannable, null, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-        }
-
         spannable = new SpannableString(text);
         Linkify.addLinks(spannable, LINKIFY_TEST_PATTERN, null);
         spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
@@ -262,7 +272,23 @@
         assertEquals("test:AZ0101.pattern", spans[1].getURL());
     }
 
-    public void testAddLinks6() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToSpannableWithSchemeNullSpannable() {
+        Linkify.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:");
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToSpannableWithSchemeNullPattern() {
+        String text = "google.pattern, test:AZ0101.pattern";
+        SpannableString spannable = new SpannableString(text);
+
+        Linkify.addLinks(spannable, null, "Test:");
+    }
+
+    @Test
+    public void testAddLinksToSpannableWithSchemeAndFilter() {
         String text = "FilterUpperCase.pattern, 12.345.pattern";
 
         SpannableString spannable = new SpannableString(text);
@@ -273,22 +299,6 @@
         assertEquals("test:ilterpperase.pattern", spans[0].getURL());
         assertEquals("test:12", spans[1].getURL());
 
-        try {
-            Linkify.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:",
-                    mMatchFilterStartWithDot, mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        try {
-            Linkify.addLinks(spannable, null, "Test:", mMatchFilterStartWithDot,
-                    mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
         spannable = new SpannableString(text);
         Linkify.addLinks(spannable, LINKIFY_TEST_PATTERN, null, mMatchFilterStartWithDot,
                 mTransformFilterUpperChar);
@@ -313,7 +323,25 @@
         assertEquals("test:12", spans[1].getURL());
     }
 
-    public void testAddLinks7() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToSpannableWithSchemeAndFilterNullSpannable() {
+        Linkify.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:",
+                mMatchFilterStartWithDot, mTransformFilterUpperChar);
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddLinksToSpannableWithSchemeAndFilterNullPattern() {
+        String text = "FilterUpperCase.pattern, 12.345.pattern";
+        SpannableString spannable = new SpannableString(text);
+
+        Linkify.addLinks(spannable, null, "Test:", mMatchFilterStartWithDot,
+                mTransformFilterUpperChar);
+    }
+
+    @Test
+    public void testAddLinksPhoneNumbers() {
         String numbersInvalid = "123456789 not a phone number";
         String numbersUKLocal = "tel:(0812)1234560 (0812)1234561";
         String numbersUSLocal = "tel:(812)1234562 (812)123.4563 "
@@ -342,17 +370,10 @@
             assertEquals("tel:+18005551214", spans[8].getURL());
         }
 
-        try {
-            Linkify.addLinks((Spannable) null, Linkify.WEB_URLS);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
         assertFalse(Linkify.addLinks((Spannable) null, 0));
     }
 
-    @SmallTest
+    @Test
     public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() {
         Spannable spannable = new SpannableString("any https://android.com any android.com any");
         Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, null, null, null);
@@ -363,7 +384,7 @@
         assertEquals("android.com", spans[1].getURL());
     }
 
-    @SmallTest
+    @Test
     public void testAddLinks_addsLinksWhenSchemesArrayIsNull() {
         Spannable spannable = new SpannableString("any https://android.com any android.com any");
         Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://", null, null);
@@ -375,7 +396,7 @@
         assertEquals("http://android.com", spans[1].getURL());
     }
 
-    @SmallTest
+    @Test
     public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() {
         Spannable spannable = new SpannableString("any android.com any");
         Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
@@ -386,7 +407,7 @@
         assertEquals("http://android.com", spans[0].getURL());
     }
 
-    @SmallTest
+    @Test
     public void testAddLinks_doesNotPrependSchemeIfSchemeExists() {
         Spannable spannable = new SpannableString("any https://android.com any");
         Linkify.addLinks(spannable, Patterns.AUTOLINK_WEB_URL, "http://",
@@ -399,7 +420,8 @@
 
     // Add links with scheme (array)
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testAddLinks_withTextView_addsLinksWhenDefaultSchemeIsNull() {
         Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
         TextView textView = new TextView(mContext);
@@ -413,7 +435,8 @@
         assertEquals("android.com", spans[1].getURL());
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testAddLinks_withTextView_addsLinksWhenSchemesArrayIsNull() {
         Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
         TextView textView = new TextView(mContext);
@@ -428,7 +451,8 @@
         assertEquals("http://android.com", spans[1].getURL());
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testAddLinks_withTextView_prependsDefaultSchemeToBeginingOfLink() {
         Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
         TextView textView = new TextView(mContext);
@@ -442,7 +466,8 @@
         assertEquals("http://android.com", spans[0].getURL());
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testAddLinks_withTextView_doesNotPrependSchemeIfSchemeExists() {
         Pattern pattern = Pattern.compile("\\b((http|https)://)?android\\.com+\\b");
         TextView textView = new TextView(mContext);
@@ -458,189 +483,183 @@
 
     // WEB_URLS Related Tests
 
-    @SmallTest
+    @Test
     public void testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld()
-            throws Exception {
+            {
         Spannable spannable = new SpannableString("hey man.its me");
         boolean linksAdded = Linkify.addLinks(spannable, Linkify.ALL);
         assertFalse("Should not add link with unknown TLD", linksAdded);
     }
 
-    @SmallTest
-    public void testAddLinks_shouldNotAddEmailAddressAsUrl() throws Exception {
+    @Test
+    public void testAddLinks_shouldNotAddEmailAddressAsUrl() {
         String url = "name@gmail.com";
-        assertAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
+        verifyAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
     }
 
-    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() throws Exception {
+    @Test
+    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() {
         String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
-        assertAddLinksWithWebUrlSucceeds("Should accept commas", url);
+        verifyAddLinksWithWebUrlSucceeds("Should accept commas", url);
     }
 
-    @SmallTest
-    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() throws Exception {
+    @Test
+    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() {
         String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        assertAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not" +
+        verifyAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not" +
                 " have TLD", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesProtocolCaseInsensitive() throws Exception {
+    @Test
+    public void testAddLinks_matchesProtocolCaseInsensitive() {
         String url = "hTtP://android.com";
-        assertAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
+        verifyAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() throws Exception {
+    @Test
+    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() {
         String url = "http://www.android.com";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+    @Test
+    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() {
         String url = "http://www.android.me";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
                 url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+    @Test
+    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() {
         String url = "android.camera";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesPunycodeUrl() throws Exception {
+    @Test
+    public void testAddLinks_matchesPunycodeUrl() {
         String url = "http://xn--fsqu00a.xn--unup4y";
-        assertAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() throws Exception {
+    @Test
+    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() {
         String url = "xn--fsqu00a.xn--unup4y";
-        assertAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
     }
 
-    @SmallTest
-    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
+    @Test
+    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() {
         String url = "xn--fsqu00a.-xn--unup4y";
-        assertAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
+        verifyAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
     }
 
-    @SmallTest
-    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() throws Exception {
+    @Test
+    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() {
         String url = "http://xn--fsqu00a.xn--unup4y-";
-        assertAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends " +
+        verifyAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends " +
                 "with dash", "http://xn--fsqu00a.xn--unup4y", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithUnicodeDomainName() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainName() {
         String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() {
         String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode " +
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode " +
                 "domain name", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() {
         String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithUnicodePath() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodePath() {
         String url = "http://android.com/\u2019/a";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesValidUrlWithPort() throws Exception {
+    @Test
+    public void testAddLinks_matchesValidUrlWithPort() {
         String url = "http://www.example.com:8080";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with port", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithPortAndQuery() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithPortAndQuery() {
         String url = "http://www.example.com:8080/?foo=bar";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlWithTilde() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlWithTilde() {
         String url = "http://www.example.com:8080/~user/?foo=bar";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
+    @Test
+    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() {
         String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        assertAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
                 url);
     }
 
-    @SmallTest
-    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() throws Exception {
+    @Test
+    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() {
         String url = "thank.you";
-        assertAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol " +
+        verifyAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol " +
                 "and does not contain a known TLD", url);
     }
 
-    @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 {
+    @Test
+    public void testAddLinks_matchesValidUrlWithEmoji() {
         String url = "Thank\u263A.com";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
     }
 
-    @SmallTest
+    @Test
     public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
-            throws Exception {
+            {
         String url = "Thank\u263A.you";
-        assertAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown " +
+        verifyAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown " +
                 "TLD", url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesDomainNameWithSurrogatePairs() throws Exception {
+    @Test
+    public void testAddLinks_matchesDomainNameWithSurrogatePairs() {
         String url = "android\uD83C\uDF38.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
                 url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesTldWithSurrogatePairs() throws Exception {
+    @Test
+    public void testAddLinks_matchesTldWithSurrogatePairs() {
         String url = "http://android.\uD83C\uDF38com";
-        assertAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
     }
 
-    @SmallTest
-    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
+    @Test
+    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() {
         String url = "android\uD83F\uDFFE.com";
-        assertAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate" +
+        verifyAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate" +
                 " pair",  url);
     }
 
-    @SmallTest
-    public void testAddLinks_matchesPathWithSurrogatePairs() throws Exception {
+    @Test
+    public void testAddLinks_matchesPathWithSurrogatePairs() {
         String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38f";
-        assertAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
                 url);
     }
 
-    @SmallTest
-    public void testAddLinks__doesNotMatchUnicodeSpaces() throws Exception {
+    @Test
+    public void testAddLinks__doesNotMatchUnicodeSpaces() {
         String part1 = "http://and";
         String part2 = "roid.com";
         String[] emptySpaces = new String[]{
@@ -664,196 +683,269 @@
 
         for (String emptySpace : emptySpaces) {
             String url = part1 + emptySpace + part2;
-            assertAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: " +
+            verifyAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: " +
                     emptySpace.codePointAt(0), part1, url);
         }
     }
 
+    @Test
+    public void testAddLinks_matchesDomainNameWithDash() {
+        String url = "http://a-nd.r-oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+
+        url = "a-nd.r-oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesDomainNameWithUnderscore() {
+        String url = "http://a_nd.r_oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+
+        url = "a_nd.r_oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesPathAndQueryWithDollarSign() {
+        String url = "http://android.com/path$?v=$val";
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+
+        url = "android.com/path$?v=$val";
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesEmptyPathWithQueryParams() {
+        String url = "http://android.com?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "http://android.com/?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com/?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+    }
+
     // EMAIL_ADDRESSES Related Tests
 
-    public void testAddLinks_email_matchesShortValidEmail() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesShortValidEmail() {
         String email = "a@a.co";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesRegularEmail() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesRegularEmail() {
         String email = "email@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() {
         String email = "email@e.somelongdomainnameforandroid.abc.uk";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithDot() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDot() {
         String email = "e.mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithPlus() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithPlus() {
         String email = "e+mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithUnderscore() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithUnderscore() {
         String email = "e_mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithDash() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDash() {
         String email = "e-mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithApostrophe() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithApostrophe() {
         String email = "e'mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithDigits() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDigits() {
         String email = "123@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesUnicodeLocalPart() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesUnicodeLocalPart() {
         String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartWithEmoji() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithEmoji() {
         String email = "smiley\u263A@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_matchesLocalPartWithSurrogatePairs()
-            throws Exception {
+            {
         String email = "a\uD83C\uDF38a@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesDomainWithDash() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesDomainWithDash() {
         String email = "email@an-droid.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesUnicodeDomain() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesUnicodeDomain() {
         String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_matchesUnicodeLocalPartAndDomain()
-            throws Exception {
+            {
         String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesDomainWithEmoji() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesDomainWithEmoji() {
         String email = "smiley@\u263Aandroid.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_matchesDomainWithSurrogatePairs()
-            throws Exception {
+            {
         String email = "email@\uD83C\uDF38android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_matchesLocalPartAndDomainWithSurrogatePairs()
-            throws Exception {
+            {
         String email = "a\uD83C\uDF38a@\uD83C\uDF38android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
-    public void testAddLinks_partiallyMatchesEmailEndingWithDot() throws Exception {
+    @Test
+    public void testAddLinks_partiallyMatchesEmailEndingWithDot() {
         String email = "email@android.co.uk.";
-        assertAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
                 "mailto:email@android.co.uk", email);
     }
 
+    @Test
     public void testAddLinks_email_partiallyMatchesLocalPartStartingWithDot()
-            throws Exception {
+            {
         String email = ".email@android.com";
-        assertAddLinksWithEmailPartiallyMatches("Should partially match email starting " +
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email starting " +
                 "with dot", "mailto:email@android.com", email);
     }
 
-    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() throws Exception {
+    @Test
+    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() {
         String email = "android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
-    public void testAddLinks_email_doesNotMatchPlainString() throws Exception {
+    @Test
+    public void testAddLinks_email_doesNotMatchPlainString() {
         String email = "email";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
-    public void testAddLinks_email_doesNotMatchEmailWithoutTld() throws Exception {
+    @Test
+    public void testAddLinks_email_doesNotMatchEmailWithoutTld() {
         String email = "email@android";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_doesNotMatchLocalPartEndingWithDot()
-            throws Exception {
+            {
         String email = "email.@android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_doesNotMatchDomainStartingWithDash()
-            throws Exception {
+            {
         String email = "email@-android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_doesNotMatchDomainWithConsecutiveDots()
-            throws Exception {
+            {
         String email = "email@android..com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
-    public void testAddLinks_email_doesNotMatchEmailWithIp() throws Exception {
+    @Test
+    public void testAddLinks_email_doesNotMatchEmailWithIp() {
         String email = "email@127.0.0.1";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
+    @Test
     public void testAddLinks_email_doesNotMatchEmailWithInvalidTld()
-            throws Exception {
+            {
         String email = "email@android.c";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
-    public void testAddLinks_email_matchesLocalPartUpTo64Chars() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesLocalPartUpTo64Chars() {
         String localPart = "";
         for (int i = 0; i < 64; i++) {
             localPart += "a";
         }
         String email = localPart + "@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email local part of length: " +
+        verifyAddLinksWithEmailSucceeds("Should match email local part of length: " +
                 localPart.length(), email);
 
         email = localPart + "a@android.com";
-        assertAddLinksWithEmailFails("Should not match email local part of length:" +
+        verifyAddLinksWithEmailFails("Should not match email local part of length:" +
                 localPart.length(), email);
     }
 
-    public void testAddLinks_email_matchesSubdomainUpTo63Chars() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesSubdomainUpTo63Chars() {
         String subdomain = "";
         for (int i = 0; i < 63; i++) {
             subdomain += "a";
         }
         String email = "email@" + subdomain + ".com";
 
-        assertAddLinksWithEmailSucceeds("Should match email subdomain of length: " +
+        verifyAddLinksWithEmailSucceeds("Should match email subdomain of length: " +
                 subdomain.length(), email);
 
         subdomain += "a";
         email = "email@" + subdomain + ".com";
 
-        assertAddLinksWithEmailFails("Should not match email subdomain of length:" +
+        verifyAddLinksWithEmailFails("Should not match email subdomain of length:" +
                 subdomain.length(), email);
     }
 
-    public void testAddLinks_email_matchesDomainUpTo255Chars() throws Exception {
+    @Test
+    public void testAddLinks_email_matchesDomainUpTo255Chars() {
         String domain = "";
         while (domain.length() <= 250) {
             domain += "d.";
@@ -861,42 +953,42 @@
         domain += "com";
         assertEquals(255, domain.length());
         String email = "a@" + domain;
-        assertAddLinksWithEmailSucceeds("Should match email domain of length: " +
+        verifyAddLinksWithEmailSucceeds("Should match email domain of length: " +
                 domain.length(), email);
 
         email = email + "m";
-        assertAddLinksWithEmailFails("Should not match email domain of length:" +
+        verifyAddLinksWithEmailFails("Should not match email domain of length:" +
                 domain.length(), email);
     }
 
     // Utility functions
-    private static void assertAddLinksWithWebUrlSucceeds(String msg, String url) {
-        assertAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
+    private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithWebUrlFails(String msg, String url) {
-        assertAddLinksFails(msg, url, Linkify.WEB_URLS);
+    private static void verifyAddLinksWithWebUrlFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
+    private static void verifyAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
             String url) {
-        assertAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithEmailSucceeds(String msg, String url) {
-        assertAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
+    private static void verifyAddLinksWithEmailSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksWithEmailFails(String msg, String url) {
-        assertAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
+    private static void verifyAddLinksWithEmailFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksWithEmailPartiallyMatches(String msg, String expected,
+    private static void verifyAddLinksWithEmailPartiallyMatches(String msg, String expected,
             String url) {
-        assertAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksSucceeds(String msg, String string, int type) {
+    private static void verifyAddLinksSucceeds(String msg, String string, int type) {
         String str = "start " + string + " end";
         Spannable spannable = new SpannableString(str);
 
@@ -910,14 +1002,14 @@
                 str.length() - " end".length(), spannable.getSpanEnd(spans[0]));
     }
 
-    private static void assertAddLinksFails(String msg, String string, int type) {
+    private static void verifyAddLinksFails(String msg, String string, int type) {
         Spannable spannable = new SpannableString("start " + string + " end");
         boolean linksAdded = Linkify.addLinks(spannable, type);
         assertFalse(msg, linksAdded);
     }
 
-    private static void assertAddLinksPartiallyMatches(String msg, String expected,
-                                                       String string, int type) {
+    private static void verifyAddLinksPartiallyMatches(String msg, String expected,
+            String string, int type) {
         Spannable spannable = new SpannableString("start " + string + " end");
         boolean linksAdded = Linkify.addLinks(spannable, type);
         URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
diff --git a/tests/tests/text/src/android/text/util/cts/Rfc822TokenTest.java b/tests/tests/text/src/android/text/util/cts/Rfc822TokenTest.java
index fc826df..47c4544 100644
--- a/tests/tests/text/src/android/text/util/cts/Rfc822TokenTest.java
+++ b/tests/tests/text/src/android/text/util/cts/Rfc822TokenTest.java
@@ -16,14 +16,23 @@
 
 package android.text.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.util.Rfc822Token;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link Rfc822Token}.
  */
-public class Rfc822TokenTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Rfc822TokenTest {
+    @Test
     public void testConstructor() {
         final String name = "John Doe";
         final String address = "jdoe@example.net";
@@ -49,6 +58,7 @@
         assertNull(rfc822Token4.getComment());
     }
 
+    @Test
     public void testAccessName() {
         String name = "John Doe";
         final String address = "jdoe@example.net";
@@ -68,19 +78,19 @@
         assertNull(rfc822Token.getName());
     }
 
+    @Test
     public void testQuoteComment() {
         assertEquals("work", Rfc822Token.quoteComment("work"));
 
         assertEquals("\\\\\\(work\\)", Rfc822Token.quoteComment("\\(work)"));
-
-        try {
-            Rfc822Token.quoteComment(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed to happen if comment is null.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testQuoteCommentNull() {
+        Rfc822Token.quoteComment(null);
+    }
+
+    @Test
     public void testAccessComment() {
         final String name = "John Doe";
         final String address = "jdoe@example.net";
@@ -100,6 +110,7 @@
         assertNull(rfc822Token.getComment());
     }
 
+    @Test
     public void testAccessAddress() {
         final String name = "John Doe";
         String address = "jdoe@example.net";
@@ -119,6 +130,7 @@
         assertNull(rfc822Token.getAddress());
     }
 
+    @Test
     public void testToString() {
         Rfc822Token rfc822Token1 = new Rfc822Token("John Doe", "jdoe@example.net", "work");
         assertEquals("John Doe (work) <jdoe@example.net>", rfc822Token1.toString());
@@ -141,32 +153,30 @@
         assertEquals("", rfc822Token6.toString());
     }
 
+    @Test
     public void testQuoteNameIfNecessary() {
         assertEquals("UPPERlower space 0123456789",
                 Rfc822Token.quoteNameIfNecessary("UPPERlower space 0123456789"));
         assertEquals("\"jdoe@example.net\"", Rfc822Token.quoteNameIfNecessary("jdoe@example.net"));
         assertEquals("\"*name\"", Rfc822Token.quoteNameIfNecessary("*name"));
 
-        try {
-            Rfc822Token.quoteNameIfNecessary(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed to happen if name is null.
-        }
-
         assertEquals("", Rfc822Token.quoteNameIfNecessary(""));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testQuoteNameIfNecessaryNull() {
+        Rfc822Token.quoteNameIfNecessary(null);
+    }
+
+    @Test
     public void testQuoteName() {
         assertEquals("John Doe", Rfc822Token.quoteName("John Doe"));
         assertEquals("\\\"John Doe\\\"", Rfc822Token.quoteName("\"John Doe\""));
         assertEquals("\\\\\\\"John Doe\\\"", Rfc822Token.quoteName("\\\"John Doe\""));
+    }
 
-        try {
-            Rfc822Token.quoteName(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed to happen if name is null.
-        }
+    @Test(expected=NullPointerException.class)
+    public void testQuoteNameNull() {
+        Rfc822Token.quoteName(null);
     }
 }
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..c8b81f4 100644
--- a/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java
+++ b/tests/tests/text/src/android/text/util/cts/Rfc822TokenizerTest.java
@@ -16,19 +16,32 @@
 
 package android.text.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Test {@link Rfc822Tokenizer}.
  */
-public class Rfc822TokenizerTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Rfc822TokenizerTest {
+    @Test
     public void testConstructor() {
         new Rfc822Tokenizer();
     }
 
+    @Test
     public void testFindTokenStart() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -61,6 +74,7 @@
         }
     }
 
+    @Test
     public void testFindTokenEnd() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -87,15 +101,16 @@
         final int TOKEN_END_POS_4 = text2.indexOf(token4) + token4.length();
         assertEquals(TOKEN_END_POS_2, rfc822Tokenizer.findTokenEnd(text2, 0));
         assertEquals(TOKEN_END_POS_4, rfc822Tokenizer.findTokenEnd(text2, TOKEN_END_POS_2 + 1));
-
-        try {
-            rfc822Tokenizer.findTokenEnd(null, 0);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed to happen if text is null.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testFindTokenEndNull() {
+        Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
+
+        rfc822Tokenizer.findTokenEnd(null, 0);
+    }
+
+    @Test
     public void testTerminateToken() {
         Rfc822Tokenizer rfc822Tokenizer = new Rfc822Tokenizer();
 
@@ -110,28 +125,53 @@
         assertEquals(text + comma + space, rfc822Tokenizer.terminateToken(null));
     }
 
+    @Test
     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");
+        verifyLocalAssertEquals(tokens[0], "Berg", "berg\\@example.com", "home");
+        verifyLocalAssertEquals(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");
+        verifyLocalAssertEquals(tokens[0], "Foo Bar", "foo\\@example.com", "something");
+        verifyLocalAssertEquals(tokens[1], null, "blah\\@example.com", "something");
+    }
 
-        try {
-            Rfc822Tokenizer.tokenize(null);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // issue 1695243, not clear what is supposed result if text is null
-        }
+    @Test(expected=NullPointerException.class)
+    public void testTokenizeNull() {
+        Rfc822Tokenizer.tokenize(null);
+    }
+
+    @Test
+    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());
+        verifyLocalAssertEquals(list.get(0), "Berg", "berg\\@example.com", "home");
+        verifyLocalAssertEquals(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());
+        verifyLocalAssertEquals(list.get(0), "Foo Bar", "foo\\@example.com", "something");
+        verifyLocalAssertEquals(list.get(1), null, "blah\\@example.com", "something");
+    }
+
+
+    @Test(expected=NullPointerException.class)
+    public void testTokenize_withListParamNull() {
+        Rfc822Tokenizer.tokenize(null);
     }
 
     /**
@@ -141,7 +181,7 @@
      * @param address expected address.
      * @param comment expected comment.
      */
-    private void localAssertEquals(Rfc822Token token, String name,
+    private void verifyLocalAssertEquals(Rfc822Token token, String name,
             String address, String comment) {
         assertEquals(name, token.getName());
         assertEquals(address, token.getAddress());
diff --git a/tests/tests/textureview/AndroidTest.xml b/tests/tests/textureview/AndroidTest.xml
index d60a4a3..7f2711b 100644
--- a/tests/tests/textureview/AndroidTest.xml
+++ b/tests/tests/textureview/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.textureview.cts" />
+        <option name="runtime-hint" value="14m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/theme/AndroidTest.xml b/tests/tests/theme/AndroidTest.xml
index 82bd476..945c580 100644
--- a/tests/tests/theme/AndroidTest.xml
+++ b/tests/tests/theme/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.theme.cts" />
+        <option name="runtime-hint" value="11m" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
index af8b4eb..a80f43c 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-minus-junit4 \
+    android-common \
+    compatibility-device-util \
+    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/AndroidManifest.xml b/tests/tests/transition/AndroidManifest.xml
index 3205f28..1fb4f0e 100644
--- a/tests/tests/transition/AndroidManifest.xml
+++ b/tests/tests/transition/AndroidManifest.xml
@@ -16,12 +16,13 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.transition.cts">
-    <uses-sdk android:minSdkVersion="11" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <application>
         <activity android:name="android.transition.cts.TransitionActivity"
             android:label="TransitionActivity"/>
+        <activity android:name="android.transition.cts.TargetActivity"
+            android:label="TargetActivity"/>
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/tests/transition/AndroidTest.xml b/tests/tests/transition/AndroidTest.xml
index 5aad82b..6862679 100644
--- a/tests/tests/transition/AndroidTest.xml
+++ b/tests/tests/transition/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.transition.cts" />
+        <option name="runtime-hint" value="11m10s" />
     </test>
 </configuration>
diff --git a/tests/tests/transition/res/layout/scene10.xml b/tests/tests/transition/res/layout/scene10.xml
index 16e3c20..5403354 100644
--- a/tests/tests/transition/res/layout/scene10.xml
+++ b/tests/tests/transition/res/layout/scene10.xml
@@ -14,33 +14,39 @@
      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">
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:layout_alignParentLeft="true"
-          android:layout_alignParentTop="true"
-          android:id="@+id/redSquare" />
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:layout_alignParentRight="true"
-          android:layout_alignParentTop="true"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#00F"
-          android:layout_alignParentRight="true"
-          android:layout_alignParentBottom="true"
-          android:id="@+id/blueSquare" />
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#FF0"
-          android:layout_alignParentLeft="true"
-          android:layout_alignParentBottom="true"
-          android:id="@+id/yellowSquare"/>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:transitionGroup="false"
+    android:transitionName="holder"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentBottom="true"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentBottom="true"
+        android:id="@+id/yellowSquare"/>
 </RelativeLayout>
diff --git a/tests/tests/transition/res/layout/scene11.xml b/tests/tests/transition/res/layout/scene11.xml
new file mode 100644
index 0000000..dc6ef19
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene11.xml
@@ -0,0 +1,28 @@
+<?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/layout/scene12.xml b/tests/tests/transition/res/layout/scene12.xml
new file mode 100644
index 0000000..559ab39
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene12.xml
@@ -0,0 +1,45 @@
+<?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:transitionName="holder"
+    android:transitionGroup="false"
+    android:orientation="horizontal"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:id="@+id/yellowSquare"/>
+</LinearLayout>
diff --git a/tests/tests/transition/res/layout/scene13.xml b/tests/tests/transition/res/layout/scene13.xml
new file mode 100644
index 0000000..b7c783f
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene13.xml
@@ -0,0 +1,50 @@
+<?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:transitionGroup="false"
+    android:transitionName="holder"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:transitionName="redSquare"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:layout_toRightOf="@id/redSquare"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:layout_toRightOf="@id/greenSquare"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:layout_toRightOf="@id/blueSquare"
+        android:id="@+id/yellowSquare"/>
+</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/ActivityTransitionTest.java b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
new file mode 100644
index 0000000..7543dae
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
@@ -0,0 +1,295 @@
+/*
+ * 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 static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.transition.Fade;
+import android.transition.Transition.TransitionListener;
+import android.view.View;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.transition.TargetTracking;
+import com.android.compatibility.common.util.transition.TrackingTransition;
+import com.android.compatibility.common.util.transition.TrackingVisibility;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityTransitionTest extends BaseTransitionTest {
+    private TransitionListener mExitListener;
+    private TransitionListener mReenterListener;
+    private TransitionListener mSharedElementReenterListener;
+    private TrackingVisibility mExitTransition;
+    private TrackingVisibility mReenterTransition;
+    private TrackingTransition mSharedElementReenterTransition;
+
+    @Override
+    public void setup() {
+        super.setup();
+        mExitTransition = new TrackingVisibility();
+        mExitListener = mock(TransitionListener.class);
+        mExitTransition.addListener(mExitListener);
+        mActivity.getWindow().setExitTransition(mExitTransition);
+
+        mReenterTransition = new TrackingVisibility();
+        mReenterListener = mock(TransitionListener.class);
+        mReenterTransition.addListener(mReenterListener);
+        mActivity.getWindow().setReenterTransition(mReenterTransition);
+
+        mSharedElementReenterTransition = new TrackingTransition();
+        mSharedElementReenterListener = mock(TransitionListener.class);
+        mSharedElementReenterTransition.addListener(mSharedElementReenterListener);
+        mActivity.getWindow().setSharedElementReenterTransition(mSharedElementReenterTransition);
+    }
+
+    @After
+    public void cleanup() {
+        if (TargetActivity.sLastCreated != null) {
+            mInstrumentation.runOnMainSync(() -> TargetActivity.sLastCreated.finish());
+        }
+        TargetActivity.sLastCreated = null;
+    }
+
+    // Views that are outside the visible area only during the shared element start
+    // should not be stripped from the transition.
+    @Test
+    public void viewsNotStripped() throws Throwable {
+        enterScene(R.layout.scene10);
+        mInstrumentation.runOnMainSync(() -> {
+            View sharedElement = mActivity.findViewById(R.id.blueSquare);
+            Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
+                    sharedElement, "holder").toBundle();
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            intent.putExtra(TargetActivity.EXTRA_LAYOUT_ID, R.layout.scene12);
+            mActivity.startActivity(intent, options);
+        });
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        verify(targetActivity.enterListener, within(3000)).onTransitionEnd(any());
+        verify(mExitListener, times(1)).onTransitionEnd(any());
+
+        // Now check the targets... they should all be there
+        assertTargetContains(targetActivity.enterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+        assertTargetExcludes(targetActivity.enterTransition, R.id.holder);
+
+        assertTargetContains(targetActivity.sharedElementEnterTransition, R.id.holder);
+        assertTargetExcludes(targetActivity.sharedElementEnterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mExitTransition, R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+        assertTargetExcludes(mExitTransition, R.id.blueSquare, R.id.holder);
+
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, targetActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        mInstrumentation.runOnMainSync(() -> targetActivity.finishAfterTransition());
+        verify(mReenterListener, within(3000)).onTransitionEnd(any());
+        verify(mSharedElementReenterListener, within(3000)).onTransitionEnd(any());
+        verify(targetActivity.returnListener, times(1)).onTransitionEnd(any());
+
+        // return targets are stripped also
+        assertTargetContains(targetActivity.returnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+        assertTargetExcludes(targetActivity.returnTransition, R.id.holder);
+
+        assertTargetContains(mReenterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+        assertTargetExcludes(mReenterTransition, R.id.blueSquare, R.id.holder);
+
+        assertTargetContains(targetActivity.sharedElementReturnTransition,
+                R.id.holder);
+        assertTargetExcludes(targetActivity.sharedElementReturnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mSharedElementReenterTransition, R.id.blueSquare);
+        assertTargetExcludes(mSharedElementReenterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, mActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        TargetActivity.sLastCreated = null;
+    }
+
+    // Views that are outside the visible area during initial layout should be stripped from
+    // the transition.
+    @Test
+    public void viewsStripped() throws Throwable {
+        enterScene(R.layout.scene13);
+        mInstrumentation.runOnMainSync(() -> {
+            View sharedElement = mActivity.findViewById(R.id.redSquare);
+            Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
+                    sharedElement, "redSquare").toBundle();
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            intent.putExtra(TargetActivity.EXTRA_LAYOUT_ID, R.layout.scene13);
+            mActivity.startActivity(intent, options);
+        });
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        verify(targetActivity.enterListener, within(3000)).onTransitionEnd(any());
+        verify(mExitListener, times(1)).onTransitionEnd(any());
+
+        // Now check the targets... they should all be stripped
+        assertTargetExcludes(targetActivity.enterTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetExcludes(mExitTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(targetActivity.sharedElementEnterTransition, R.id.redSquare);
+        assertTargetExcludes(targetActivity.sharedElementEnterTransition,
+                R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, targetActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        mInstrumentation.runOnMainSync(() -> targetActivity.finishAfterTransition());
+        verify(mReenterListener, within(3000)).onTransitionEnd(any());
+        verify(mSharedElementReenterListener, within(3000)).onTransitionEnd(any());
+        verify(targetActivity.returnListener, times(1)).onTransitionEnd(any());
+
+        // return targets are stripped also
+        assertTargetExcludes(targetActivity.returnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetExcludes(mReenterTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(targetActivity.sharedElementReturnTransition,
+                R.id.redSquare);
+        assertTargetExcludes(targetActivity.sharedElementReturnTransition,
+                R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mSharedElementReenterTransition, R.id.redSquare);
+        assertTargetExcludes(mSharedElementReenterTransition,
+                R.id.blueSquare, R.id.greenSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.holder).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.redSquare).getVisibility());
+
+        assertEquals(1, mActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        TargetActivity.sLastCreated = null;
+    }
+
+    // When an exit transition takes longer than it takes the activity to cover it (and onStop
+    // is called), the exiting views should become visible.
+    @Test
+    public void earlyExitStop() throws Throwable {
+        enterScene(R.layout.scene1);
+        final View hello = mActivity.findViewById(R.id.hello);
+        final View red = mActivity.findViewById(R.id.redSquare);
+        final View green = mActivity.findViewById(R.id.greenSquare);
+        mInstrumentation.runOnMainSync(() -> {
+            Fade fade = new Fade();
+            fade.setDuration(10000);
+            fade.addListener(mExitListener);
+            mActivity.getWindow().setExitTransition(fade);
+            Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity).toBundle();
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            intent.putExtra(TargetActivity.EXTRA_LAYOUT_ID, R.layout.scene4);
+            mActivity.startActivity(intent, options);
+        });
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        verify(targetActivity.enterListener, within(3000)).onTransitionEnd(any());
+        verify(mExitListener, within(3000)).onTransitionEnd(any());
+
+        mInstrumentation.runOnMainSync(() -> {
+            // Verify that the exited views have an alpha of 1 and are visible
+            assertEquals(1.0f, hello.getAlpha(), 0.01f);
+            assertEquals(1.0f, red.getAlpha(), 0.01f);
+            assertEquals(1.0f, green.getAlpha(), 0.01f);
+
+            assertEquals(View.VISIBLE, hello.getVisibility());
+            assertEquals(View.VISIBLE, red.getVisibility());
+            assertEquals(View.VISIBLE, green.getVisibility());
+            targetActivity.finish();
+        });
+    }
+
+    private TargetActivity waitForTargetActivity() {
+        PollingCheck.waitFor(() -> TargetActivity.sLastCreated != null);
+        // Just make sure that we're not in the middle of running on the UI thread.
+        mInstrumentation.runOnMainSync(() -> {});
+        return TargetActivity.sLastCreated;
+    }
+
+    private Set<Integer> getTargetViewIds(TargetTracking transition) {
+        return transition.getTrackedTargets().stream()
+                .map(v -> v.getId())
+                .collect(Collectors.toSet());
+    }
+
+    private void assertTargetContains(TargetTracking transition, int... ids) {
+        Set<Integer> targets = getTargetViewIds(transition);
+        for (int id : ids) {
+            assertTrueWithId(id, "%s was not included from the transition", targets.contains(id));
+        }
+    }
+
+    private void assertTargetExcludes(TargetTracking transition, int... ids) {
+        Set<Integer> targets = getTargetViewIds(transition);
+        for (int id : ids) {
+            assertTrueWithId(id, "%s was not excluded from the transition", !targets.contains(id));
+        }
+    }
+
+    private void assertTrueWithId(int id, String message, boolean valueToAssert) {
+        if (!valueToAssert) {
+            fail(String.format(message, mActivity.getResources().getResourceName(id)));
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java b/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
index d6b00cf..941e09d 100644
--- a/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ArcMotionTest.java
@@ -15,15 +15,21 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Path;
-import android.graphics.PathMeasure;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ArcMotion;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class ArcMotionTest extends PathMotionTest {
-
-    public void test90Quadrants() throws Throwable {
+    @Test
+    public void test90Quadrants() {
         ArcMotion arcMotion = new ArcMotion();
         arcMotion.setMaximumAngle(90);
 
@@ -44,7 +50,8 @@
         assertPathMatches(expected, path);
     }
 
-    public void test345Triangles() throws Throwable {
+    @Test
+    public void test345Triangles() {
         // 3-4-5 triangles are easy to calculate the control points
         ArcMotion arcMotion = new ArcMotion();
         arcMotion.setMaximumAngle(90);
@@ -84,7 +91,7 @@
         assertPathMatches(expected, path);
     }
 
-    private Path arcWithPoint(float startX, float startY, float endX, float endY,
+    private static Path arcWithPoint(float startX, float startY, float endX, float endY,
             float eX, float eY) {
         float c1x = (eX + startX)/2;
         float c1y = (eY + startY)/2;
@@ -96,10 +103,11 @@
         return path;
     }
 
-    public void testMaximumAngle() throws Throwable {
+    @Test
+    public void testMaximumAngle() {
         ArcMotion arcMotion = new ArcMotion();
         arcMotion.setMaximumAngle(45f);
-        assertEquals(45f, arcMotion.getMaximumAngle());
+        assertEquals(45f, arcMotion.getMaximumAngle(), 0.0f);
 
         float ratio = (float) Math.tan(Math.PI/8);
         float ex = 50 + (50 * ratio);
@@ -110,10 +118,11 @@
         assertPathMatches(expected, path);
     }
 
-    public void testMinimumHorizontalAngle() throws Throwable {
+    @Test
+    public void testMinimumHorizontalAngle() {
         ArcMotion arcMotion = new ArcMotion();
         arcMotion.setMinimumHorizontalAngle(45);
-        assertEquals(45f, arcMotion.getMinimumHorizontalAngle());
+        assertEquals(45f, arcMotion.getMinimumHorizontalAngle(), 0.0f);
 
         float ey = (float)(Math.tan(Math.PI/8) * 50);
         float ex = 50;
@@ -127,10 +136,11 @@
         assertPathMatches(expected, path);
     }
 
-    public void testMinimumVerticalAngle() throws Throwable {
+    @Test
+    public void testMinimumVerticalAngle() {
         ArcMotion arcMotion = new ArcMotion();
         arcMotion.setMinimumVerticalAngle(45);
-        assertEquals(45f, arcMotion.getMinimumVerticalAngle());
+        assertEquals(45f, arcMotion.getMinimumVerticalAngle(), 0.0f);
 
         float ex = (float)(Math.tan(Math.PI/8) * 50);
         float ey = 50;
diff --git a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
index a3a8cad..5917ace 100644
--- a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
@@ -15,47 +15,56 @@
  */
 package android.transition.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
-import android.test.ActivityInstrumentationTestCase2;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
 import android.transition.Scene;
 import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.transition.TransitionValues;
 import android.transition.Visibility;
-import android.view.Choreographer;
-import android.view.Choreographer.FrameCallback;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
-import junit.framework.Assert;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
 
 import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
-public class BaseTransitionTest extends ActivityInstrumentationTestCase2<TransitionActivity> {
+public abstract class BaseTransitionTest {
+    protected Instrumentation mInstrumentation;
     protected TransitionActivity mActivity;
     protected FrameLayout mSceneRoot;
-    public float mAnimatedValue;
-    protected ArrayList<View> mTargets = new ArrayList<View>();
+    private float mAnimatedValue;
+    protected ArrayList<View> mTargets = new ArrayList<>();
     protected Transition mTransition;
-    protected SimpleTransitionListener mListener;
+    protected Transition.TransitionListener mListener;
 
-    public BaseTransitionTest() {
-        super(TransitionActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<TransitionActivity> mActivityRule =
+            new ActivityTestRule<>(TransitionActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mInstrumentation.setInTouchMode(false);
+        mActivity = mActivityRule.getActivity();
         mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container);
         mTargets.clear();
         mTransition = new TestTransition();
-        mListener = new SimpleTransitionListener();
+        mListener = mock(Transition.TransitionListener.class);
         mTransition.addListener(mListener);
     }
 
@@ -63,53 +72,43 @@
         waitForStart(mListener);
     }
 
-    protected void waitForStart(SimpleTransitionListener listener) throws InterruptedException {
-        assertTrue(listener.startLatch.await(4000, TimeUnit.MILLISECONDS));
+    protected static void waitForStart(Transition.TransitionListener listener) {
+        verify(listener, within(4000)).onTransitionStart(any());
     }
 
-    protected void waitForEnd(long waitMillis) throws InterruptedException {
+    protected void waitForEnd(long waitMillis) {
         waitForEnd(mListener, waitMillis);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
     }
 
-    protected static void waitForEnd(SimpleTransitionListener listener, long waitMillis)
-            throws InterruptedException {
-        listener.endLatch.await(waitMillis, TimeUnit.MILLISECONDS);
+    protected static void waitForEnd(Transition.TransitionListener listener, long waitMillis) {
+        if (waitMillis == 0) {
+            verify(listener, times(1)).onTransitionEnd(any());
+        } else {
+            verify(listener, within(waitMillis)).onTransitionEnd(any());
+        }
     }
 
     protected View loadLayout(final int layout) throws Throwable {
         View[] root = new View[1];
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                root[0] = mActivity.getLayoutInflater().inflate(layout, mSceneRoot, false);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> root[0] = mActivity.getLayoutInflater().inflate(layout, mSceneRoot, false));
 
         return root[0];
     }
 
     protected Scene loadScene(final View layout) throws Throwable {
-        Scene[] scene = new Scene[1];
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scene[0] = new Scene(mSceneRoot, layout);
-            }
-        });
+        final Scene[] scene = new Scene[1];
+        mActivityRule.runOnUiThread(() -> scene[0] = new Scene(mSceneRoot, layout));
 
         return scene[0];
     }
 
     protected Scene loadScene(final int layoutId) throws Throwable {
-        Scene scene[] = new Scene[1];
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scene[0] = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity);
-            }
-        });
+        final Scene scene[] = new Scene[1];
+        mActivityRule.runOnUiThread(
+                () -> scene[0] = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity));
         return scene[0];
     }
 
@@ -118,22 +117,12 @@
     }
 
     protected void startTransition(final Scene scene) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.go(scene, mTransition);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> TransitionManager.go(scene, mTransition));
         waitForStart();
     }
 
     protected void endTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.endTransitions(mSceneRoot);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> TransitionManager.endTransitions(mSceneRoot));
     }
 
     protected void enterScene(final int layoutId) throws Throwable {
@@ -141,49 +130,24 @@
     }
 
     protected void enterScene(final Scene scene) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(1);
-
-        runTestOnUiThread(() -> {
-            final ViewTreeObserver.OnGlobalLayoutListener listener =
-                    new ViewTreeObserver.OnGlobalLayoutListener() {
-                @Override
-                public void onGlobalLayout() {
-                    mActivity.getWindow().getDecorView().
-                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
-                    latch.countDown();
-                }
-            };
-
-            mActivity.getWindow().getDecorView().
-                    getViewTreeObserver().addOnGlobalLayoutListener(listener);
-
-            scene.enter();
-        });
-
-        try {
-            Assert.assertTrue("Expected layout pass within 5 seconds",
-                    latch.await(5, TimeUnit.SECONDS));
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
+        WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, scene::enter, false);
     }
 
     protected void exitScene(final Scene scene) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scene.exit();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(scene::exit);
+        mInstrumentation.waitForIdleSync();
     }
 
     protected void resetListener() {
         mTransition.removeListener(mListener);
-        mListener = new SimpleTransitionListener();
+        mListener = mock(Transition.TransitionListener.class);
         mTransition.addListener(mListener);
     }
 
+    public void setAnimatedValue(float animatedValue) {
+        mAnimatedValue = animatedValue;
+    }
+
     public class TestTransition extends Visibility {
 
         public TestTransition() {
@@ -193,14 +157,14 @@
         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
             mTargets.add(endValues.view);
-            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 0, 1);
+            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 0, 1);
         }
 
         @Override
         public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
             mTargets.add(startValues.view);
-            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 1, 0);
+            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "animatedValue", 1, 0);
         }
     }
 }
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..538f46c
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/CaptureValuesTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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 static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+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;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+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.
+     */
+    @Test
+    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(mActivity.findViewById(R.id.redSquare));
+        mTransition = set;
+        resetListener();
+        mActivityRule.runOnUiThread(() -> {
+            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 verifyCapturedValues(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);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeBoundsCaptureValues extends ChangeBounds {
+        public ChangeBoundsCaptureValues() {
+            super();
+            setResizeClip(true);
+            setReparent(true);
+        }
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeImageTransformCaptureValues extends ChangeImageTransform {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeTransformCaptureValues extends ChangeTransform {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class AutoTransitionCaptureValues extends AutoTransition {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeClipBoundsCaptureValues extends ChangeClipBounds {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ChangeScrollCaptureValues extends ChangeScroll {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class ExplodeCaptureValues extends Explode {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+
+    public class SlideCaptureValues extends Slide {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+    public class TransitionSetCaptureValues extends TransitionSet {
+        @Override
+        public void captureStartValues(TransitionValues transitionValues) {
+            super.captureStartValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, true);
+        }
+
+        @Override
+        public void captureEndValues(TransitionValues transitionValues) {
+            super.captureEndValues(transitionValues);
+            verifyCapturedValues(this, transitionValues, false);
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index d5c1245..e19a32d 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -15,12 +15,28 @@
  */
 package android.transition.cts;
 
+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.assertTrue;
+import static org.mockito.Mockito.mock;
+
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeBounds;
+import android.transition.Transition;
 import android.util.TypedValue;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ChangeBoundsTest extends BaseTransitionTest {
     private static final int SMALL_SQUARE_SIZE_DP = 10;
     private static final int LARGE_SQUARE_SIZE_DP = 30;
@@ -28,23 +44,22 @@
 
     ChangeBounds mChangeBounds;
 
-    public ChangeBoundsTest() {
-    }
-
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         resetChangeBoundsTransition();
     }
 
     private void resetChangeBoundsTransition() {
-        mListener = new SimpleTransitionListener();
+        mListener = mock(Transition.TransitionListener.class);
         mChangeBounds = new ChangeBounds();
         mChangeBounds.setDuration(400);
         mChangeBounds.addListener(mListener);
         mTransition = mChangeBounds;
     }
 
+    @Test
     public void testBasicChangeBounds() throws Throwable {
         enterScene(R.layout.scene1);
 
@@ -60,6 +75,7 @@
         validateInScene6();
     }
 
+    @Test
     public void testResizeClip() throws Throwable {
         assertEquals(false, mChangeBounds.getResizeClip());
         mChangeBounds.setResizeClip(true);
@@ -78,6 +94,7 @@
         validateInScene6();
     }
 
+    @Test
     public void testResizeClipSmaller() throws Throwable {
         mChangeBounds.setResizeClip(true);
         enterScene(R.layout.scene6);
@@ -94,6 +111,7 @@
         validateInScene1();
     }
 
+    @Test
     public void testInterruptSameDestination() throws Throwable {
         enterScene(R.layout.scene1);
 
@@ -111,6 +129,7 @@
         validateInScene6();
     }
 
+    @Test
     public void testInterruptSameDestinationResizeClip() throws Throwable {
         mChangeBounds.setResizeClip(true);
         enterScene(R.layout.scene1);
@@ -132,6 +151,7 @@
         validateInScene6();
     }
 
+    @Test
     public void testInterruptWithReverse() throws Throwable {
         enterScene(R.layout.scene1);
 
@@ -150,6 +170,7 @@
         validateInScene1();
     }
 
+    @Test
     public void testInterruptWithReverseResizeClip() throws Throwable {
         mChangeBounds.setResizeClip(true);
         enterScene(R.layout.scene1);
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java
index 9411d29..b7eb0dd 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeClipBoundsTest.java
@@ -15,25 +15,37 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Rect;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeClipBounds;
 import android.transition.TransitionManager;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ChangeClipBoundsTest extends BaseTransitionTest {
     private ChangeClipBounds mChangeClipBounds;
 
-    public ChangeClipBoundsTest() {
-    }
-
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         mChangeClipBounds = new ChangeClipBounds();
         mTransition = mChangeClipBounds;
         resetListener();
     }
 
+    @Test
     public void testChangeClipBounds() throws Throwable {
         enterScene(R.layout.scene1);
 
@@ -41,69 +53,49 @@
         final Rect newClip = new Rect(redSquare.getLeft() + 10, redSquare.getTop() + 10,
                 redSquare.getRight() - 10, redSquare.getBottom() - 10);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNull(redSquare.getClipBounds());
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
-                redSquare.setClipBounds(newClip);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertNull(redSquare.getClipBounds());
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
+            redSquare.setClipBounds(newClip);
         });
         waitForStart();
         Thread.sleep(150);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Rect midClip = redSquare.getClipBounds();
-                assertNotNull(midClip);
-                assertTrue(midClip.left > 0 && midClip.left < newClip.left);
-                assertTrue(midClip.top > 0 && midClip.top < newClip.top);
-                assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
-                assertTrue(midClip.bottom < redSquare.getBottom() &&
-                        midClip.bottom > newClip.bottom);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Rect midClip = redSquare.getClipBounds();
+            assertNotNull(midClip);
+            assertTrue(midClip.left > 0 && midClip.left < newClip.left);
+            assertTrue(midClip.top > 0 && midClip.top < newClip.top);
+            assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
+            assertTrue(midClip.bottom < redSquare.getBottom() &&
+                    midClip.bottom > newClip.bottom);
         });
         waitForEnd(400);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final Rect endRect = redSquare.getClipBounds();
-                assertNotNull(endRect);
-                assertEquals(newClip, endRect);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            final Rect endRect = redSquare.getClipBounds();
+            assertNotNull(endRect);
+            assertEquals(newClip, endRect);
         });
 
         resetListener();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
-                redSquare.setClipBounds(null);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeClipBounds);
+            redSquare.setClipBounds(null);
         });
         waitForStart();
         Thread.sleep(150);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Rect midClip = redSquare.getClipBounds();
-                assertNotNull(midClip);
-                assertTrue(midClip.left > 0 && midClip.left < newClip.left);
-                assertTrue(midClip.top > 0 && midClip.top < newClip.top);
-                assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
-                assertTrue(midClip.bottom < redSquare.getBottom() &&
-                        midClip.bottom > newClip.bottom);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Rect midClip = redSquare.getClipBounds();
+            assertNotNull(midClip);
+            assertTrue(midClip.left > 0 && midClip.left < newClip.left);
+            assertTrue(midClip.top > 0 && midClip.top < newClip.top);
+            assertTrue(midClip.right < redSquare.getRight() && midClip.right > newClip.right);
+            assertTrue(midClip.bottom < redSquare.getBottom() &&
+                    midClip.bottom > newClip.bottom);
         });
         waitForEnd(400);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNotNull(redSquare.getClipBounds());
-            }
-        });
+        mActivityRule.runOnUiThread(() -> assertNotNull(redSquare.getClipBounds()));
     }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java b/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java
index a26e850..b27364e 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeImageTransformTest.java
@@ -15,10 +15,20 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.graphics.Matrix;
 import android.graphics.drawable.Drawable;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeImageTransform;
 import android.transition.TransitionManager;
 import android.transition.TransitionValues;
@@ -29,6 +39,12 @@
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ChangeImageTransformTest extends BaseTransitionTest {
     ChangeImageTransform mChangeImageTransform;
     Matrix mStartMatrix;
@@ -37,8 +53,9 @@
     ImageView mImageView;
 
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         resetTransition();
         mStartMatrix = null;
         mEndMatrix = null;
@@ -53,29 +70,33 @@
         resetListener();
     }
 
+    @Test
     public void testCenterToFitXY() throws Throwable {
         transformImage(ScaleType.CENTER, ScaleType.FIT_XY);
-        assertMatrixMatches(centerMatrix(), mStartMatrix);
-        assertMatrixMatches(fitXYMatrix(), mEndMatrix);
+        verifyMatrixMatches(centerMatrix(), mStartMatrix);
+        verifyMatrixMatches(fitXYMatrix(), mEndMatrix);
     }
 
+    @Test
     public void testCenterCropToFitCenter() throws Throwable {
         transformImage(ScaleType.CENTER_CROP, ScaleType.FIT_CENTER);
-        assertMatrixMatches(centerCropMatrix(), mStartMatrix);
-        assertMatrixMatches(fitCenterMatrix(), mEndMatrix);
+        verifyMatrixMatches(centerCropMatrix(), mStartMatrix);
+        verifyMatrixMatches(fitCenterMatrix(), mEndMatrix);
     }
 
+    @Test
     public void testCenterInsideToFitEnd() throws Throwable {
         transformImage(ScaleType.CENTER_INSIDE, ScaleType.FIT_END);
         // CENTER_INSIDE and CENTER are the same when the image is smaller than the View
-        assertMatrixMatches(centerMatrix(), mStartMatrix);
-        assertMatrixMatches(fitEndMatrix(), mEndMatrix);
+        verifyMatrixMatches(centerMatrix(), mStartMatrix);
+        verifyMatrixMatches(fitEndMatrix(), mEndMatrix);
     }
 
+    @Test
     public void testFitStartToCenter() throws Throwable {
         transformImage(ScaleType.FIT_START, ScaleType.CENTER);
-        assertMatrixMatches(fitStartMatrix(), mStartMatrix);
-        assertMatrixMatches(centerMatrix(), mEndMatrix);
+        verifyMatrixMatches(fitStartMatrix(), mStartMatrix);
+        verifyMatrixMatches(centerMatrix(), mEndMatrix);
     }
 
     private Matrix centerMatrix() {
@@ -188,7 +209,7 @@
         return matrix;
     }
 
-    private void assertMatrixMatches(Matrix expected, Matrix matrix) {
+    private void verifyMatrixMatches(Matrix expected, Matrix matrix) {
         if (expected == null) {
             assertNull(matrix);
             return;
@@ -209,16 +230,12 @@
 
     private void transformImage(ScaleType startScale, final ScaleType endScale) throws Throwable {
         final ImageView imageView = enterImageViewScene(startScale);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeImageTransform);
-                imageView.setScaleType(endScale);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeImageTransform);
+            imageView.setScaleType(endScale);
         });
         waitForStart();
-        int expectedEndCount = (startScale == endScale) ? 0 : 1;
-        assertEquals(expectedEndCount, mListener.endLatch.getCount());
+        verify(mListener, (startScale == endScale) ? times(1) : never()).onTransitionEnd(any());
         waitForEnd(200);
     }
 
@@ -226,24 +243,21 @@
         enterScene(R.layout.scene4);
         final ViewGroup container = (ViewGroup) mActivity.findViewById(R.id.holder);
         final ImageView[] imageViews = new ImageView[1];
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mImageView = new ImageView(mActivity);
-                mImage = mActivity.getDrawable(android.R.drawable.ic_media_play);
-                mImageView.setImageDrawable(mImage);
-                mImageView.setScaleType(scaleType);
-                imageViews[0] = mImageView;
-                container.addView(mImageView);
-                LayoutParams layoutParams = mImageView.getLayoutParams();
-                DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
-                float size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, metrics);
-                layoutParams.width = Math.round(size);
-                layoutParams.height = Math.round(size * 2);
-                mImageView.setLayoutParams(layoutParams);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mImageView = new ImageView(mActivity);
+            mImage = mActivity.getDrawable(android.R.drawable.ic_media_play);
+            mImageView.setImageDrawable(mImage);
+            mImageView.setScaleType(scaleType);
+            imageViews[0] = mImageView;
+            container.addView(mImageView);
+            LayoutParams layoutParams = mImageView.getLayoutParams();
+            DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+            float size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, metrics);
+            layoutParams.width = Math.round(size);
+            layoutParams.height = Math.round(size * 2);
+            mImageView.setLayoutParams(layoutParams);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         return imageViews[0];
     }
 
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
index 2dee364..b0e1f9e 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeScrollTest.java
@@ -15,58 +15,59 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeScroll;
 import android.transition.TransitionManager;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ChangeScrollTest extends BaseTransitionTest {
     ChangeScroll mChangeScroll;
 
-    public ChangeScrollTest() {
-    }
-
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         mChangeScroll = new ChangeScroll();
         mTransition = mChangeScroll;
         resetListener();
     }
 
+    @Test
     public void testChangeScroll() throws Throwable {
         enterScene(R.layout.scene5);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View view = mActivity.findViewById(R.id.text);
-                assertEquals(0, view.getScrollX());
-                assertEquals(0, view.getScrollY());
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeScroll);
-                view.scrollTo(150, 300);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            final View view = mActivity.findViewById(R.id.text);
+            assertEquals(0, view.getScrollX());
+            assertEquals(0, view.getScrollY());
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeScroll);
+            view.scrollTo(150, 300);
         });
         waitForStart();
         Thread.sleep(150);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View view = mActivity.findViewById(R.id.text);
-                final int scrollX = view.getScrollX();
-                final int scrollY = view.getScrollY();
-                assertTrue(scrollX > 0);
-                assertTrue(scrollX < 150);
-                assertTrue(scrollY > 0);
-                assertTrue(scrollY < 300);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            final View view = mActivity.findViewById(R.id.text);
+            final int scrollX = view.getScrollX();
+            final int scrollY = view.getScrollY();
+            assertTrue(scrollX > 0);
+            assertTrue(scrollX < 150);
+            assertTrue(scrollY > 0);
+            assertTrue(scrollY < 300);
         });
         waitForEnd(400);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View view = mActivity.findViewById(R.id.text);
-                assertEquals(150, view.getScrollX());
-                assertEquals(300, view.getScrollY());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            final View view = mActivity.findViewById(R.id.text);
+            assertEquals(150, view.getScrollX());
+            assertEquals(300, view.getScrollY());
         });
     }
 }
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java b/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java
index 78a5d82..fb231fa 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeTransformTest.java
@@ -15,17 +15,32 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeTransform;
 import android.transition.TransitionManager;
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ChangeTransformTest extends BaseTransitionTest {
     ChangeTransform mChangeTransform;
 
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         resetChangeBoundsTransition();
     }
 
@@ -35,78 +50,73 @@
         resetListener();
     }
 
+    @Test
     public void testTranslation() throws Throwable {
         enterScene(R.layout.scene1);
 
         final View redSquare = mActivity.findViewById(R.id.redSquare);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
-                redSquare.setTranslationX(500);
-                redSquare.setTranslationY(600);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+            redSquare.setTranslationX(500);
+            redSquare.setTranslationY(600);
         });
         waitForStart();
 
-        assertEquals(1, mListener.endLatch.getCount()); // still running
+        verify(mListener, never()).onTransitionEnd(any()); // still running
         // There is no way to validate the intermediate matrix because it uses
         // hidden properties of the View to execute.
         waitForEnd(400);
-        assertEquals(500f, redSquare.getTranslationX());
-        assertEquals(600f, redSquare.getTranslationY());
+        assertEquals(500f, redSquare.getTranslationX(), 0.0f);
+        assertEquals(600f, redSquare.getTranslationY(), 0.0f);
     }
 
+    @Test
     public void testRotation() throws Throwable {
         enterScene(R.layout.scene1);
 
         final View redSquare = mActivity.findViewById(R.id.redSquare);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
-                redSquare.setRotation(45);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+            redSquare.setRotation(45);
         });
         waitForStart();
 
-        assertEquals(1, mListener.endLatch.getCount()); // still running
+        verify(mListener, never()).onTransitionEnd(any()); // still running
         // There is no way to validate the intermediate matrix because it uses
         // hidden properties of the View to execute.
         waitForEnd(400);
-        assertEquals(45f, redSquare.getRotation());
+        assertEquals(45f, redSquare.getRotation(), 0.0f);
     }
 
+    @Test
     public void testScale() throws Throwable {
         enterScene(R.layout.scene1);
 
         final View redSquare = mActivity.findViewById(R.id.redSquare);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
-                redSquare.setScaleX(2f);
-                redSquare.setScaleY(3f);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mChangeTransform);
+            redSquare.setScaleX(2f);
+            redSquare.setScaleY(3f);
         });
         waitForStart();
 
-        assertEquals(1, mListener.endLatch.getCount()); // still running
+        verify(mListener, never()).onTransitionEnd(any()); // still running
         // There is no way to validate the intermediate matrix because it uses
         // hidden properties of the View to execute.
         waitForEnd(400);
-        assertEquals(2f, redSquare.getScaleX());
-        assertEquals(3f, redSquare.getScaleY());
+        assertEquals(2f, redSquare.getScaleX(), 0.0f);
+        assertEquals(3f, redSquare.getScaleY(), 0.0f);
     }
 
+    @Test
     public void testReparent() throws Throwable {
         assertEquals(true, mChangeTransform.getReparent());
         enterScene(R.layout.scene5);
         startTransition(R.layout.scene9);
-        assertEquals(1, mListener.endLatch.getCount()); // still running
+        verify(mListener, never()).onTransitionEnd(any()); // still running
         waitForEnd(400);
 
         resetListener();
@@ -116,23 +126,21 @@
         waitForEnd(0); // no transition to run because reparent == false
     }
 
+    @Test
     public void testReparentWithOverlay() throws Throwable {
         assertEquals(true, mChangeTransform.getReparentWithOverlay());
         enterScene(R.layout.scene5);
         startTransition(R.layout.scene9);
-        assertEquals(1, mListener.endLatch.getCount()); // still running
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                View view = new View(mActivity);
-                view.setRight(100);
-                view.setBottom(100);
-                mSceneRoot.getOverlay().add(view);
-                ViewGroup container = (ViewGroup) view.getParent();
-                assertEquals(2, container.getChildCount());
-                mSceneRoot.getOverlay().remove(view);
-                assertTrue(mActivity.findViewById(R.id.text).getVisibility() != View.VISIBLE);
-            }
+        verify(mListener, never()).onTransitionEnd(any()); // still running
+        mActivityRule.runOnUiThread(() -> {
+            View view = new View(mActivity);
+            view.setRight(100);
+            view.setBottom(100);
+            mSceneRoot.getOverlay().add(view);
+            ViewGroup container = (ViewGroup) view.getParent();
+            assertEquals(2, container.getChildCount());
+            mSceneRoot.getOverlay().remove(view);
+            assertTrue(mActivity.findViewById(R.id.text).getVisibility() != View.VISIBLE);
         });
         waitForEnd(400);
 
@@ -140,19 +148,16 @@
         assertEquals(false, mChangeTransform.getReparentWithOverlay());
         resetListener();
         startTransition(R.layout.scene5);
-        assertEquals(1, mListener.endLatch.getCount()); // still running
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                View view = new View(mActivity);
-                view.setRight(100);
-                view.setBottom(100);
-                mSceneRoot.getOverlay().add(view);
-                ViewGroup container = (ViewGroup) view.getParent();
-                assertEquals(1, container.getChildCount());
-                mSceneRoot.getOverlay().remove(view);
-                assertEquals(View.VISIBLE, mActivity.findViewById(R.id.text).getVisibility());
-            }
+        verify(mListener, never()).onTransitionEnd(any()); // still running
+        mActivityRule.runOnUiThread(() -> {
+            View view = new View(mActivity);
+            view.setRight(100);
+            view.setBottom(100);
+            mSceneRoot.getOverlay().add(view);
+            ViewGroup container = (ViewGroup) view.getParent();
+            assertEquals(1, container.getChildCount());
+            mSceneRoot.getOverlay().remove(view);
+            assertEquals(View.VISIBLE, mActivity.findViewById(R.id.text).getVisibility());
         });
         waitForEnd(400);
     }
diff --git a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
index e9e2264..52340e0 100644
--- a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
@@ -15,18 +15,31 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Explode;
 import android.transition.TransitionManager;
 import android.view.View;
-import android.widget.RelativeLayout;
-import android.widget.RelativeLayout.LayoutParams;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ExplodeTest extends BaseTransitionTest {
     Explode mExplode;
 
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         resetTransition();
     }
 
@@ -36,6 +49,7 @@
         resetListener();
     }
 
+    @Test
     public void testExplode() throws Throwable {
         enterScene(R.layout.scene10);
         final View redSquare = mActivity.findViewById(R.id.redSquare);
@@ -43,18 +57,15 @@
         final View blueSquare = mActivity.findViewById(R.id.blueSquare);
         final View yellowSquare = mActivity.findViewById(R.id.yellowSquare);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                redSquare.setVisibility(View.INVISIBLE);
-                greenSquare.setVisibility(View.INVISIBLE);
-                blueSquare.setVisibility(View.INVISIBLE);
-                yellowSquare.setVisibility(View.INVISIBLE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            redSquare.setVisibility(View.INVISIBLE);
+            greenSquare.setVisibility(View.INVISIBLE);
+            blueSquare.setVisibility(View.INVISIBLE);
+            yellowSquare.setVisibility(View.INVISIBLE);
         });
         waitForStart();
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         assertEquals(View.VISIBLE, redSquare.getVisibility());
         assertEquals(View.VISIBLE, greenSquare.getVisibility());
         assertEquals(View.VISIBLE, blueSquare.getVisibility());
@@ -63,24 +74,25 @@
         float redStartY = redSquare.getTranslationY();
 
         Thread.sleep(100);
-        assertTranslation(redSquare, true, true);
-        assertTranslation(greenSquare, false, true);
-        assertTranslation(blueSquare, false, false);
-        assertTranslation(yellowSquare, true, false);
+        verifyTranslation(redSquare, true, true);
+        verifyTranslation(greenSquare, false, true);
+        verifyTranslation(blueSquare, false, false);
+        verifyTranslation(yellowSquare, true, false);
         assertTrue(redStartX > redSquare.getTranslationX()); // moving left
         assertTrue(redStartY > redSquare.getTranslationY()); // moving up
         waitForEnd(400);
 
-        assertNoTranslation(redSquare);
-        assertNoTranslation(greenSquare);
-        assertNoTranslation(blueSquare);
-        assertNoTranslation(yellowSquare);
+        verifyNoTranslation(redSquare);
+        verifyNoTranslation(greenSquare);
+        verifyNoTranslation(blueSquare);
+        verifyNoTranslation(yellowSquare);
         assertEquals(View.INVISIBLE, redSquare.getVisibility());
         assertEquals(View.INVISIBLE, greenSquare.getVisibility());
         assertEquals(View.INVISIBLE, blueSquare.getVisibility());
         assertEquals(View.INVISIBLE, yellowSquare.getVisibility());
     }
 
+    @Test
     public void testImplode() throws Throwable {
         enterScene(R.layout.scene10);
         final View redSquare = mActivity.findViewById(R.id.redSquare);
@@ -88,26 +100,20 @@
         final View blueSquare = mActivity.findViewById(R.id.blueSquare);
         final View yellowSquare = mActivity.findViewById(R.id.yellowSquare);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                redSquare.setVisibility(View.INVISIBLE);
-                greenSquare.setVisibility(View.INVISIBLE);
-                blueSquare.setVisibility(View.INVISIBLE);
-                yellowSquare.setVisibility(View.INVISIBLE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            redSquare.setVisibility(View.INVISIBLE);
+            greenSquare.setVisibility(View.INVISIBLE);
+            blueSquare.setVisibility(View.INVISIBLE);
+            yellowSquare.setVisibility(View.INVISIBLE);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                redSquare.setVisibility(View.VISIBLE);
-                greenSquare.setVisibility(View.VISIBLE);
-                blueSquare.setVisibility(View.VISIBLE);
-                yellowSquare.setVisibility(View.VISIBLE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            redSquare.setVisibility(View.VISIBLE);
+            greenSquare.setVisibility(View.VISIBLE);
+            blueSquare.setVisibility(View.VISIBLE);
+            yellowSquare.setVisibility(View.VISIBLE);
         });
         waitForStart();
 
@@ -119,25 +125,25 @@
         float redStartY = redSquare.getTranslationY();
 
         Thread.sleep(100);
-        assertTranslation(redSquare, true, true);
-        assertTranslation(greenSquare, false, true);
-        assertTranslation(blueSquare, false, false);
-        assertTranslation(yellowSquare, true, false);
+        verifyTranslation(redSquare, true, true);
+        verifyTranslation(greenSquare, false, true);
+        verifyTranslation(blueSquare, false, false);
+        verifyTranslation(yellowSquare, true, false);
         assertTrue(redStartX < redSquare.getTranslationX()); // moving right
         assertTrue(redStartY < redSquare.getTranslationY()); // moving down
         waitForEnd(400);
 
-        assertNoTranslation(redSquare);
-        assertNoTranslation(greenSquare);
-        assertNoTranslation(blueSquare);
-        assertNoTranslation(yellowSquare);
+        verifyNoTranslation(redSquare);
+        verifyNoTranslation(greenSquare);
+        verifyNoTranslation(blueSquare);
+        verifyNoTranslation(yellowSquare);
         assertEquals(View.VISIBLE, redSquare.getVisibility());
         assertEquals(View.VISIBLE, greenSquare.getVisibility());
         assertEquals(View.VISIBLE, blueSquare.getVisibility());
         assertEquals(View.VISIBLE, yellowSquare.getVisibility());
     }
 
-    private void assertTranslation(View view, boolean goLeft, boolean goUp) {
+    private void verifyTranslation(View view, boolean goLeft, boolean goUp) {
         float translationX = view.getTranslationX();
         float translationY = view.getTranslationY();
 
@@ -154,9 +160,9 @@
         }
     }
 
-    private void assertNoTranslation(View view) {
-        assertEquals(0f, view.getTranslationX());
-        assertEquals(0f, view.getTranslationY());
+    private void verifyNoTranslation(View view) {
+        assertEquals(0f, view.getTranslationX(), 0.0f);
+        assertEquals(0f, view.getTranslationY(), 0.0f);
     }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/FadeTest.java b/tests/tests/transition/src/android/transition/cts/FadeTest.java
index a6a1b2f..22a6039 100644
--- a/tests/tests/transition/src/android/transition/cts/FadeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/FadeTest.java
@@ -15,18 +15,31 @@
  */
 package android.transition.cts;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Fade;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * This tests the public API for Fade. The alpha cannot be easily tested as part of CTS,
  * so those are implementation tests.
  */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class FadeTest extends BaseTransitionTest {
     Fade mFade;
 
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         resetTransition();
     }
 
@@ -37,16 +50,17 @@
         resetListener();
     }
 
+    @Test
     public void testMode() throws Throwable {
         // Should animate in and out by default
         enterScene(R.layout.scene4);
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         resetListener();
         startTransition(R.layout.scene4);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         // Now only animate in
@@ -54,7 +68,7 @@
         mTransition = mFade;
         resetListener();
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         // No animation since it should only animate in
@@ -72,7 +86,7 @@
         // but it should animate out
         resetListener();
         startTransition(R.layout.scene4);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
     }
 }
diff --git a/tests/tests/transition/src/android/transition/cts/PathMotionTest.java b/tests/tests/transition/src/android/transition/cts/PathMotionTest.java
index 97bf274..51903fa 100644
--- a/tests/tests/transition/src/android/transition/cts/PathMotionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/PathMotionTest.java
@@ -15,12 +15,12 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 
-import junit.framework.TestCase;
-
-public class PathMotionTest extends TestCase {
+public abstract class PathMotionTest {
     public static void assertPathMatches(Path expectedPath, Path path) {
         PathMeasure expectedMeasure = new PathMeasure(expectedPath, false);
         PathMeasure pathMeasure = new PathMeasure(path, 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..a7ae8f3 100644
--- a/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/PatternPathMotionTest.java
@@ -15,12 +15,21 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertSame;
+
 import android.graphics.Path;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.PatternPathMotion;
 
-public class PatternPathMotionTest extends PathMotionTest {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    public void testStraightPath() throws Throwable {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PatternPathMotionTest extends PathMotionTest {
+    @Test
+    public void testStraightPath() {
         Path pattern = new Path();
         pattern.moveTo(100, 500);
         pattern.lineTo(300, 1000);
@@ -35,7 +44,8 @@
         assertPathMatches(expected, pathMotion.getPath(0, 0, 100, 100));
     }
 
-    public void testCurve() throws Throwable {
+    @Test
+    public void testCurve() {
         Path pattern = new Path();
         pattern.addArc(0, 0, 100, 100, 0, 180);
 
@@ -47,5 +57,15 @@
 
         assertPathMatches(expected, pathMotion.getPath(0, 0, 0, 100));
     }
+
+    @Test
+    public void testSetPatternPath() {
+        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..dfd7b03
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/PropagationTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.transition.CircularPropagation;
+import android.transition.SidePropagation;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.Gravity;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PropagationTest extends BaseTransitionTest {
+    @Test
+    public void testCircularPropagation() throws Throwable {
+        enterScene(R.layout.scene10);
+        CircularPropagation propagation = new CircularPropagation();
+        mTransition.setPropagation(propagation);
+        final TransitionValues redValues = new TransitionValues();
+        redValues.view = mActivity.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));
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
+    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);
+    }
+
+    @Test
+    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);
+    }
+
+    @Test
+    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..8c06f51 100644
--- a/tests/tests/transition/src/android/transition/cts/SceneTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SceneTest.java
@@ -15,96 +15,104 @@
  */
 package android.transition.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Scene;
 import android.view.View;
+import android.view.ViewGroup;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class SceneTest extends BaseTransitionTest {
-
-    public SceneTest() {
-    }
-
+    /**
+     * Test Scene(ViewGroup) with enterAction and exitAction
+     */
+    @Test
     public void testDynamicConstructor() throws Throwable {
         Scene scene = new Scene(mSceneRoot);
         assertEquals(mSceneRoot, scene.getSceneRoot());
-        CallCheck enterCheck = new CallCheck() {
-            @Override
-            public void run() {
-                super.run();
-                mActivity.getLayoutInflater().inflate(R.layout.scene1, mSceneRoot, true);
-            }
-        };
+        Runnable enterCheck = mock(Runnable.class);
+        doAnswer((InvocationOnMock invocation) -> mActivity.getLayoutInflater().inflate(
+                R.layout.scene1, mSceneRoot, true)).when(enterCheck).run();
         scene.setEnterAction(enterCheck);
-        CallCheck exitCheck = new CallCheck();
+        Runnable exitCheck = mock(Runnable.class);
         scene.setExitAction(exitCheck);
         enterScene(scene);
 
-        assertTrue(enterCheck.wasRun);
-        assertFalse(exitCheck.wasRun);
+        verify(enterCheck, times(1)).run();
+        verifyZeroInteractions(exitCheck);
 
         View redSquare = mActivity.findViewById(R.id.redSquare);
         assertNotNull(redSquare);
 
         exitScene(scene);
         assertNotNull(mSceneRoot.findViewById(R.id.redSquare));
-        assertTrue(exitCheck.wasRun);
+        verify(exitCheck, times(1)).run();
 
         enterScene(R.layout.scene4);
         assertNull(mSceneRoot.findViewById(R.id.redSquare));
     }
 
+    /**
+     * Test Scene(ViewGroup, View)
+     */
+    @Test
     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)
+     */
+    @Test
+    public void testDeprecatedConstructor() throws Throwable {
+        View view = loadLayout(R.layout.scene1);
+        constructorTest(new Scene(mSceneRoot, (ViewGroup) view));
+    }
+
+    /**
+     * Test Scene.getSceneForLayout
+     */
+    @Test
     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();
+        Runnable enterCheck = mock(Runnable.class);
         scene.setEnterAction(enterCheck);
-        CallCheck exitCheck = new CallCheck();
+        Runnable exitCheck = mock(Runnable.class);
         scene.setExitAction(exitCheck);
         enterScene(scene);
 
-        assertTrue(enterCheck.wasRun);
-        assertFalse(exitCheck.wasRun);
+        verify(enterCheck, times(1)).run();
+        verifyZeroInteractions(exitCheck);
 
         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));
-    }
-
-    private static class CallCheck implements Runnable {
-        public boolean wasRun;
-
-        @Override
-        public void run() {
-            wasRun = true;
-        }
+        verify(exitCheck, times(1)).run();
     }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java b/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
deleted file mode 100644
index fb8596a..0000000
--- a/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
+++ /dev/null
@@ -1,60 +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 android.transition.cts;
-
-import android.transition.Transition;
-import android.transition.Transition.TransitionListener;
-
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Listener captures whether each of the methods is called.
- */
-class SimpleTransitionListener implements TransitionListener {
-    public Transition transition;
-
-    public CountDownLatch startLatch = new CountDownLatch(1);
-    public CountDownLatch endLatch = new CountDownLatch(1);
-    public CountDownLatch cancelLatch = new CountDownLatch(1);
-    public CountDownLatch pauseLatch = new CountDownLatch(1);
-    public CountDownLatch resumeLatch = new CountDownLatch(1);
-
-    @Override
-    public void onTransitionStart(Transition transition) {
-        this.transition = transition;
-        startLatch.countDown();
-    }
-
-    @Override
-    public void onTransitionEnd(Transition transition) {
-        endLatch.countDown();
-    }
-
-    @Override
-    public void onTransitionCancel(Transition transition) {
-        cancelLatch.countDown();
-    }
-
-    @Override
-    public void onTransitionPause(Transition transition) {
-        pauseLatch.countDown();
-    }
-
-    @Override
-    public void onTransitionResume(Transition transition) {
-        resumeLatch.countDown();
-    }
-}
diff --git a/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java
index fefa353..e0ce0cc 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideBadEdgeTest.java
@@ -15,15 +15,20 @@
  */
 package android.transition.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Slide;
 import android.view.Gravity;
 
-import junit.framework.TestCase;
-
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SlideBadEdgeTest extends TestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SlideBadEdgeTest {
 
     private static final Object[][] sBadGravity = {
             { Gravity.AXIS_CLIP, "AXIS_CLIP" },
@@ -50,12 +55,13 @@
     };
 
     @SmallTest
+    @Test
     public void testBadSide() {
         for (int i = 0; i < sBadGravity.length; i++) {
             int badEdge = (Integer) sBadGravity[i][0];
             String edgeName = (String) sBadGravity[i][1];
             try {
-                Slide slide = new Slide(badEdge);
+                new Slide(badEdge);
                 fail("Should not be able to set slide edge to " + edgeName);
             } catch (IllegalArgumentException e) {
                 // expected
diff --git a/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java
index 060b4cc..3de780c 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideDefaultEdgeTest.java
@@ -15,26 +15,20 @@
  */
 package android.transition.cts;
 
-import android.support.test.rule.ActivityTestRule;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.transition.Slide;
-import android.transition.TransitionManager;
-import android.view.Gravity;
-import android.view.View;
+import static org.junit.Assert.assertEquals;
 
-import org.junit.Rule;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.transition.Slide;
+import android.view.Gravity;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class SlideDefaultEdgeTest {
     @Test
-    @SmallTest
     public void testDefaultSide() {
         // default to bottom
         Slide slide = new Slide();
diff --git a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
index 01225dc..b4bf800 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
@@ -15,22 +15,30 @@
  */
 package android.transition.cts;
 
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertEquals;
+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.verify;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Slide;
+import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.junit.Test;
-
-import java.util.concurrent.TimeUnit;
+import org.junit.runner.RunWith;
 
 @MediumTest
-public class SlideEdgeTest extends ActivityInstrumentationTestCase2<TransitionActivity>  {
+@RunWith(AndroidJUnit4.class)
+public class SlideEdgeTest extends BaseTransitionTest  {
     private static final Object[][] sSlideEdgeArray = {
             { Gravity.START, "START" },
             { Gravity.END, "END" },
@@ -40,10 +48,7 @@
             { Gravity.BOTTOM, "BOTTOM" },
     };
 
-    public SlideEdgeTest() {
-        super(TransitionActivity.class);
-    }
-
+    @Test
     public void testSetSide() throws Throwable {
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
@@ -59,39 +64,31 @@
         }
     }
 
+    @Test
     public void testSlideOut() throws Throwable {
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            final SimpleTransitionListener listener = new SimpleTransitionListener();
+            final Transition.TransitionListener listener =
+                    mock(Transition.TransitionListener.class);
             slide.addListener(listener);
 
-            final Instrumentation instrumentation = getInstrumentation();
-            final Activity activity = getActivity();
-            instrumentation.runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    activity.setContentView(R.layout.scene1);
-                }
-            });
-            instrumentation.waitForIdleSync();
+            mActivityRule.runOnUiThread(() -> mActivity.setContentView(R.layout.scene1));
+            mInstrumentation.waitForIdleSync();
 
-            final View redSquare = activity.findViewById(R.id.redSquare);
-            final View greenSquare = activity.findViewById(R.id.greenSquare);
-            final View hello = activity.findViewById(R.id.hello);
-            final ViewGroup sceneRoot = (ViewGroup) activity.findViewById(R.id.holder);
+            final View redSquare = mActivity.findViewById(R.id.redSquare);
+            final View greenSquare = mActivity.findViewById(R.id.greenSquare);
+            final View hello = mActivity.findViewById(R.id.hello);
+            final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.holder);
 
-            instrumentation.runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    TransitionManager.beginDelayedTransition(sceneRoot, slide);
-                    redSquare.setVisibility(View.INVISIBLE);
-                    greenSquare.setVisibility(View.INVISIBLE);
-                    hello.setVisibility(View.INVISIBLE);
-                }
+            mActivityRule.runOnUiThread(() -> {
+                TransitionManager.beginDelayedTransition(sceneRoot, slide);
+                redSquare.setVisibility(View.INVISIBLE);
+                greenSquare.setVisibility(View.INVISIBLE);
+                hello.setVisibility(View.INVISIBLE);
             });
-            assertTrue(listener.startLatch.await(1, TimeUnit.SECONDS));
-            assertEquals(1, listener.endLatch.getCount());
+            verify(listener, within(1000)).onTransitionStart(any());
+            verify(listener, never()).onTransitionEnd(any());
             assertEquals(View.VISIBLE, redSquare.getVisibility());
             assertEquals(View.VISIBLE, greenSquare.getVisibility());
             assertEquals(View.VISIBLE, hello.getVisibility());
@@ -100,9 +97,9 @@
             float redStartY = redSquare.getTranslationY();
 
             Thread.sleep(200);
-            assertTranslation(slideEdge, redSquare);
-            assertTranslation(slideEdge, greenSquare);
-            assertTranslation(slideEdge, hello);
+            verifyTranslation(slideEdge, redSquare);
+            verifyTranslation(slideEdge, greenSquare);
+            verifyTranslation(slideEdge, hello);
 
             final float redMidX = redSquare.getTranslationX();
             final float redMidY = redSquare.getTranslationY();
@@ -130,64 +127,52 @@
                             redStartY < redSquare.getTranslationY());
                     break;
             }
-            assertTrue(listener.endLatch.await(1, TimeUnit.SECONDS));
-            instrumentation.waitForIdleSync();
+            verify(listener, within(1000)).onTransitionEnd(any());
+            mInstrumentation.waitForIdleSync();
 
-            assertNoTranslation(redSquare);
-            assertNoTranslation(greenSquare);
-            assertNoTranslation(hello);
+            verifyNoTranslation(redSquare);
+            verifyNoTranslation(greenSquare);
+            verifyNoTranslation(hello);
             assertEquals(View.INVISIBLE, redSquare.getVisibility());
             assertEquals(View.INVISIBLE, greenSquare.getVisibility());
             assertEquals(View.INVISIBLE, hello.getVisibility());
         }
     }
 
+    @Test
     public void testSlideIn() throws Throwable {
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            final SimpleTransitionListener listener = new SimpleTransitionListener();
+            final Transition.TransitionListener listener =
+                    mock(Transition.TransitionListener.class);
             slide.addListener(listener);
 
-            final Instrumentation instrumentation = getInstrumentation();
-            final Activity activity = getActivity();
+            mActivityRule.runOnUiThread(() -> mActivity.setContentView(R.layout.scene1));
+            mInstrumentation.waitForIdleSync();
 
-            instrumentation.runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    activity.setContentView(R.layout.scene1);
-                }
+            final View redSquare = mActivity.findViewById(R.id.redSquare);
+            final View greenSquare = mActivity.findViewById(R.id.greenSquare);
+            final View hello = mActivity.findViewById(R.id.hello);
+            final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.holder);
+
+            mActivityRule.runOnUiThread(() -> {
+                redSquare.setVisibility(View.INVISIBLE);
+                greenSquare.setVisibility(View.INVISIBLE);
+                hello.setVisibility(View.INVISIBLE);
             });
-            instrumentation.waitForIdleSync();
-
-            final View redSquare = activity.findViewById(R.id.redSquare);
-            final View greenSquare = activity.findViewById(R.id.greenSquare);
-            final View hello = activity.findViewById(R.id.hello);
-            final ViewGroup sceneRoot = (ViewGroup) activity.findViewById(R.id.holder);
-
-            instrumentation.runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    redSquare.setVisibility(View.INVISIBLE);
-                    greenSquare.setVisibility(View.INVISIBLE);
-                    hello.setVisibility(View.INVISIBLE);
-                }
-            });
-            instrumentation.waitForIdleSync();
+            mInstrumentation.waitForIdleSync();
 
             // now slide in
-            instrumentation.runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    TransitionManager.beginDelayedTransition(sceneRoot, slide);
-                    redSquare.setVisibility(View.VISIBLE);
-                    greenSquare.setVisibility(View.VISIBLE);
-                    hello.setVisibility(View.VISIBLE);
-                }
+            mActivityRule.runOnUiThread(() -> {
+                TransitionManager.beginDelayedTransition(sceneRoot, slide);
+                redSquare.setVisibility(View.VISIBLE);
+                greenSquare.setVisibility(View.VISIBLE);
+                hello.setVisibility(View.VISIBLE);
             });
-            assertTrue(listener.startLatch.await(1, TimeUnit.SECONDS));
+            verify(listener, within(1000)).onTransitionStart(any());
 
-            assertEquals(1, listener.endLatch.getCount());
+            verify(listener, never()).onTransitionEnd(any());
             assertEquals(View.VISIBLE, redSquare.getVisibility());
             assertEquals(View.VISIBLE, greenSquare.getVisibility());
             assertEquals(View.VISIBLE, hello.getVisibility());
@@ -196,9 +181,9 @@
             final float redStartY = redSquare.getTranslationY();
 
             Thread.sleep(200);
-            assertTranslation(slideEdge, redSquare);
-            assertTranslation(slideEdge, greenSquare);
-            assertTranslation(slideEdge, hello);
+            verifyTranslation(slideEdge, redSquare);
+            verifyTranslation(slideEdge, greenSquare);
+            verifyTranslation(slideEdge, hello);
             final float redMidX = redSquare.getTranslationX();
             final float redMidY = redSquare.getTranslationY();
 
@@ -226,19 +211,19 @@
                             redStartY > redSquare.getTranslationY());
                     break;
             }
-            assertTrue(listener.endLatch.await(1, TimeUnit.SECONDS));
-            instrumentation.waitForIdleSync();
+            verify(listener, within(1000)).onTransitionEnd(any());
+            mInstrumentation.waitForIdleSync();
 
-            assertNoTranslation(redSquare);
-            assertNoTranslation(greenSquare);
-            assertNoTranslation(hello);
+            verifyNoTranslation(redSquare);
+            verifyNoTranslation(greenSquare);
+            verifyNoTranslation(hello);
             assertEquals(View.VISIBLE, redSquare.getVisibility());
             assertEquals(View.VISIBLE, greenSquare.getVisibility());
             assertEquals(View.VISIBLE, hello.getVisibility());
         }
     }
 
-    private void assertTranslation(int slideEdge, View view) {
+    private void verifyTranslation(int slideEdge, View view) {
         switch (slideEdge) {
             case Gravity.LEFT:
             case Gravity.START:
@@ -261,7 +246,7 @@
         }
     }
 
-    private void assertNoTranslation(View view) {
+    private void verifyNoTranslation(View view) {
         assertEquals(0f, view.getTranslationX(), 0.01f);
         assertEquals(0f, view.getTranslationY(), 0.01f);
     }
diff --git a/tests/tests/transition/src/android/transition/cts/TargetActivity.java b/tests/tests/transition/src/android/transition/cts/TargetActivity.java
new file mode 100644
index 0000000..68175d5
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TargetActivity.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.transition.cts;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.transition.Transition.TransitionListener;
+
+import com.android.compatibility.common.util.transition.TrackingTransition;
+import com.android.compatibility.common.util.transition.TrackingVisibility;
+
+public class TargetActivity extends Activity {
+    public static final String EXTRA_LAYOUT_ID = "layoutId";
+
+    final TrackingVisibility enterTransition = new TrackingVisibility();
+    final TrackingVisibility returnTransition = new TrackingVisibility();
+    final TrackingTransition sharedElementEnterTransition = new TrackingTransition();
+    final TrackingTransition sharedElementReturnTransition = new TrackingTransition();
+
+    final TransitionListener enterListener = mock(TransitionListener.class);
+    final TransitionListener returnListener = mock(TransitionListener.class);
+
+    public static TargetActivity sLastCreated;
+
+    @Override
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+        Intent intent = getIntent();
+        int layoutId = R.layout.transition_main;
+        if (intent != null) {
+            layoutId = intent.getIntExtra(EXTRA_LAYOUT_ID, layoutId);
+        }
+        setContentView(layoutId);
+        getWindow().setEnterTransition(enterTransition);
+        getWindow().setReturnTransition(returnTransition);
+        getWindow().setSharedElementEnterTransition(sharedElementEnterTransition);
+        getWindow().setSharedElementReturnTransition(sharedElementReturnTransition);
+        enterTransition.addListener(enterListener);
+        returnTransition.addListener(returnListener);
+
+        sLastCreated = this;
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionActivity.java b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
index be9bf24..afc48be 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
@@ -17,21 +17,7 @@
 package android.transition.cts;
 
 import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RadialGradient;
-import android.graphics.Shader;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
 import android.os.Bundle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import java.util.ArrayList;
-
-import android.transition.cts.R;
 
 public class TransitionActivity extends Activity {
     @Override
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..9a7ab94
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TransitionInflaterTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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 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.junit.Assert.fail;
+
+import android.content.Context;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+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.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TransitionInflaterTest extends BaseTransitionTest {
+    @Test
+    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());
+    }
+
+    @Test
+    public void testInflation() {
+        TransitionInflater inflater = TransitionInflater.from(mActivity);
+        verifyFadeProperties(inflater.inflateTransition(R.transition.fade));
+        verifyChangeBoundsProperties(inflater.inflateTransition(R.transition.change_bounds));
+        verifySlideProperties(inflater.inflateTransition(R.transition.slide));
+        verifyExplodeProperties(inflater.inflateTransition(R.transition.explode));
+        verifyChangeImageTransformProperties(
+                inflater.inflateTransition(R.transition.change_image_transform));
+        verifyChangeTransformProperties(inflater.inflateTransition(R.transition.change_transform));
+        verifyChangeClipBoundsProperties(
+                inflater.inflateTransition(R.transition.change_clip_bounds));
+        verifyAutoTransitionProperties(inflater.inflateTransition(R.transition.auto_transition));
+        verifyChangeScrollProperties(inflater.inflateTransition(R.transition.change_scroll));
+        verifyTransitionSetProperties(inflater.inflateTransition(R.transition.transition_set));
+        verifyCustomTransitionProperties(
+                inflater.inflateTransition(R.transition.custom_transition));
+        verifyTargetIds(inflater.inflateTransition(R.transition.target_ids));
+        verifyTargetNames(inflater.inflateTransition(R.transition.target_names));
+        verifyTargetClass(inflater.inflateTransition(R.transition.target_classes));
+        verifyArcMotion(inflater.inflateTransition(R.transition.arc_motion));
+        verifyCustomPathMotion(inflater.inflateTransition(R.transition.custom_path_motion));
+        verifyPatternPathMotion(inflater.inflateTransition(R.transition.pattern_path_motion));
+    }
+
+    @Test
+    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 verifyFadeProperties(Transition transition) {
+        assertTrue(transition instanceof Fade);
+        Fade fade = (Fade) transition;
+        assertEquals(Fade.OUT, fade.getMode());
+    }
+
+    private void verifyChangeBoundsProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeBounds);
+        ChangeBounds changeBounds = (ChangeBounds) transition;
+        assertTrue(changeBounds.getResizeClip());
+    }
+
+    private void verifySlideProperties(Transition transition) {
+        assertTrue(transition instanceof Slide);
+        Slide slide = (Slide) transition;
+        assertEquals(Gravity.TOP, slide.getSlideEdge());
+    }
+
+    private void verifyExplodeProperties(Transition transition) {
+        assertTrue(transition instanceof Explode);
+        Visibility visibility = (Visibility) transition;
+        assertEquals(Visibility.MODE_IN, visibility.getMode());
+    }
+
+    private void verifyChangeImageTransformProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeImageTransform);
+    }
+
+    private void verifyChangeTransformProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeTransform);
+        ChangeTransform changeTransform = (ChangeTransform) transition;
+        assertFalse(changeTransform.getReparent());
+        assertFalse(changeTransform.getReparentWithOverlay());
+    }
+
+    private void verifyChangeClipBoundsProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeClipBounds);
+    }
+
+    private void verifyAutoTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof AutoTransition);
+    }
+
+    private void verifyChangeScrollProperties(Transition transition) {
+        assertTrue(transition instanceof ChangeScroll);
+    }
+
+    private void verifyTransitionSetProperties(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 verifyCustomTransitionProperties(Transition transition) {
+        assertTrue(transition instanceof CustomTransition);
+    }
+
+    private void verifyTargetIds(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 verifyTargetNames(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 verifyTargetClass(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 verifyArcMotion(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 verifyCustomPathMotion(Transition transition) {
+        assertNotNull(transition);
+        PathMotion motion = transition.getPathMotion();
+        assertNotNull(motion);
+        assertTrue(motion instanceof CustomPathMotion);
+    }
+
+    private void verifyPatternPathMotion(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..d4375cc 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -15,146 +15,205 @@
  */
 package android.transition.cts;
 
-import android.transition.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+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 android.graphics.Rect;
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Scene;
+import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.View;
+import android.view.ViewTreeObserver;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TransitionManagerTest extends BaseTransitionTest {
-
-    public TransitionManagerTest() {
-    }
-
+    @Test
     public void testBeginDelayedTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                View view = mActivity.getLayoutInflater().inflate(R.layout.scene1, mSceneRoot,
-                        false);
-                mSceneRoot.addView(view);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            View view = mActivity.getLayoutInflater().inflate(R.layout.scene1, mSceneRoot,
+                    false);
+            mSceneRoot.addView(view);
         });
 
         waitForStart();
         waitForEnd(300);
-        assertEquals(1, mListener.resumeLatch.getCount());
-        assertEquals(1, mListener.pauseLatch.getCount());
-        assertEquals(1, mListener.cancelLatch.getCount());
-        assertNotNull(mListener.transition);
-        assertEquals(TestTransition.class, mListener.transition.getClass());
-        assertTrue(mTransition != mListener.transition);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNotNull(mActivity.findViewById(R.id.redSquare));
-                assertNotNull(mActivity.findViewById(R.id.greenSquare));
-            }
+        verify(mListener, never()).onTransitionResume(any());
+        verify(mListener, never()).onTransitionPause(any());
+        verify(mListener, never()).onTransitionCancel(any());
+        ArgumentCaptor<Transition> transitionArgumentCaptor =
+                ArgumentCaptor.forClass(Transition.class);
+        verify(mListener, times(1)).onTransitionStart(transitionArgumentCaptor.capture());
+        assertEquals(TestTransition.class, transitionArgumentCaptor.getValue().getClass());
+        assertTrue(mTransition != transitionArgumentCaptor.getValue());
+        mActivityRule.runOnUiThread(() -> {
+            assertNotNull(mActivity.findViewById(R.id.redSquare));
+            assertNotNull(mActivity.findViewById(R.id.greenSquare));
         });
     }
 
+    @Test
+    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;
+                    }
+                });
+        mActivityRule.runOnUiThread(() -> TransitionManager.beginDelayedTransition(mSceneRoot));
+        enterScene(R.layout.scene6);
+        assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
+        ensureRedSquareIsMoving();
+        endTransition();
+    }
+
+    private void ensureRedSquareIsMoving() throws InterruptedException {
+        final View view = mActivity.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(() -> {
+            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));
+    }
+
+    @Test
     public void testGo() throws Throwable {
         startTransition(R.layout.scene1);
         waitForStart();
         waitForEnd(300);
 
-        assertEquals(1, mListener.resumeLatch.getCount());
-        assertEquals(1, mListener.pauseLatch.getCount());
-        assertEquals(1, mListener.cancelLatch.getCount());
-        assertNotNull(mListener.transition);
-        assertEquals(TestTransition.class, mListener.transition.getClass());
-        assertTrue(mTransition != mListener.transition);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertNotNull(mActivity.findViewById(R.id.redSquare));
-                assertNotNull(mActivity.findViewById(R.id.greenSquare));
-            }
+        verify(mListener, never()).onTransitionResume(any());
+        verify(mListener, never()).onTransitionPause(any());
+        verify(mListener, never()).onTransitionCancel(any());
+        ArgumentCaptor<Transition> transitionArgumentCaptor =
+                ArgumentCaptor.forClass(Transition.class);
+        verify(mListener, times(1)).onTransitionStart(transitionArgumentCaptor.capture());
+        assertEquals(TestTransition.class, transitionArgumentCaptor.getValue().getClass());
+        assertTrue(mTransition != transitionArgumentCaptor.getValue());
+        mActivityRule.runOnUiThread(() -> {
+            assertNotNull(mActivity.findViewById(R.id.redSquare));
+            assertNotNull(mActivity.findViewById(R.id.greenSquare));
         });
     }
 
+    @Test
+    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);
+        mActivityRule.runOnUiThread(() -> TransitionManager.go(scene6));
+        assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
+        ensureRedSquareIsMoving();
+        endTransition();
+    }
+
+    @Test
     public void testSetTransition1() throws Throwable {
         final TransitionManager transitionManager = new TransitionManager();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
-                transitionManager.setTransition(scene, mTransition);
-                transitionManager.transitionTo(scene);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+            transitionManager.setTransition(scene, mTransition);
+            transitionManager.transitionTo(scene);
         });
 
         waitForStart();
         waitForEnd(300);
-        assertEquals(1, mListener.resumeLatch.getCount());
-        assertEquals(1, mListener.pauseLatch.getCount());
-        assertEquals(1, mListener.cancelLatch.getCount());
-        assertNotNull(mListener.transition);
-        assertEquals(TestTransition.class, mListener.transition.getClass());
-        assertTrue(mTransition != mListener.transition);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListener.startLatch = new CountDownLatch(1);
-                mListener.endLatch = new CountDownLatch(1);
-                assertNotNull(mActivity.findViewById(R.id.redSquare));
-                assertNotNull(mActivity.findViewById(R.id.greenSquare));
-                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
-                transitionManager.transitionTo(scene);
-            }
+        verify(mListener, never()).onTransitionResume(any());
+        verify(mListener, never()).onTransitionPause(any());
+        verify(mListener, never()).onTransitionCancel(any());
+        ArgumentCaptor<Transition> transitionArgumentCaptor =
+                ArgumentCaptor.forClass(Transition.class);
+        verify(mListener, times(1)).onTransitionStart(transitionArgumentCaptor.capture());
+        assertEquals(TestTransition.class, transitionArgumentCaptor.getValue().getClass());
+        assertTrue(mTransition != transitionArgumentCaptor.getValue());
+        mActivityRule.runOnUiThread(() -> {
+            reset(mListener);
+            assertNotNull(mActivity.findViewById(R.id.redSquare));
+            assertNotNull(mActivity.findViewById(R.id.greenSquare));
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+            transitionManager.transitionTo(scene);
         });
-        assertFalse(mListener.startLatch.await(50, TimeUnit.MILLISECONDS));
+        SystemClock.sleep(50);
+        verify(mListener, never()).onTransitionStart(any());
         endTransition();
     }
 
+    @Test
     public void testSetTransition2() throws Throwable {
         final TransitionManager transitionManager = new TransitionManager();
         final Scene[] scenes = new Scene[3];
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scenes[0] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
-                scenes[1] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
-                scenes[2] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, mActivity);
-                transitionManager.setTransition(scenes[0], scenes[1], mTransition);
-                transitionManager.transitionTo(scenes[0]);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            scenes[0] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+            scenes[1] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+            scenes[2] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, mActivity);
+            transitionManager.setTransition(scenes[0], scenes[1], mTransition);
+            transitionManager.transitionTo(scenes[0]);
         });
-        assertFalse(mListener.startLatch.await(100, TimeUnit.MILLISECONDS));
+        SystemClock.sleep(100);
+        verify(mListener, never()).onTransitionStart(any());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                transitionManager.transitionTo(scenes[1]);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> transitionManager.transitionTo(scenes[1]));
 
         waitForStart();
         waitForEnd(300);
-        assertEquals(1, mListener.resumeLatch.getCount());
-        assertEquals(1, mListener.pauseLatch.getCount());
-        assertEquals(1, mListener.cancelLatch.getCount());
-        assertNotNull(mListener.transition);
-        assertEquals(TestTransition.class, mListener.transition.getClass());
-        assertTrue(mTransition != mListener.transition);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListener.startLatch = new CountDownLatch(1);
-                mListener.endLatch = new CountDownLatch(1);
-                transitionManager.transitionTo(scenes[2]);
-            }
+        verify(mListener, never()).onTransitionResume(any());
+        verify(mListener, never()).onTransitionPause(any());
+        verify(mListener, never()).onTransitionCancel(any());
+        ArgumentCaptor<Transition> transitionArgumentCaptor =
+                ArgumentCaptor.forClass(Transition.class);
+        verify(mListener, times(1)).onTransitionStart(transitionArgumentCaptor.capture());
+        assertEquals(TestTransition.class, transitionArgumentCaptor.getValue().getClass());
+        assertTrue(mTransition != transitionArgumentCaptor.getValue());
+        mActivityRule.runOnUiThread(() -> {
+            reset(mListener);
+            transitionManager.transitionTo(scenes[2]);
         });
-        assertFalse(mListener.startLatch.await(50, TimeUnit.MILLISECONDS));
+        SystemClock.sleep(50);
+        verify(mListener, never()).onTransitionStart(any());
         endTransition();
     }
 
+    @Test
     public void testEndTransitions() throws Throwable {
         mTransition.setDuration(400);
 
@@ -164,19 +223,19 @@
         waitForEnd(100);
     }
 
+    @Test
     public void testEndTransitionsBeforeStarted() throws Throwable {
         mTransition.setDuration(400);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
-                TransitionManager.go(scene, mTransition);
-                TransitionManager.endTransitions(mSceneRoot);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+            TransitionManager.go(scene, mTransition);
+            TransitionManager.endTransitions(mSceneRoot);
         });
-        assertFalse(mListener.startLatch.await(100, TimeUnit.MILLISECONDS));
-        assertFalse(mListener.endLatch.await(10, TimeUnit.MILLISECONDS));
+        SystemClock.sleep(100);
+        verify(mListener, never()).onTransitionStart(any());
+        SystemClock.sleep(10);
+        verify(mListener, never()).onTransitionEnd(any());
     }
 }
 
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java b/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
index adfc36a..60cd5b0 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionSetTest.java
@@ -15,21 +15,39 @@
  */
 package android.transition.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.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 android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.ChangeBounds;
 import android.transition.Fade;
+import android.transition.Transition;
 import android.transition.TransitionSet;
 
-import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TransitionSetTest extends BaseTransitionTest {
-
+    @Test
     public void testTransitionTogether() throws Throwable {
         TransitionSet transitionSet = new TransitionSet();
         Fade fade = new Fade();
-        SimpleTransitionListener fadeListener = new SimpleTransitionListener();
+        final Transition.TransitionListener fadeListener =
+                mock(Transition.TransitionListener.class);
         fade.addListener(fadeListener);
         ChangeBounds changeBounds = new ChangeBounds();
-        SimpleTransitionListener changeBoundsListener = new SimpleTransitionListener();
+        final Transition.TransitionListener changeBoundsListener =
+                mock(Transition.TransitionListener.class);
         changeBounds.addListener(changeBoundsListener);
         transitionSet.addTransition(fade);
         transitionSet.addTransition(changeBounds);
@@ -39,22 +57,22 @@
         assertEquals(TransitionSet.ORDERING_TOGETHER, transitionSet.getOrdering());
         enterScene(R.layout.scene1);
         startTransition(R.layout.scene3);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(0, fadeListener.startLatch.getCount());
-                assertEquals(0, changeBoundsListener.startLatch.getCount());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            verify(fadeListener, times(1)).onTransitionStart(any());
+            verify(changeBoundsListener, times(1)).onTransitionStart(any());
         });
     }
 
+    @Test
     public void testTransitionSequentially() throws Throwable {
         TransitionSet transitionSet = new TransitionSet();
         Fade fade = new Fade();
-        SimpleTransitionListener fadeListener = new SimpleTransitionListener();
+        final Transition.TransitionListener fadeListener =
+                mock(Transition.TransitionListener.class);
         fade.addListener(fadeListener);
         ChangeBounds changeBounds = new ChangeBounds();
-        SimpleTransitionListener changeBoundsListener = new SimpleTransitionListener();
+        final Transition.TransitionListener changeBoundsListener =
+                mock(Transition.TransitionListener.class);
         changeBounds.addListener(changeBoundsListener);
         transitionSet.addTransition(fade);
         transitionSet.addTransition(changeBounds);
@@ -67,22 +85,16 @@
 
         enterScene(R.layout.scene1);
         startTransition(R.layout.scene3);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(0, fadeListener.startLatch.getCount());
-                assertEquals(1, changeBoundsListener.startLatch.getCount());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            verify(fadeListener, times(1)).onTransitionStart(any());
+            verify(changeBoundsListener, never()).onTransitionStart(any());
         });
-        assertTrue(fadeListener.endLatch.await(400, TimeUnit.MILLISECONDS));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(0, changeBoundsListener.startLatch.getCount());
-            }
-        });
+        verify(fadeListener, within(400)).onTransitionEnd(any());
+        mActivityRule.runOnUiThread(
+                () -> verify(changeBoundsListener, times(1)).onTransitionStart(any()));
     }
 
+    @Test
     public void testTransitionCount() throws Throwable {
         TransitionSet transitionSet = new TransitionSet();
         assertEquals(0, transitionSet.getTransitionCount());
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
index 9ae568a..506ea7b 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -15,14 +15,29 @@
  */
 package android.transition.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+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.times;
+import static org.mockito.Mockito.verify;
+
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.graphics.Rect;
-import android.os.Debug;
 import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 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;
@@ -38,62 +53,59 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TransitionTest extends BaseTransitionTest {
-
-    public TransitionTest() {
-    }
-
+    @Test
     public void testAddListener() throws Throwable {
         startTransition(R.layout.scene1);
         waitForStart();
 
-        final SimpleTransitionListener listener2 = new SimpleTransitionListener();
+        final Transition.TransitionListener listener2 = mock(Transition.TransitionListener.class);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                AutoTransition autoTransition = new AutoTransition();
-                autoTransition.setDuration(100);
-                autoTransition.addListener(listener2);
-                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
-                TransitionManager.go(scene, autoTransition);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            AutoTransition autoTransition = new AutoTransition();
+            autoTransition.setDuration(100);
+            autoTransition.addListener(listener2);
+            Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+            TransitionManager.go(scene, autoTransition);
         });
 
         waitForStart(listener2);
 
-        assertEquals(0, mListener.pauseLatch.getCount());
-        assertEquals(0, mListener.resumeLatch.getCount());
-        assertEquals(1, mListener.cancelLatch.getCount());
-        assertEquals(1, mListener.endLatch.getCount());
-        assertEquals(0, mListener.startLatch.getCount());
+        verify(mListener, times(1)).onTransitionPause(any());
+        verify(mListener, times(1)).onTransitionResume(any());
+        verify(mListener, never()).onTransitionCancel(any());
+        verify(mListener, never()).onTransitionEnd(any());
+        verify(mListener, times(1)).onTransitionStart(any());
 
-        assertEquals(1, listener2.pauseLatch.getCount());
-        assertEquals(1, listener2.resumeLatch.getCount());
-        assertEquals(1, listener2.cancelLatch.getCount());
-        assertEquals(1, listener2.endLatch.getCount());
-        assertEquals(0, listener2.startLatch.getCount());
+        verify(listener2, never()).onTransitionPause(any());
+        verify(listener2, never()).onTransitionResume(any());
+        verify(listener2, never()).onTransitionCancel(any());
+        verify(listener2, never()).onTransitionEnd(any());
+        verify(listener2, times(1)).onTransitionStart(any());
         endTransition();
     }
 
+    @Test
     public void testRemoveListener() throws Throwable {
         startTransition(R.layout.scene1);
         waitForStart();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTransition.removeListener(mListener);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTransition.removeListener(mListener));
 
-        assertFalse(mListener.endLatch.await(250, TimeUnit.MILLISECONDS));
+        SystemClock.sleep(250);
+        verify(mListener, never()).onTransitionEnd(any());
     }
 
+    @Test
     public void testAddTargetId() throws Throwable {
         enterScene(R.layout.scene4);
         assertNotNull(mTransition.getTargetIds());
@@ -107,6 +119,7 @@
         endTransition();
     }
 
+    @Test
     public void testRemoveTargetId() throws Throwable {
         enterScene(R.layout.scene4);
         mTransition.addTarget(R.id.holder);
@@ -123,6 +136,7 @@
         endTransition();
     }
 
+    @Test
     public void testAddTargetClass() throws Throwable {
         enterScene(R.layout.scene4);
         assertNull(mTransition.getTargetTypes());
@@ -135,6 +149,7 @@
         endTransition();
     }
 
+    @Test
     public void testRemoveTargetClass() throws Throwable {
         enterScene(R.layout.scene4);
         mTransition.addTarget(TextView.class);
@@ -150,24 +165,17 @@
         endTransition();
     }
 
+    @Test
     public void testAddTargetView() throws Throwable {
         enterScene(R.layout.scene1);
 
         final View[] target = new View[1];
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                target[0] = mActivity.findViewById(R.id.hello);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> target[0] = mActivity.findViewById(R.id.hello));
         mTransition.addTarget(target[0]);
         assertEquals(1, mTransition.getTargets().size());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                target[0].setVisibility(View.GONE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            target[0].setVisibility(View.GONE);
         });
         waitForStart();
         assertEquals(1, mTargets.size());
@@ -175,17 +183,15 @@
         endTransition();
     }
 
+    @Test
     public void testRemoveTargetView() throws Throwable {
         enterScene(R.layout.scene1);
 
         final View[] target = new View[3];
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                target[0] = mActivity.findViewById(R.id.hello);
-                target[1] = mActivity.findViewById(R.id.greenSquare);
-                target[2] = mActivity.findViewById(R.id.redSquare);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            target[0] = mActivity.findViewById(R.id.hello);
+            target[1] = mActivity.findViewById(R.id.greenSquare);
+            target[2] = mActivity.findViewById(R.id.redSquare);
         });
 
         mTransition.addTarget(target[0]);
@@ -194,12 +200,9 @@
         mTransition.removeTarget(target[2]); // should do nothing
         mTransition.removeTarget(target[1]);
         assertEquals(1, mTransition.getTargets().size());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                target[0].setVisibility(View.GONE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            target[0].setVisibility(View.GONE);
         });
         waitForStart();
         assertEquals(1, mTargets.size());
@@ -207,6 +210,7 @@
         endTransition();
     }
 
+    @Test
     public void testAddTargetName() throws Throwable {
         enterScene(R.layout.scene4);
         assertNull(mTransition.getTargetNames());
@@ -220,6 +224,7 @@
         endTransition();
     }
 
+    @Test
     public void testRemoveTargetName() throws Throwable {
         enterScene(R.layout.scene4);
         mTransition.addTarget("holder");
@@ -237,22 +242,22 @@
         endTransition();
     }
 
+    @Test
     public void testIsTransitionRequired() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition = new NotRequiredTransition();
+        assertFalse(mTransition.isTransitionRequired(null, null));
         resetListener();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
-                mActivity.findViewById(R.id.hello).setVisibility(View.GONE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+            mActivity.findViewById(R.id.hello).setVisibility(View.GONE);
         });
         waitForStart();
         assertEquals(0, mTargets.size());
         endTransition();
     }
 
+    @Test
     public void testCanRemoveViews() throws Throwable {
         enterScene(R.layout.scene1);
         assertFalse(mTransition.canRemoveViews());
@@ -281,10 +286,11 @@
         startTransition(R.layout.scene2);
     }
 
+    @Test
     public void testExcludeChildrenView() throws Throwable {
         View layout1 = loadLayout(R.layout.scene1);
         Scene scene1 = loadScene(layout1);
-        enterScene(R.layout.scene1);
+        enterScene(scene1);
         View holder1 = layout1.findViewById(R.id.holder);
         mTransition.excludeChildren(holder1, true);
         View layout2 = loadLayout(R.layout.scene2);
@@ -292,29 +298,48 @@
         View holder2 = layout2.findViewById(R.id.holder);
         mTransition.excludeChildren(holder2, true);
         startTransition(scene2);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
 
         mTransition.excludeChildren(holder1, false); // remove it
         mTransition.excludeChildren(holder2, false); // remove it
         resetListener();
         startTransition(scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // it is running as expected
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
     public void testExcludeChildrenId() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition.excludeChildren(R.id.holder, true);
         startTransition(R.layout.scene2);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
 
         resetListener();
         mTransition.excludeChildren(R.id.holder, false); // remove it
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // It is running
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
+    public void testExcludeChildrenClass() throws Throwable {
+        enterScene(R.layout.scene1);
+        mTransition.excludeChildren(RelativeLayout.class, true);
+        startTransition(R.layout.scene2);
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
+
+        resetListener();
+        mTransition.excludeChildren(RelativeLayout.class, false); // remove it
+        startTransition(R.layout.scene1);
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
+        endTransition();
+    }
+
+    @Test
     public void testExcludeTargetView() throws Throwable {
         View layout1 = loadLayout(R.layout.scene1);
         Scene scene1 = loadScene(layout1);
@@ -322,54 +347,61 @@
         View redSquare1 = layout1.findViewById(R.id.redSquare);
         mTransition.excludeTarget(redSquare1, true);
         startTransition(R.layout.scene7);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        waitForEnd(600);
 
         mTransition.excludeTarget(redSquare1, false); // remove it
         resetListener();
         startTransition(scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // it is running as expected
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
     public void testExcludeTargetId() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition.excludeTarget(R.id.redSquare, true);
         startTransition(R.layout.scene7);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
 
         resetListener();
         mTransition.excludeTarget(R.id.redSquare, false); // remove it
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // It is running
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
     public void testExcludeTargetClass() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition.excludeTarget(TextView.class, true);
         startTransition(R.layout.scene3);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
 
         resetListener();
         mTransition.excludeTarget(TextView.class, false); // remove it
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // It is running
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
     public void testExcludeTargetName() throws Throwable {
         enterScene(R.layout.scene1);
         mTransition.excludeTarget("hello", true);
         startTransition(R.layout.scene3);
-        waitForEnd(0); // Should already be ended, since no children are transitioning
+        // Should already be ended, since no children are transitioning
+        verify(mListener, times(1)).onTransitionEnd(any());
 
         resetListener();
         mTransition.excludeTarget("hello", false); // remove it
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount()); // It is running
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         endTransition();
     }
 
+    @Test
     public void testDuration() throws Throwable {
         assertEquals(-1, mTransition.getDuration());
         enterScene(R.layout.scene1);
@@ -382,7 +414,9 @@
         assertEquals(500, endTime - startTime, 100);
     }
 
+    @Test
     public void testEpicenter() throws Throwable {
+        assertNull(mTransition.getEpicenter());
         EpicenterCallback callback = new EpicenterCallback() {
             @Override
             public Rect onGetEpicenter(Transition transition) {
@@ -390,9 +424,11 @@
             }
         };
         mTransition.setEpicenterCallback(callback);
-        assertEquals(callback, mTransition.getEpicenterCallback());
+        assertSame(callback, mTransition.getEpicenterCallback());
+        assertEquals(new Rect(0, 0, 1, 1), mTransition.getEpicenter());
     }
 
+    @Test
     public void testInterpolator() throws Throwable {
         enterScene(R.layout.scene1);
         View redSquare = mActivity.findViewById(R.id.redSquare);
@@ -406,23 +442,26 @@
         startTransition(R.layout.scene4);
         assertFalse(transition.animators.isEmpty());
         Animator animator = transition.animators.get(redSquare);
-        AnimationStartListener listener = transition.listeners.get(redSquare);
-        assertTrue(listener.startLatch.await(100, TimeUnit.MILLISECONDS));
+        Animator.AnimatorListener listener = transition.listeners.get(redSquare);
+        verify(listener, within(100)).onAnimationStart(any());
         assertSame(interpolator, animator.getInterpolator());
         endTransition();
     }
 
+    @Test
     public void testName() throws Throwable {
         assertEquals("android.transition.cts.BaseTransitionTest$TestTransition",
                 mTransition.getName());
     }
 
+    @Test
     public void testPathMotion() throws Throwable {
         PathMotion pathMotion = new ArcMotion();
         mTransition.setPathMotion(pathMotion);
         assertEquals(pathMotion, mTransition.getPathMotion());
     }
 
+    @Test
     public void testPropagation() throws Throwable {
         enterScene(R.layout.scene1);
         CaptureAnimatorTransition transition = new CaptureAnimatorTransition();
@@ -460,13 +499,23 @@
         startTransition(R.layout.scene4);
         Animator redSquareAnimator = transition.animators.get(redSquare);
         Animator greenSquareAnimator = transition.animators.get(greenSquare);
-        AnimationStartListener listener = transition.listeners.get(redSquare);
-        assertTrue(listener.startLatch.await(100, TimeUnit.MILLISECONDS));
+        Animator.AnimatorListener listener = transition.listeners.get(redSquare);
+        verify(listener, within(100)).onAnimationStart(any());
         assertEquals(0, redSquareAnimator.getStartDelay());
         assertEquals(diffTop, greenSquareAnimator.getStartDelay());
         endTransition();
     }
 
+    @Test
+    public void testSetPropagation() throws Throwable {
+        Transition transition = new ChangeBounds();
+        assertNull(transition.getPropagation());
+        TransitionPropagation propagation = new CircularPropagation();
+        transition.setPropagation(propagation);
+        assertSame(propagation, transition.getPropagation());
+    }
+
+    @Test
     public void testStartDelay() throws Throwable {
         CaptureAnimatorTransition transition = new CaptureAnimatorTransition();
         mTransition = transition;
@@ -482,21 +531,26 @@
 
         Animator animator = transition.animators.get(redSquare);
         assertFalse(animator.isRunning());
-        AnimationStartListener listener = transition.listeners.get(redSquare);
-        assertTrue(listener.startLatch.await(250, TimeUnit.MILLISECONDS));
+        Animator.AnimatorListener listener = transition.listeners.get(redSquare);
+        verify(listener, within(250)).onAnimationStart(any());
         endTransition();
     }
 
+    @Test
     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();
     }
 
+    @Test
     public void testMatchOrder() throws Throwable {
         mTransition = new ChangeBounds();
         resetListener();
@@ -511,10 +565,62 @@
 
         resetListener();
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
         waitForEnd(400);
     }
 
+    @Test
+    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);
+        verify(mListener, within(500)).onTransitionEnd(any());
+        // createAnimator shouldn't have been called.
+        assertEquals(1, transition.latch.getCount());
+
+        assertNotNull(transition.getTransitionProperties());
+        assertEquals(1, transition.getTransitionProperties().length);
+    }
+
+    @Test
+    public void testGoWithNullParameter() throws Throwable {
+        final View layout1 = loadLayout(R.layout.scene1);
+        final Scene scene1 = loadScene(layout1);
+
+        final View layout3 = loadLayout(R.layout.scene3);
+        final Scene scene3 = loadScene(layout3);
+
+        enterScene(scene1);
+
+        mInstrumentation.runOnMainSync(() -> {
+            // scene1
+            assertSame(layout1, mActivity.findViewById(R.id.holder));
+            assertNotNull(mActivity.findViewById(R.id.hello));
+
+            TransitionManager.go(scene3, null);
+            // now at scene3
+            assertSame(layout3, mActivity.findViewById(R.id.holder));
+            assertNull(mActivity.findViewById(R.id.hello));
+
+            TransitionManager.go(scene1, null);
+
+            // now at scene1
+            assertSame(layout1, mActivity.findViewById(R.id.holder));
+            assertNotNull(mActivity.findViewById(R.id.hello));
+        });
+    }
+
     private class NotRequiredTransition extends TestTransition {
         @Override
         public boolean isTransitionRequired(TransitionValues startValues,
@@ -525,7 +631,7 @@
 
     private class CaptureAnimatorTransition extends TestTransition {
         public HashMap<View, Animator> animators = new HashMap<>();
-        public HashMap<View, AnimationStartListener> listeners = new HashMap<>();
+        public HashMap<View, Animator.AnimatorListener> listeners = new HashMap<>();
 
         @Override
         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
@@ -543,7 +649,7 @@
 
         private Animator setupAnimator(Animator animator, View view) {
             animators.put(view, animator);
-            AnimationStartListener listener = new AnimationStartListener();
+            Animator.AnimatorListener listener = mock(Animator.AnimatorListener.class);
             animator.addListener(listener);
             listeners.put(view, listener);
             return animator;
@@ -551,9 +657,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,18 +671,53 @@
         @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);
         }
     }
 
-    private class AnimationStartListener extends AnimatorListenerAdapter {
-        public CountDownLatch startLatch = new CountDownLatch(1);
+    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 void onAnimationStart(Animator animation) {
-            startLatch.countDown();
+        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..a71748a 100644
--- a/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
+++ b/tests/tests/transition/src/android/transition/cts/VisibilityTest.java
@@ -15,41 +15,64 @@
  */
 package android.transition.cts;
 
+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.never;
+import static org.mockito.Mockito.verify;
+
+import android.animation.Animator;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.transition.TransitionManager;
 import android.transition.TransitionValues;
 import android.transition.Visibility;
 import android.view.View;
+import android.view.ViewGroup;
 
+import org.junit.Before;
+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 VisibilityTest extends BaseTransitionTest {
     Visibility mVisibilityTransition;
 
-    public VisibilityTest() {
-    }
-
     @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        super.setup();
         mVisibilityTransition = (Visibility) mTransition;
     }
 
+    @Test
     public void testMode() throws Throwable {
         assertEquals(Visibility.MODE_IN | Visibility.MODE_OUT, mVisibilityTransition.getMode());
 
         // Should animate in and out
         enterScene(R.layout.scene4);
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         resetListener();
         startTransition(R.layout.scene4);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         // Now only animate in
         resetListener();
         mVisibilityTransition.setMode(Visibility.MODE_IN);
         startTransition(R.layout.scene1);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
 
         // No animation since it should only animate in
@@ -66,10 +89,11 @@
         // but it should animate out
         resetListener();
         startTransition(R.layout.scene4);
-        assertEquals(1, mListener.endLatch.getCount());
+        verify(mListener, never()).onTransitionEnd(any());
         waitForEnd(400);
     }
 
+    @Test
     public void testIsVisible() throws Throwable {
         assertFalse(mVisibilityTransition.isVisible(null));
 
@@ -80,29 +104,115 @@
         mTransition.captureStartValues(visibleValues);
 
         assertTrue(mVisibilityTransition.isVisible(visibleValues));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                redSquare.setVisibility(View.INVISIBLE);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> redSquare.setVisibility(View.INVISIBLE));
+        mInstrumentation.waitForIdleSync();
         TransitionValues invisibleValues = new TransitionValues();
         invisibleValues.view = redSquare;
         mTransition.captureStartValues(invisibleValues);
         assertFalse(mVisibilityTransition.isVisible(invisibleValues));
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                redSquare.setVisibility(View.GONE);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> redSquare.setVisibility(View.GONE));
+        mInstrumentation.waitForIdleSync();
         TransitionValues goneValues = new TransitionValues();
         goneValues.view = redSquare;
         mTransition.captureStartValues(goneValues);
         assertFalse(mVisibilityTransition.isVisible(goneValues));
     }
+
+    @Test
+    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.
+    }
+
+    @Test
+    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 = mActivity.findViewById(R.id.text);
+        mActivityRule.runOnUiThread(() -> {
+            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/tv/Android.mk b/tests/tests/tv/Android.mk
index 749e3d1..640e16e 100644
--- a/tests/tests/tv/Android.mk
+++ b/tests/tests/tv/Android.mk
@@ -29,7 +29,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/tv/AndroidTest.xml b/tests/tests/tv/AndroidTest.xml
index d5a133f..1b5621e 100644
--- a/tests/tests/tv/AndroidTest.xml
+++ b/tests/tests/tv/AndroidTest.xml
@@ -22,5 +22,6 @@
         <option name="package" value="android.tv.cts" />
         <!-- test-timeout unit is ms, value = 5 min -->
         <option name="test-timeout" value="300000" />
+        <option name="runtime-hint" value="9m" />
     </test>
 </configuration>
diff --git a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
index 9769175..4fe84f7 100644
--- a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.media.tv.TvContract;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
@@ -29,6 +28,8 @@
 
 import android.tv.cts.R;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
diff --git a/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java b/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
index a7b5805..2acf5ce 100644
--- a/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/HardwareSessionTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.media.tv.TvContract;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
@@ -31,6 +30,8 @@
 
 import android.tv.cts.R;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
index 526f401..e1c165b 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
@@ -19,7 +19,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.PollingCheck;
 import android.media.tv.TvContentRating;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager;
@@ -27,6 +26,8 @@
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index 47b5527..ab2073b 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.media.PlaybackParams;
 import android.media.tv.TvContentRating;
 import android.media.tv.TvContract;
@@ -45,6 +44,8 @@
 
 import android.tv.cts.R;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index 59cb902..47a6517 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.media.tv.TvContract;
 import android.media.tv.TvInputInfo;
@@ -38,6 +37,8 @@
 
 import android.tv.cts.R;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
diff --git a/tests/tests/uidisolation/AndroidTest.xml b/tests/tests/uidisolation/AndroidTest.xml
index e7717c0..746e756 100644
--- a/tests/tests/uidisolation/AndroidTest.xml
+++ b/tests/tests/uidisolation/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.uidisolation.cts" />
+        <option name="runtime-hint" value="15m" />
     </test>
 </configuration>
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index fd01e10..e1f6eef 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -26,7 +26,11 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    ctstestrunner \
+    mockito-target-minus-junit4 \
+    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 fcd38ae..59f7522 100644
--- a/tests/tests/uirendering/AndroidManifest.xml
+++ b/tests/tests/uirendering/AndroidManifest.xml
@@ -30,6 +30,8 @@
         <activity android:name="android.uirendering.cts.testinfrastructure.DrawActivity"
                   android:theme="@style/WhiteBackgroundTheme"
                   android:resizeableActivity="false" />
+        <activity android:name="android.uirendering.cts.testinfrastructure.MaterialActivity"
+                  android:theme="@android:style/Theme.Material.Light" />
         <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-nodpi/text_path_with_offset.png b/tests/tests/uirendering/res/drawable-nodpi/text_path_with_offset.png
new file mode 100644
index 0000000..533d1ea
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/text_path_with_offset.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/drawable/rectangle.xml b/tests/tests/uirendering/res/drawable/rectangle.xml
new file mode 100644
index 0000000..43c539f
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable/rectangle.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="90px"
+        android:width="90px"
+        android:viewportHeight="1"
+        android:viewportWidth="1" >
+
+    <group>
+        <path
+            android:name="box0"
+            android:pathData="m0,0l1,0l0,1l-1,0l0-1z"
+            android:fillColor="#FF0000" />
+    </group>
+</vector>
\ No newline at end of file
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/res/layout/textureview.xml b/tests/tests/uirendering/res/layout/textureview.xml
new file mode 100644
index 0000000..f2fbfd1
--- /dev/null
+++ b/tests/tests/uirendering/res/layout/textureview.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<TextureView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/test_width"
+    android:layout_height="@dimen/test_height" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorCountVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorCountVerifier.java
new file mode 100644
index 0000000..1cf71c5
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorCountVerifier.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.uirendering.cts.bitmapverifiers;
+
+import android.util.Log;
+
+public class ColorCountVerifier extends BitmapVerifier {
+    private int mColor;
+    private int mCount;
+
+    public ColorCountVerifier(int color, int count) {
+        mColor = color;
+        mCount = count;
+    }
+
+    @Override
+    public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
+        int count = 0;
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                if (bitmap[indexFromXAndY(x, y, stride, offset)] == mColor) {
+                    count++;
+                }
+            }
+        }
+        if (count != mCount) {
+            Log.d("ColorCountVerifier", ("Color count mismatch " + count) + " != " + mCount);
+        }
+        return count == mCount;
+    }
+
+}
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/BitmapFilterTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
index a2f0305..a954294 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -19,12 +19,13 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
+
 import org.junit.Test;
 
 @MediumTest
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..85e0e23 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -16,16 +16,21 @@
 
 package android.uirendering.cts.testclasses;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import org.junit.Test;
+import android.util.DisplayMetrics;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 /**
  * Tests of state query-able from canvas at draw time.
@@ -114,4 +119,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/ColorFilterAlphaTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
index cef2232..bbc50df 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
@@ -20,12 +20,13 @@
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.PorterDuffColorFilter;
-import android.test.suitebuilder.annotation.LargeTest;
+import android.graphics.PorterDuffXfermode;
+import android.support.test.filters.LargeTest;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
+
 import org.junit.Test;
 
 import java.util.List;
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..61b0f43
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.uirendering.cts.testclasses;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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;
+
+@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..a7587ba 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -16,18 +16,24 @@
 
 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;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.ExactComparer;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.R;
+
 import org.junit.Test;
 
 @MediumTest
@@ -138,6 +144,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/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index 73779d6..2a2ec51 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -18,18 +18,16 @@
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Typeface;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
 
-import android.uirendering.cts.R;
 import org.junit.Test;
 
 @MediumTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
new file mode 100644
index 0000000..37713de
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.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.uirendering.cts.testclasses;
+
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Shader;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import org.junit.Test;
+
+@MediumTest
+public class GradientTests extends ActivityTestBase {
+    @Test
+    public void testAlphaPreMultiplication() {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint paint = new Paint();
+
+                    // Add a red background to cover the activity's
+                    paint.setColor(Color.RED);
+                    canvas.drawRect(0.0f, 0.0f, width, height, paint);
+
+                    paint.setColor(Color.WHITE);
+                    paint.setShader(new LinearGradient(
+                            0.0f, 0.0f, 0.0f, 40.0f,
+                            0xffffffff, 0x00ffffff, Shader.TileMode.CLAMP)
+                    );
+                    canvas.drawRect(0.0f, 0.0f, width, height, paint);
+                }, true)
+                .runWithVerifier(new SamplePointVerifier(new Point[] {
+                        new Point(0, 0), new Point(0, 39)
+                }, new int[] {
+                        // Opaque white on red, result is white
+                        0xffffffff,
+                        // Transparent white on red, result is red
+                        // This means the source color (0x00ffffff) was
+                        // properly pre-multiplied
+                        0xffff0000
+                }, 10)); // Tolerance set to account for dithering and interpolation
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index 212e666..6f86ee7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -15,19 +15,18 @@
  */
 package android.uirendering.cts.testclasses;
 
-import android.graphics.Point;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.uirendering.cts.R;
-
 import android.graphics.Color;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
-import android.view.View;
+
 import org.junit.Test;
 
 @MediumTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index 4f99378..61d239b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -16,6 +16,8 @@
 
 package android.uirendering.cts.testclasses;
 
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
@@ -23,19 +25,25 @@
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.ColorCountVerifier;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
+import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewTreeObserver;
-import android.uirendering.cts.R;
 import android.widget.FrameLayout;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class LayerTests extends ActivityTestBase {
@@ -59,6 +67,34 @@
     }
 
     @Test
+    public void testLayerPaintSimpleAlphaWithHardware() {
+        @ColorInt
+        final int expectedColor = Color.rgb(255, 128, 128);
+        createTest()
+                .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+                    view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+
+                    // reduce alpha, so that overdraw will result in a different color
+                    view.setAlpha(0.5f);
+                })
+                .runWithVerifier(new ColorVerifier(expectedColor));
+    }
+
+    @Test
+    public void testLayerPaintSimpleAlphaWithSoftware() {
+        @ColorInt
+        final int expectedColor = Color.rgb(255, 128, 128);
+        createTest()
+                .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+                    view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+                    // reduce alpha, so that overdraw will result in a different color
+                    view.setAlpha(0.5f);
+                })
+                .runWithVerifier(new ColorVerifier(expectedColor));
+    }
+
+    @Test
     public void testLayerPaintColorFilter() {
         // Red, fully desaturated. Note that it's not 255/3 in each channel.
         // See ColorMatrix#setSaturation()
@@ -98,6 +134,66 @@
     }
 
     @Test
+    public void testLayerClear() {
+        ViewInitializer initializer = new ViewInitializer() {
+            ObjectAnimator mAnimator;
+            @Override
+            public void initializeView(View view) {
+                FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
+                root.setAlpha(0.5f);
+
+                View child = new View(view.getContext());
+                child.setBackgroundColor(Color.BLUE);
+                child.setTranslationX(10);
+                child.setTranslationY(10);
+                child.setLayoutParams(
+                        new FrameLayout.LayoutParams(50, 50));
+                child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                root.addView(child);
+
+                mAnimator = ObjectAnimator.ofInt(child, "translationY", 0, 20);
+                mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+                mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+                mAnimator.setDuration(200);
+                mAnimator.start();
+            }
+            @Override
+            public void teardownView() {
+                mAnimator.cancel();
+            }
+        };
+
+        createTest()
+                .addLayout(R.layout.frame_layout, initializer, true)
+                .runWithAnimationVerifier(new ColorCountVerifier(Color.WHITE, 90 * 90 - 50 * 50));
+    }
+
+    @Test
+    public void testAlphaLayerChild() {
+        ViewInitializer initializer = new ViewInitializer() {
+            @Override
+            public void initializeView(View view) {
+                FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
+                root.setAlpha(0.5f);
+
+                View child = new View(view.getContext());
+                child.setBackgroundColor(Color.BLUE);
+                child.setTranslationX(10);
+                child.setTranslationY(10);
+                child.setLayoutParams(
+                        new FrameLayout.LayoutParams(50, 50));
+                child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                root.addView(child);
+            }
+        };
+
+        createTest()
+                .addLayout(R.layout.frame_layout, initializer)
+                .runWithVerifier(new RectVerifier(Color.WHITE, 0xff8080ff,
+                        new Rect(10, 10, 60, 60)));
+    }
+
+    @Test
     public void testLayerInitialSizeZero() {
         createTest()
                 .addLayout(R.layout.frame_layout, view -> {
@@ -122,6 +218,7 @@
 
     @Test
     public void testLayerResizeZero() {
+        final CountDownLatch fence = new CountDownLatch(1);
         createTest()
                 .addLayout(R.layout.frame_layout, view -> {
                     FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
@@ -148,11 +245,15 @@
                                 root.getChildAt(0).requestLayout();
                                 root.getChildAt(1).getLayoutParams().height = 0;
                                 root.getChildAt(1).requestLayout();
+                                root.getViewTreeObserver().removeOnPreDrawListener(this);
+                                root.post(fence::countDown);
+                            } else {
+                                root.postInvalidate();
                             }
                             return true;
                         }
                     });
-                }, true)
+                }, true, fence)
                 .runWithVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */));
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index d69126c..c0323b6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -17,12 +17,12 @@
 
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
-import android.uirendering.cts.R;
-
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+
 import org.junit.Test;
 
 @MediumTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index a3145ef..6eaba8f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -16,26 +16,30 @@
 
 package android.uirendering.cts.testclasses;
 
+import static org.junit.Assert.assertNotNull;
+
 import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Typeface;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 import android.uirendering.cts.testinfrastructure.CanvasClientDrawable;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.uirendering.cts.util.WebViewReadyHelper;
 import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.WebView;
-import android.uirendering.cts.R;
+
 import org.junit.Test;
 
-import static org.junit.Assert.assertNotNull;
+import java.util.concurrent.CountDownLatch;
 
 @MediumTest
 public class PathClippingTests extends ActivityTestBase {
@@ -160,11 +164,22 @@
                 .runWithComparer(new MSSIMComparer(0.90));
     }
 
+    private ViewInitializer initBlueWebView(final CountDownLatch fence) {
+        return view -> {
+            WebView webview = (WebView)view.findViewById(R.id.webview);
+            assertNotNull(webview);
+            WebViewReadyHelper helper = new WebViewReadyHelper(webview, fence);
+            helper.loadData("<body style=\"background-color:blue\">");
+        };
+    }
+
     @Test
     public void testWebViewClipWithCircle() {
         if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
             return; // no WebView to run test on
         }
+        CountDownLatch hwFence = new CountDownLatch(1);
+        CountDownLatch swFence = new CountDownLatch(1);
         createTest()
                 // golden client - draw a simple non-AA circle
                 .addCanvasClient((canvas, width, height) -> {
@@ -174,11 +189,10 @@
                     canvas.drawOval(0, 0, width, height, paint);
                 }, false)
                 // verify against solid color webview, clipped to its parent oval
-                .addLayout(R.layout.circle_clipped_webview, (ViewInitializer) view -> {
-                    WebView webview = (WebView)view.findViewById(R.id.webview);
-                    assertNotNull(webview);
-                    webview.loadData("<body style=\"background-color:blue\">", null, null);
-                })
+                .addLayout(R.layout.circle_clipped_webview,
+                        initBlueWebView(hwFence), true, hwFence)
+                .addLayout(R.layout.circle_clipped_webview,
+                        initBlueWebView(swFence), false, swFence)
                 .runWithComparer(new MSSIMComparer(0.95));
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
new file mode 100644
index 0000000..5abe831
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
@@ -0,0 +1,38 @@
+package android.uirendering.cts.testclasses;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Typeface;
+import android.support.test.filters.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 PathTests extends ActivityTestBase {
+
+    private static final double REGULAR_THRESHOLD = 0.92;
+
+    @Test
+    public void testTextPathWithOffset() {
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint paint = new Paint();
+                    paint.setColor(Color.BLACK);
+                    paint.setAntiAlias(true);
+                    paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
+                    paint.setTextSize(26);
+                    Path path = new Path();
+                    String text = "Abc";
+                    paint.getTextPath(text, 0, text.length(), 0, 0, path);
+                    path.offset(0, 50);
+                    canvas.drawPath(path, paint);
+                })
+                .runWithVerifier(new GoldenImageVerifier(getActivity(),
+                        R.drawable.text_path_with_offset, new MSSIMComparer(REGULAR_THRESHOLD)));
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
index a2f3730..c1e10d3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -21,10 +21,11 @@
 import android.graphics.Paint;
 import android.graphics.Picture;
 import android.graphics.Rect;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+
 import org.junit.Test;
 
 @MediumTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
index 16a38e8..862d7d9 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
@@ -25,12 +25,12 @@
 import android.graphics.PorterDuff;
 import android.graphics.RadialGradient;
 import android.graphics.Shader;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
-import android.uirendering.cts.R;
+
 import org.junit.Test;
 
 @MediumTest
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index 6b9fb79..4e2cbac 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -17,13 +17,12 @@
 
 import android.graphics.Color;
 import android.graphics.Point;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
-
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.R;
-
+import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.util.CompareUtils;
+
 import org.junit.Test;
 
 @MediumTest
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..9aad23d
--- /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.support.test.filters.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/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 901792d..52b87cc 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -15,23 +15,30 @@
  */
 package android.uirendering.cts.testclasses;
 
+import com.android.compatibility.common.util.SynchronousPixelCopy;
+
 import android.animation.ObjectAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Point;
 import android.graphics.Rect;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.uirendering.cts.bitmapverifiers.*;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
-import android.uirendering.cts.testinfrastructure.DrawActivity;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 import android.view.Gravity;
+import android.view.PixelCopy;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
-import android.uirendering.cts.R;
 import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
+
+import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.concurrent.CountDownLatch;
@@ -100,8 +107,80 @@
                 mAnimator.cancel();
             }
         };
+        Screenshotter screenshotter = testOffset -> {
+            Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
+            return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
+        };
         createTest()
                 .addLayout(R.layout.frame_layout, initializer, true)
+                .withScreenshotter(screenshotter)
                 .runWithAnimationVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */));
     }
+
+    private static class SurfaceViewHelper implements ViewInitializer, Screenshotter, SurfaceHolder.Callback {
+        private final CanvasClient mCanvasClient;
+        private final CountDownLatch mFence = new CountDownLatch(1);
+        private SurfaceView mSurfaceView;
+
+        public SurfaceViewHelper(CanvasClient canvasClient) {
+            mCanvasClient = canvasClient;
+        }
+
+        @Override
+        public Bitmap takeScreenshot(Point point /* ignored */) {
+            SynchronousPixelCopy copy = new SynchronousPixelCopy();
+            Bitmap dest = Bitmap.createBitmap(
+                    TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
+            Rect srcRect = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT);
+            int copyResult = copy.request(mSurfaceView, srcRect, dest);
+            Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
+            return dest;
+        }
+
+        @Override
+        public void initializeView(View view) {
+            FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
+            mSurfaceView = new SurfaceView(view.getContext());
+            mSurfaceView.getHolder().addCallback(this);
+            root.addView(mSurfaceView, new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    FrameLayout.LayoutParams.MATCH_PARENT));
+        }
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            // TODO: Remove the post() which is a temporary workaround for b/32484713
+            mSurfaceView.post(() -> {
+                Canvas canvas = holder.lockHardwareCanvas();
+                mCanvasClient.draw(canvas, width, height);
+                holder.unlockCanvasAndPost(canvas);
+                mFence.countDown();
+            });
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+        }
+
+        public CountDownLatch getFence() {
+            return mFence;
+        }
+    }
+
+    @Test
+    public void testSurfaceHolderHardwareCanvas() {
+        SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
+            Assert.assertNotNull(canvas);
+            Assert.assertTrue(canvas.isHardwareAccelerated());
+            canvas.drawColor(Color.GREEN);
+        });
+        createTest()
+                .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
+                .withScreenshotter(helper)
+                .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */));
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index 3f51bbe..856fc17 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -22,17 +22,15 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Shader;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 import android.uirendering.cts.testinfrastructure.DisplayModifier;
 import android.uirendering.cts.testinfrastructure.ResourceModifier;
-import org.junit.Test;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import org.junit.Test;
 
 /**
  * Test cases of all combination of resource modifications.
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
new file mode 100644
index 0000000..9588eb2
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.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.uirendering.cts.testclasses;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.ColorInt;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.uirendering.cts.util.DrawCountDown;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.ViewGroup;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+
+@MediumTest
+public class TextureViewTests extends ActivityTestBase {
+
+    private static SurfaceTexture sRedTexture;
+
+    @BeforeClass
+    public static void setupClass() {
+        sRedTexture = createSurfaceTexture(true, Color.RED);
+    }
+
+    @AfterClass
+    public static void teardownClass() {
+        sRedTexture.release();
+        sRedTexture = null;
+    }
+
+    @Test
+    public void testConstructDetachedSingleBuffered() {
+        testConstructDetached(true);
+    }
+    @Test
+    public void testConstructDetachedMultiBuffered() {
+        testConstructDetached(false);
+    }
+
+    private void testConstructDetached(boolean singleBuffered) {
+        final SurfaceTexture texture = createSurfaceTexture(singleBuffered, Color.RED);
+        createTest()
+                .addLayout(R.layout.textureview, (ViewInitializer) view -> {
+                    TextureView textureview = (TextureView) view;
+                    textureview.setSurfaceTexture(texture);
+                }, true)
+                .runWithVerifier(new ColorVerifier(Color.RED));
+        Assert.assertTrue(texture.isReleased());
+    }
+
+    private static SurfaceTexture createSurfaceTexture(boolean singleBuffered,
+            @ColorInt int fillColor) {
+        SurfaceTexture texture = new SurfaceTexture(singleBuffered);
+        texture.setDefaultBufferSize(TEST_WIDTH, TEST_HEIGHT);
+        Surface producer = new Surface(texture);
+        Canvas canvas = producer.lockCanvas(null);
+        canvas.drawColor(fillColor);
+        producer.unlockCanvasAndPost(canvas);
+        return texture;
+    }
+
+    @Test
+    public void testReuseSurfaceTexture() {
+        final CountDownLatch fence = new CountDownLatch(1);
+        SurfaceTextureListener stlistener = mock(SurfaceTextureListener.class);
+        when(stlistener.onSurfaceTextureDestroyed(any(SurfaceTexture.class)))
+                .thenReturn(false);
+        createTest()
+                .addLayout(R.layout.textureview, (ViewInitializer) view -> {
+                    final TextureView textureview = (TextureView) view;
+                    final ViewGroup parent = (ViewGroup) textureview.getParent();
+                    textureview.setSurfaceTextureListener(stlistener);
+                    textureview.setSurfaceTexture(sRedTexture);
+                    DrawCountDown.countDownDraws(parent, 1, () -> {
+                        parent.removeView(textureview);
+                    });
+                    DrawCountDown.countDownDraws(parent, 2, () -> {
+                        parent.addView(textureview);
+                        textureview.setSurfaceTexture(sRedTexture);
+                        textureview.post(fence::countDown);
+                    });
+                }, true, fence)
+                .runWithVerifier(new ColorVerifier(Color.RED));
+        verify(stlistener, times(2)).onSurfaceTextureDestroyed(any(SurfaceTexture.class));
+    }
+
+    @Test
+    public void testLockCanvas() {
+        final CountDownLatch fence = new CountDownLatch(1);
+        createTest()
+                .addLayout(R.layout.textureview, (ViewInitializer) view -> {
+                    final TextureView textureview = (TextureView) view;
+                    textureview.setSurfaceTextureListener(new SurfaceTextureListener() {
+                        @Override
+                        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+                            textureview.post(fence::countDown);
+                        }
+                        @Override
+                        public void onSurfaceTextureSizeChanged(SurfaceTexture surface,
+                                int width, int height) {}
+                        @Override
+                        public void onSurfaceTextureAvailable(SurfaceTexture surface,
+                                int width, int height) {
+                            Canvas canvas = textureview.lockCanvas();
+                            canvas.drawColor(Color.BLUE);
+                            textureview.unlockCanvasAndPost(canvas);
+                        }
+                        @Override
+                        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+                            return true;
+                        }
+                    });
+                }, true, fence)
+                .runWithVerifier(new ColorVerifier(Color.BLUE));
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
new file mode 100644
index 0000000..2a64ac4
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
@@ -0,0 +1,46 @@
+/*
+ * 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.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.VectorDrawable;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapverifiers.RectVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+
+import org.junit.Test;
+
+@MediumTest
+public class VectorDrawableTests extends ActivityTestBase {
+    @Test
+    public void testScaleDown() {
+        VectorDrawable vd = (VectorDrawable) getActivity().getResources().getDrawable(
+                R.drawable.rectangle, null);
+        createTest()
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.scale(0.5f, 0.5f);
+                    vd.setBounds(new Rect(0, 0, 50, 50));
+                    vd.draw(canvas);
+                })
+                .runWithVerifier(
+                        new RectVerifier(Color.WHITE, Color.RED, new Rect(0, 0, 25, 25)));
+    }
+}
+
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..d74dcb7
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
@@ -0,0 +1,42 @@
+/*
+ * 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.support.test.filters.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/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index c8ca8c3..47f9f4d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -1,10 +1,13 @@
 package android.uirendering.cts.testclasses;
 
+import static org.junit.Assert.assertFalse;
+
 import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testclasses.view.UnclippedBlueView;
@@ -13,10 +16,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
-import android.uirendering.cts.R;
-import org.junit.Test;
 
-import static org.junit.Assert.assertFalse;
+import org.junit.Test;
 
 /**
  * This tests view clipping by modifying properties of blue_padded_layout, and validating
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
index 4f2e0ab..04e1dfd 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
@@ -22,10 +22,11 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
-import android.test.suitebuilder.annotation.LargeTest;
+import android.support.test.filters.LargeTest;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
+
 import org.junit.Test;
 
 import java.util.ArrayList;
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 ae915db..e340899 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -15,22 +15,25 @@
  */
 package android.uirendering.cts.testinfrastructure;
 
+import com.android.compatibility.common.util.SynchronousPixelCopy;
+
 import android.annotation.Nullable;
 import android.app.Instrumentation;
+import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Point;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-import android.support.test.rule.ActivityTestRule;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
 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.view.PixelCopy;
 
-import android.support.test.InstrumentationRegistry;
 import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.rules.TestName;
@@ -40,8 +43,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,44 +51,21 @@
 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;
+    private Screenshotter mScreenshotter;
 
-    @Rule
-    public ActivityTestRule<DrawActivity> mActivityRule = new ActivityTestRule<>(
-            DrawActivity.class);
+    private static DrawActivity sActivity;
 
     @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());
-        }
-    }
-
-    protected DrawActivity getActivity() {
-        return mActivityRule.getActivity();
-    }
+    private BitmapAsserter mBitmapAsserter = new BitmapAsserter(this.getClass().getSimpleName(),
+            name.getMethodName());
 
     protected String getName() {
         return name.getMethodName();
@@ -97,12 +75,30 @@
         return InstrumentationRegistry.getInstrumentation();
     }
 
+    protected DrawActivity getActivity() {
+        if (sActivity == null) {
+            Instrumentation instrumentation = getInstrumentation();
+            instrumentation.setInTouchMode(true);
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClass(instrumentation.getTargetContext(), DrawActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            sActivity = (DrawActivity) instrumentation.startActivitySync(intent);
+        }
+        return sActivity;
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        if (sActivity != null) {
+            // All tests are finished, tear down the activity
+            sActivity.allTestsFinished();
+            sActivity = null;
+        }
+    }
+
     @Before
     public void setUp() {
-        mDifferenceVisualizer = new PassFailVisualizer();
-        if (USE_RS) {
-            mRenderScript = RenderScript.create(getActivity().getApplicationContext());
-        }
+        mBitmapAsserter.setUp(getActivity());
     }
 
     @After
@@ -125,14 +121,24 @@
     }
 
     public Bitmap takeScreenshot(Point testOffset) {
-        Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
-        return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
+        if (mScreenshotter == null) {
+            SynchronousPixelCopy copy = new SynchronousPixelCopy();
+            Bitmap dest = Bitmap.createBitmap(
+                    TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
+            Rect srcRect = new Rect(testOffset.x, testOffset.y,
+                    testOffset.x + TEST_WIDTH, testOffset.y + TEST_HEIGHT);
+            int copyResult = copy.request(getActivity().getWindow(), srcRect, dest);
+            Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
+            return dest;
+        } else {
+            return mScreenshotter.takeScreenshot(testOffset);
+        }
     }
 
     protected Point runRenderSpec(TestCase testCase) {
         Point testOffset = getActivity().enqueueRenderSpecAndWait(
                 testCase.layoutID, testCase.canvasClient,
-                null, testCase.viewInitializer, testCase.useHardware);
+                testCase.viewInitializer, testCase.useHardware);
         testCase.wasTestRan = true;
         if (testCase.readyFence != null) {
             try {
@@ -152,59 +158,16 @@
         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();
+        mScreenshotter = null;
         return mTestCaseBuilder;
     }
 
+    public interface Screenshotter {
+        Bitmap takeScreenshot(Point point);
+    }
+
     /**
      * Defines a group of CanvasClients, XML layouts, and WebView html files for testing.
      */
@@ -228,8 +191,8 @@
 
             for (TestCase testCase : mTestCases) {
                 Bitmap testCaseBitmap = captureRenderSpec(testCase);
-                assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
-                        testCase.getDebugString());
+                mBitmapAsserter.assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
+                        getName(), testCase.getDebugString());
             }
         }
 
@@ -244,8 +207,10 @@
 
             for (TestCase testCase : mTestCases) {
                 Bitmap testCaseBitmap = captureRenderSpec(testCase);
-                assertBitmapIsVerified(testCaseBitmap, bitmapVerifier, testCase.getDebugString());
+                mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
+                        getName(), testCase.getDebugString());
             }
+            getActivity().reset();
         }
 
         private static final int VERIFY_ANIMATION_LOOP_COUNT = 20;
@@ -273,8 +238,8 @@
                         e.printStackTrace();
                     }
                     Bitmap testCaseBitmap = takeScreenshot(testOffset);
-                    assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
-                            testCase.getDebugString());
+                    mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
+                            getName(), testCase.getDebugString());
                 }
             }
         }
@@ -293,6 +258,12 @@
             });
         }
 
+        public TestCaseBuilder withScreenshotter(Screenshotter screenshotter) {
+            Assert.assertNull("Screenshotter is already set!", mScreenshotter);
+            mScreenshotter = screenshotter;
+            return this;
+        }
+
         public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer) {
             return addLayout(layoutId, viewInitializer, false)
                     .addLayout(layoutId, viewInitializer, true);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 42c2225..d55f6af 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -22,12 +22,11 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.uirendering.cts.R;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
-import android.webkit.WebView;
-
-import android.uirendering.cts.R;
 
 /**
  * A generic activity that uses a view specified by the user.
@@ -35,7 +34,6 @@
 public class DrawActivity extends Activity {
     private final static long TIME_OUT_MS = 10000;
     private final Point mLock = new Point();
-    public static final int MIN_NUMBER_OF_DRAWS = 20;
 
     private Handler mHandler;
     private View mView;
@@ -55,14 +53,12 @@
         return mOnTv;
     }
 
-    public Point enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient, String webViewUrl,
+    public Point enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient,
             @Nullable ViewInitializer viewInitializer, boolean useHardware) {
         ((RenderSpecHandler) mHandler).setViewInitializer(viewInitializer);
         int arg2 = (useHardware ? View.LAYER_TYPE_NONE : View.LAYER_TYPE_SOFTWARE);
         if (canvasClient != null) {
             mHandler.obtainMessage(RenderSpecHandler.CANVAS_MSG, 0, arg2, canvasClient).sendToTarget();
-        } else if (webViewUrl != null) {
-            mHandler.obtainMessage(RenderSpecHandler.WEB_VIEW_MSG, 0, arg2, webViewUrl).sendToTarget();
         } else {
             mHandler.obtainMessage(RenderSpecHandler.LAYOUT_MSG, layoutId, arg2).sendToTarget();
         }
@@ -79,12 +75,29 @@
         return point;
     }
 
+    public void reset() {
+        mHandler.sendEmptyMessage(RenderSpecHandler.RESET_MSG);
+        synchronized (mLock) {
+            try {
+                mLock.wait(TIME_OUT_MS);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
     private ViewInitializer mViewInitializer;
 
+    private void notifyOnDrawCompleted() {
+        DrawCounterListener onDrawListener = new DrawCounterListener();
+        mView.getViewTreeObserver().addOnDrawListener(onDrawListener);
+        mView.invalidate();
+    }
+
     private class RenderSpecHandler extends Handler {
+        public static final int RESET_MSG = 0;
         public static final int LAYOUT_MSG = 1;
         public static final int CANVAS_MSG = 2;
-        public static final int WEB_VIEW_MSG = 3;
 
 
         public void setViewInitializer(ViewInitializer viewInitializer) {
@@ -92,7 +105,14 @@
         }
 
         public void handleMessage(Message message) {
-            int drawCountDelay = 0;
+            if (message.what == RESET_MSG) {
+                ((ViewGroup)findViewById(android.R.id.content)).removeAllViews();
+                synchronized (mLock) {
+                    mLock.set(-1, -1);
+                    mLock.notify();
+                }
+                return;
+            }
             setContentView(R.layout.test_container);
             ViewStub stub = (ViewStub) findViewById(R.id.test_content_stub);
             mViewWrapper = findViewById(R.id.test_content_wrapper);
@@ -107,14 +127,6 @@
                     mView = stub.inflate();
                     ((CanvasClientView) mView).setCanvasClient((CanvasClient) (message.obj));
                 } break;
-
-                case WEB_VIEW_MSG: {
-                    stub.setLayoutResource(R.layout.test_content_webview);
-                    mView = stub.inflate();
-                    ((WebView) mView).loadUrl((String) message.obj);
-                    ((WebView) mView).setInitialScale(100);
-                    drawCountDelay = 10;
-                } break;
             }
 
             if (mView == null) {
@@ -129,11 +141,7 @@
             // can control layer type of View under test.
             mViewWrapper.setLayerType(message.arg2, null);
 
-            DrawCounterListener onDrawListener = new DrawCounterListener(drawCountDelay);
-
-            mView.getViewTreeObserver().addOnPreDrawListener(onDrawListener);
-
-            mView.postInvalidate();
+            notifyOnDrawCompleted();
         }
     }
 
@@ -145,27 +153,27 @@
         }
     }
 
-    private class DrawCounterListener implements ViewTreeObserver.OnPreDrawListener {
-        private int mCurrentDraws = 0;
-        private int mExtraDraws;
+    @Override
+    public void finish() {
+        // Ignore
+    }
 
-        public DrawCounterListener(int extraDraws) {
-            mExtraDraws = extraDraws;
-        }
+    /** Call this when all the tests that use this activity have completed.
+     * This will then clean up any internal state and finish the activity. */
+    public void allTestsFinished() {
+        super.finish();
+    }
 
+    private class DrawCounterListener implements ViewTreeObserver.OnDrawListener {
         @Override
-        public boolean onPreDraw() {
-            mCurrentDraws++;
-            if (mCurrentDraws < MIN_NUMBER_OF_DRAWS + mExtraDraws) {
-                mView.postInvalidate();
-            } else {
+        public void onDraw() {
+            mView.post(() -> {
+                mView.getViewTreeObserver().removeOnDrawListener(this);
                 synchronized (mLock) {
                     mLock.set(mViewWrapper.getLeft(), mViewWrapper.getTop());
                     mLock.notify();
                 }
-                mView.getViewTreeObserver().removeOnPreDrawListener(this);
-            }
-            return true;
+            });
         }
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java
new file mode 100644
index 0000000..53df12c
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/MaterialActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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.testinfrastructure;
+
+import android.app.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/uirendering/src/android/uirendering/cts/util/DrawCountDown.java b/tests/tests/uirendering/src/android/uirendering/cts/util/DrawCountDown.java
new file mode 100644
index 0000000..a268531
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/DrawCountDown.java
@@ -0,0 +1,36 @@
+package android.uirendering.cts.util;
+
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+
+public class DrawCountDown implements OnPreDrawListener {
+    private int mDrawCount;
+    private View mTargetView;
+    private Runnable mRunnable;
+
+    private DrawCountDown(View targetView, int countFrames, Runnable countReachedListener) {
+        mTargetView = targetView;
+        mDrawCount = countFrames;
+        mRunnable = countReachedListener;
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        if (mDrawCount <= 0) {
+            mTargetView.getViewTreeObserver().removeOnPreDrawListener(this);
+            mRunnable.run();
+        } else {
+            mDrawCount--;
+            mTargetView.postInvalidate();
+        }
+        return true;
+ 
+    }
+
+    public static void countDownDraws(View targetView, int countFrames,
+            Runnable onDrawCountReachedListener) {
+        DrawCountDown counter = new DrawCountDown(targetView, countFrames,
+                onDrawCountReachedListener);
+        targetView.getViewTreeObserver().addOnPreDrawListener(counter);
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/WebViewReadyHelper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/WebViewReadyHelper.java
new file mode 100644
index 0000000..22ee9ca
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/WebViewReadyHelper.java
@@ -0,0 +1,47 @@
+package android.uirendering.cts.util;
+
+import android.view.ViewTreeObserver.OnDrawListener;
+import android.webkit.WebView;
+import android.webkit.WebView.VisualStateCallback;
+import android.webkit.WebViewClient;
+
+import java.util.concurrent.CountDownLatch;
+
+public final class WebViewReadyHelper {
+    private final CountDownLatch mLatch;
+    private final WebView mWebView;
+
+    public WebViewReadyHelper(WebView webview, CountDownLatch latch) {
+        mWebView = webview;
+        mLatch = latch;
+        mWebView.setWebViewClient(mClient);
+    }
+
+    public void loadData(String data) {
+        mWebView.loadData(data, null, null);
+    }
+
+    private WebViewClient mClient = new WebViewClient() {
+        public void onPageFinished(WebView view, String url) {
+            mWebView.postVisualStateCallback(0, mVisualStateCallback);
+        }
+    };
+
+    private VisualStateCallback mVisualStateCallback = new VisualStateCallback() {
+        @Override
+        public void onComplete(long requestId) {
+            mWebView.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
+            mWebView.invalidate();
+        }
+    };
+
+    private OnDrawListener mOnDrawListener = new OnDrawListener() {
+        @Override
+        public void onDraw() {
+            mWebView.post(() -> {
+                mWebView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener);
+                mLatch.countDown();
+            });
+        }
+    };
+}
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/AndroidTest.xml b/tests/tests/util/AndroidTest.xml
index 9af993c..c5aa253 100644
--- a/tests/tests/util/AndroidTest.xml
+++ b/tests/tests/util/AndroidTest.xml
@@ -20,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.util.cts" />
+        <option name="runtime-hint" value="9m" />
     </test>
 </configuration>
diff --git a/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java b/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
index 17304b6..86cf1b1 100644
--- a/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
+++ b/tests/tests/util/src/android/util/cts/AndroidExceptionTest.java
@@ -16,14 +16,22 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AndroidException;
-import android.test.AndroidTestCase;
 
-public class AndroidExceptionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AndroidExceptionTest {
     private static final String NAME = "Test_AndroidException";
     private static final Exception CAUSE = new Exception();
 
+    @Test
     public void testAndroidException() {
         try {
             throw new AndroidException();
diff --git a/tests/tests/util/src/android/util/cts/AndroidRuntimeExceptionTest.java b/tests/tests/util/src/android/util/cts/AndroidRuntimeExceptionTest.java
index 8e8d84a..886269f 100644
--- a/tests/tests/util/src/android/util/cts/AndroidRuntimeExceptionTest.java
+++ b/tests/tests/util/src/android/util/cts/AndroidRuntimeExceptionTest.java
@@ -16,14 +16,22 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AndroidRuntimeException;
 
-public class AndroidRuntimeExceptionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AndroidRuntimeExceptionTest {
     private static final String NAME = "Test_AndroidRuntimeException";
     private static final Exception CAUSE = new Exception();
 
+    @Test
     public void testAndroidRuntimeException() {
         try {
             throw new AndroidRuntimeException();
diff --git a/tests/tests/util/src/android/util/cts/ArrayMapTest.java b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
index 130b354..ec17516 100644
--- a/tests/tests/util/src/android/util/cts/ArrayMapTest.java
+++ b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
@@ -16,13 +16,19 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.fail;
+
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.util.Log;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collection;
@@ -31,7 +37,9 @@
 import java.util.Map;
 import java.util.Set;
 
-public class ArrayMapTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArrayMapTest {
     static final boolean DEBUG = false;
 
     static final int OP_ADD = 1;
@@ -332,9 +340,10 @@
         }
     }
 
+    @Test
     public void testBasicArrayMap() {
-        HashMap<ControlledHash, Integer> hashMap = new HashMap<ControlledHash, Integer>();
-        ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<ControlledHash, Integer>();
+        HashMap<ControlledHash, Integer> hashMap = new HashMap<>();
+        ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<>();
         Bundle bundle = new Bundle();
 
         for (int i=0; i<OPS.length; i++) {
@@ -406,11 +415,9 @@
             dump(hashMap, arrayMap);
             fail(msg);
         }
-
-        //Log.e("test", "Test successful; printing final map.");
-        //dump(hashMap, arrayMap);
     }
 
+    @Test
     public void testCopyArrayMap() {
         // map copy constructor test
         ArrayMap newMap = new ArrayMap<Integer, String>();
@@ -428,10 +435,11 @@
         }
     }
 
+    @Test
     public void testEqualsArrayMap() {
-        ArrayMap<Integer, String> map1 = new ArrayMap<Integer, String>();
-        ArrayMap<Integer, String> map2 = new ArrayMap<Integer, String>();
-        HashMap<Integer, String> map3 = new HashMap<Integer, String>();
+        ArrayMap<Integer, String> map1 = new ArrayMap<>();
+        ArrayMap<Integer, String> map2 = new ArrayMap<>();
+        HashMap<Integer, String> map3 = new HashMap<>();
         if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
             fail("ArrayMap equals failure for empty maps " + map1 + ", " +
                     map2 + ", " + map3);
@@ -465,6 +473,7 @@
      * Test creating a malformed array map with duplicated keys and that we will catch this
      * when unparcelling.
      */
+    @Test
     public void testDuplicateKeys() throws NoSuchMethodException,
             InvocationTargetException, IllegalAccessException, NoSuchFieldException {
         ArrayMap<String, Object> map1 = new ArrayMap(2);
@@ -497,4 +506,33 @@
         dump(map1, map2);
         fail(msg);
     }
+
+    private static void checkEntrySetToArray(ArrayMap<?, ?> testMap) {
+        try {
+            testMap.entrySet().toArray();
+            fail();
+        } catch (UnsupportedOperationException expected) {}
+
+        try {
+            Map.Entry<?, ?>[] entries = new Map.Entry[20];
+            testMap.entrySet().toArray(entries);
+            fail();
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    // http://b/32294038, Test ArrayMap.entrySet().toArray()
+    @Test
+    public void testEntrySetArray() {
+        // Create
+        ArrayMap<Integer, String> testMap = new ArrayMap<>();
+
+        // Test empty
+        checkEntrySetToArray(testMap);
+
+        // Test non-empty
+        for (int i = 0; i < 10; ++i) {
+            testMap.put(i, String.valueOf(i));
+        }
+        checkEntrySetToArray(testMap);
+    }
 }
diff --git a/tests/tests/util/src/android/util/cts/ArraySetTest.java b/tests/tests/util/src/android/util/cts/ArraySetTest.java
index 112459c..554d209 100644
--- a/tests/tests/util/src/android/util/cts/ArraySetTest.java
+++ b/tests/tests/util/src/android/util/cts/ArraySetTest.java
@@ -16,19 +16,30 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+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.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.ArraySet;
 import android.util.Log;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.Set;
 
 // As is the case with ArraySet itself, ArraySetTest borrows heavily from ArrayMapTest.
 
-public class ArraySetTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArraySetTest {
     private static final String TAG = "ArraySetTest";
 
     private static final boolean DEBUG = false;
@@ -201,17 +212,18 @@
         }
     }
 
+    @Test
     public void testTest() {
         assertEquals("OPS and KEYS must be equal length", OPS.length, KEYS.length);
     }
 
+    @Test
     public void testBasicArraySet() {
-        HashSet<ControlledHash> hashSet = new HashSet<ControlledHash>();
-        ArraySet<ControlledHash> arraySet = new ArraySet<ControlledHash>();
+        HashSet<ControlledHash> hashSet = new HashSet<>();
+        ArraySet<ControlledHash> arraySet = new ArraySet<>();
 
         for (int i = 0; i < OPS.length; i++) {
             ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
-            String strKey = KEYS[i] < 0 ? null : Integer.toString(KEYS[i]);
             switch (OPS[i]) {
                 case OP_ADD:
                     if (DEBUG) Log.i(TAG, "Adding key: " + key);
@@ -270,6 +282,7 @@
         dump(hashSet, arraySet);
     }
 
+    @Test
     public void testCopyArraySet() {
         // set copy constructor test
         ArraySet newSet = new ArraySet<Integer>();
@@ -288,10 +301,11 @@
         }
     }
 
+    @Test
     public void testEqualsArrayMap() {
-        ArraySet<Integer> set1 = new ArraySet<Integer>();
-        ArraySet<Integer> set2 = new ArraySet<Integer>();
-        HashSet<Integer> set3 = new HashSet<Integer>();
+        ArraySet<Integer> set1 = new ArraySet<>();
+        ArraySet<Integer> set2 = new ArraySet<>();
+        HashSet<Integer> set3 = new HashSet<>();
         if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) {
             fail("ArraySet equals failure for empty sets " + set1 + ", " +
                     set2 + ", " + set3);
@@ -314,8 +328,9 @@
         }
     }
 
+    @Test
     public void testIsEmpty() {
-        ArraySet<Integer> set = new ArraySet<Integer>();
+        ArraySet<Integer> set = new ArraySet<>();
         assertEquals("New ArraySet should have size==0", 0, set.size());
         assertTrue("New ArraySet should be isEmptry", set.isEmpty());
 
@@ -328,8 +343,9 @@
         assertTrue("ArraySet should be isEmptry", set.isEmpty());
     }
 
+    @Test
     public void testRemoveAt() {
-        ArraySet<Integer> set = new ArraySet<Integer>();
+        ArraySet<Integer> set = new ArraySet<>();
 
         for (int i = 0; i < 10; ++i) {
             set.add(i * 10);
@@ -361,8 +377,9 @@
         }
     }
 
+    @Test
     public void testIndexOf() {
-        ArraySet<Integer> set = new ArraySet<Integer>();
+        ArraySet<Integer> set = new ArraySet<>();
 
         for (int i = 0; i < 10; ++i) {
             set.add(i * 10);
@@ -373,10 +390,11 @@
         }
     }
 
+    @Test
     public void testAddAll() {
-        ArraySet<Integer> arraySet = new ArraySet<Integer>();
-        ArraySet<Integer> testArraySet = new ArraySet<Integer>();
-        ArrayList<Integer> testArrayList = new ArrayList<Integer>();
+        ArraySet<Integer> arraySet = new ArraySet<>();
+        ArraySet<Integer> testArraySet = new ArraySet<>();
+        ArrayList<Integer> testArrayList = new ArrayList<>();
 
         for (int i = 0; i < 10; ++i) {
             testArraySet.add(i * 10);
@@ -401,10 +419,11 @@
         assertTrue("ArraySet.addAll(Container) failed", arraySet.containsAll(testArrayList));
     }
 
+    @Test
     public void testRemoveAll() {
-        ArraySet<Integer> arraySet = new ArraySet<Integer>();
-        ArraySet<Integer> arraySetToRemove = new ArraySet<Integer>();
-        ArrayList<Integer> arrayListToRemove = new ArrayList<Integer>();
+        ArraySet<Integer> arraySet = new ArraySet<>();
+        ArraySet<Integer> arraySetToRemove = new ArraySet<>();
+        ArrayList<Integer> arrayListToRemove = new ArrayList<>();
 
         for (int i = 0; i < 10; ++i) {
             arraySet.add(i * 10);
@@ -440,9 +459,10 @@
         assertEquals(0, arraySet.size());
     }
 
+    @Test
     public void testRetainAll() {
-        ArraySet<Integer> arraySet = new ArraySet<Integer>();
-        ArrayList<Integer> arrayListToRetain = new ArrayList<Integer>();
+        ArraySet<Integer> arraySet = new ArraySet<>();
+        ArrayList<Integer> arrayListToRetain = new ArrayList<>();
 
         for (int i = 0; i < 10; ++i) {
             arraySet.add(i * 10);
@@ -466,8 +486,9 @@
         assertEquals(2, arraySet.size());
     }
 
+    @Test
     public void testToArray() {
-        ArraySet<Integer> arraySet = new ArraySet<Integer>();
+        ArraySet<Integer> arraySet = new ArraySet<>();
         for (int i = 0; i < 10; ++i) {
             arraySet.add(i * 10);
         }
diff --git a/tests/tests/util/src/android/util/cts/DebugUtilsTest.java b/tests/tests/util/src/android/util/cts/DebugUtilsTest.java
index 203b4efd4..8d5f61b 100644
--- a/tests/tests/util/src/android/util/cts/DebugUtilsTest.java
+++ b/tests/tests/util/src/android/util/cts/DebugUtilsTest.java
@@ -15,10 +15,19 @@
  */
 package android.util.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DebugUtils;
 
-public class DebugUtilsTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DebugUtilsTest {
+    @Test
     public void testIsObjectSelected(){
         // note: because System.getenv("ANDROID_OBJECT_FILTER") always returns null, can't test
         // the case that the method isObjectSelected return true
diff --git a/tests/tests/util/src/android/util/cts/DisplayMetricsTest.java b/tests/tests/util/src/android/util/cts/DisplayMetricsTest.java
index fd8fa53..4966be0 100644
--- a/tests/tests/util/src/android/util/cts/DisplayMetricsTest.java
+++ b/tests/tests/util/src/android/util/cts/DisplayMetricsTest.java
@@ -15,15 +15,26 @@
  */
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.WindowManager;
 
-public class DisplayMetricsTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayMetricsTest {
     private Display initDisplay() {
-        WindowManager windowManager = (WindowManager) getContext()
+        WindowManager windowManager = (WindowManager) InstrumentationRegistry.getTargetContext()
                 .getSystemService(Context.WINDOW_SERVICE);
         assertNotNull(windowManager);
         Display display = windowManager.getDefaultDisplay();
@@ -31,6 +42,7 @@
         return display;
     }
 
+    @Test
     public void testDisplayMetricsOp() {
         DisplayMetrics outMetrics = new DisplayMetrics();
         outMetrics.setToDefaults();
diff --git a/tests/tests/util/src/android/util/cts/EventLogTest.java b/tests/tests/util/src/android/util/cts/EventLogTest.java
index 2065e32..0b784c4 100644
--- a/tests/tests/util/src/android/util/cts/EventLogTest.java
+++ b/tests/tests/util/src/android/util/cts/EventLogTest.java
@@ -16,22 +16,31 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Process;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.EventLog;
 import android.util.EventLog.Event;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
-import junit.framework.TestCase;
-
-public class EventLogTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EventLogTest {
     private static final int ANSWER_TAG = 42;
     private static final int PI_TAG = 314;
     private static final int E_TAG = 2718;
 
+    @Test
     public void testWriteEvent() throws Exception {
         long markerData = System.currentTimeMillis();
         EventLog.writeEvent(ANSWER_TAG, markerData);
@@ -57,6 +66,7 @@
         assertEquals("Test", arr[3]);
     }
 
+    @Test
     public void testWriteEventWithOversizeValue() throws Exception {
         StringBuilder longString = new StringBuilder();
         for (int i = 0; i < 1000; i++) longString.append("xyzzy");
@@ -118,11 +128,12 @@
         assertEquals(12345, arr6[arr6.length - 1]);
     }
 
+    @Test
     public void testWriteNullEvent() throws Exception {
         Long markerData = System.currentTimeMillis();
         EventLog.writeEvent(ANSWER_TAG, markerData);
         EventLog.writeEvent(ANSWER_TAG, (String) null);
-        EventLog.writeEvent(ANSWER_TAG, 12345, (String) null);
+        EventLog.writeEvent(ANSWER_TAG, 12345, null);
 
         List<EventLog.Event> events = getEventsAfterMarker(markerData, ANSWER_TAG);
         assertEquals(2, events.size());
@@ -134,6 +145,7 @@
         assertEquals("NULL", arr[1]);
     }
 
+    @Test
     public void testReadEvents() throws Exception {
         Long markerData = System.currentTimeMillis();
         EventLog.writeEvent(ANSWER_TAG, markerData);
@@ -149,24 +161,24 @@
 
         List<Event> events = getEventsAfterMarker(markerData, ANSWER_TAG, PI_TAG, E_TAG);
         assertEquals(3, events.size());
-        assertEvent(events.get(0), ANSWER_TAG, data0);
-        assertEvent(events.get(1), PI_TAG, data1);
-        assertEvent(events.get(2), E_TAG, data2);
+        verifyEvent(events.get(0), ANSWER_TAG, data0);
+        verifyEvent(events.get(1), PI_TAG, data1);
+        verifyEvent(events.get(2), E_TAG, data2);
 
         events = getEventsAfterMarker(markerData, ANSWER_TAG, E_TAG);
         assertEquals(2, events.size());
-        assertEvent(events.get(0), ANSWER_TAG, data0);
-        assertEvent(events.get(1), E_TAG, data2);
+        verifyEvent(events.get(0), ANSWER_TAG, data0);
+        verifyEvent(events.get(1), E_TAG, data2);
 
         events = getEventsAfterMarker(markerData, ANSWER_TAG);
         assertEquals(1, events.size());
-        assertEvent(events.get(0), ANSWER_TAG, data0);
+        verifyEvent(events.get(0), ANSWER_TAG, data0);
     }
 
     /** Return elements after and the event that has the marker data and matching tag. */
     private List<Event> getEventsAfterMarker(Object marker, int... tags)
             throws IOException, InterruptedException {
-        List<Event> events = new ArrayList<Event>();
+        List<Event> events = new ArrayList<>();
         // Give the message some time to show up in the log
         Thread.sleep(20);
         EventLog.readEvents(tags, events);
@@ -179,19 +191,19 @@
             }
         }
 
-        assertEventTimes(events);
+        verifyEventTimes(events);
 
         return events;
     }
 
-    private void assertEvent(Event event, int expectedTag, Object expectedData) {
+    private void verifyEvent(Event event, int expectedTag, Object expectedData) {
         assertEquals(Process.myPid(), event.getProcessId());
         assertEquals(Process.myTid(), event.getThreadId());
         assertEquals(expectedTag, event.getTag());
         assertEquals(expectedData, event.getData());
     }
 
-    private void assertEventTimes(List<Event> events) {
+    private void verifyEventTimes(List<Event> events) {
         for (int i = 0; i + 1 < events.size(); i++) {
             long time = events.get(i).getTimeNanos();
             long nextTime = events.get(i).getTimeNanos();
@@ -199,6 +211,7 @@
         }
     }
 
+    @Test
     public void testGetTagName() throws Exception {
         assertEquals("answer", EventLog.getTagName(ANSWER_TAG));
         assertEquals("pi", EventLog.getTagName(PI_TAG));
@@ -206,6 +219,7 @@
         assertEquals(null, EventLog.getTagName(999999999));
     }
 
+    @Test
     public void testGetTagCode() throws Exception {
         assertEquals(ANSWER_TAG, EventLog.getTagCode("answer"));
         assertEquals(PI_TAG, EventLog.getTagCode("pi"));
diff --git a/tests/tests/util/src/android/util/cts/HalfTest.java b/tests/tests/util/src/android/util/cts/HalfTest.java
new file mode 100644
index 0000000..493fcac
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/HalfTest.java
@@ -0,0 +1,448 @@
+/*
+ * 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.util.Half;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.util.Half.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HalfTest {
+    private static void assertShortEquals(short a, short b) {
+        assertEquals((long) (a & 0xffff), (long) (b & 0xffff));
+    }
+
+    private static void assertShortEquals(int a, short b) {
+        assertEquals((long) (a & 0xffff), (long) (b & 0xffff));
+    }
+
+    @Test
+    public void singleToHalf() {
+        // Zeroes, NaN and infinities
+        assertShortEquals(POSITIVE_ZERO, valueOf(0.0f));
+        assertShortEquals(NEGATIVE_ZERO, valueOf(-0.0f));
+        assertShortEquals(NaN, valueOf(Float.NaN));
+        assertShortEquals(POSITIVE_INFINITY, valueOf(Float.POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, valueOf(Float.NEGATIVE_INFINITY));
+        // Known values
+        assertShortEquals(0x3c01, valueOf(1.0009765625f));
+        assertShortEquals(0xc000, valueOf(-2.0f));
+        assertShortEquals(0x0400, valueOf(6.10352e-5f));
+        assertShortEquals(0x7bff, valueOf(65504.0f));
+        assertShortEquals(0x3555, valueOf(1.0f / 3.0f));
+        // Denormals
+        assertShortEquals(0x03ff, valueOf(6.09756e-5f));
+        assertShortEquals(MIN_VALUE, valueOf(5.96046e-8f));
+        assertShortEquals(0x83ff, valueOf(-6.09756e-5f));
+        assertShortEquals(0x8001, valueOf(-5.96046e-8f));
+        // Denormals (flushed to +/-0)
+        assertShortEquals(POSITIVE_ZERO, valueOf(5.96046e-9f));
+        assertShortEquals(NEGATIVE_ZERO, valueOf(-5.96046e-9f));
+    }
+
+    @Test
+    public void halfToSingle() {
+        // Zeroes, NaN and infinities
+        assertEquals(0.0f, toFloat(valueOf(0.0f)), 1e-6f);
+        assertEquals(-0.0f, toFloat(valueOf(-0.0f)), 1e-6f);
+        assertEquals(Float.NaN, toFloat(valueOf(Float.NaN)), 1e-6f);
+        assertEquals(Float.POSITIVE_INFINITY, toFloat(valueOf(Float.POSITIVE_INFINITY)), 1e-6f);
+        assertEquals(Float.NEGATIVE_INFINITY, toFloat(valueOf(Float.NEGATIVE_INFINITY)), 1e-6f);
+        // Known values
+        assertEquals(1.0009765625f, toFloat(valueOf(1.0009765625f)), 1e-6f);
+        assertEquals(-2.0f, toFloat(valueOf(-2.0f)), 1e-6f);
+        assertEquals(6.1035156e-5f, toFloat(valueOf(6.10352e-5f)), 1e-6f); // Inexact
+        assertEquals(65504.0f, toFloat(valueOf(65504.0f)), 1e-6f);
+        assertEquals(0.33325195f, toFloat(valueOf(1.0f / 3.0f)), 1e-6f); // Inexact
+        // Denormals (flushed to +/-0)
+        assertEquals(6.097555e-5f, toFloat(valueOf(6.09756e-5f)), 1e-6f);
+        assertEquals(5.9604645e-8f, toFloat(valueOf(5.96046e-8f)), 1e-9f);
+        assertEquals(-6.097555e-5f, toFloat(valueOf(-6.09756e-5f)), 1e-6f);
+        assertEquals(-5.9604645e-8f, toFloat(valueOf(-5.96046e-8f)), 1e-9f);
+    }
+
+    @Test
+    public void hexString() {
+        assertEquals("NaN", toHexString(NaN));
+        assertEquals("Infinity", toHexString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", toHexString(NEGATIVE_INFINITY));
+        assertEquals("0x0.0p0", toHexString(POSITIVE_ZERO));
+        assertEquals("-0x0.0p0", toHexString(NEGATIVE_ZERO));
+        assertEquals("0x1.0p0", toHexString(valueOf(1.0f)));
+        assertEquals("-0x1.0p0", toHexString(valueOf(-1.0f)));
+        assertEquals("0x1.0p1", toHexString(valueOf(2.0f)));
+        assertEquals("0x1.0p8", toHexString(valueOf(256.0f)));
+        assertEquals("0x1.0p-1", toHexString(valueOf(0.5f)));
+        assertEquals("0x1.0p-2", toHexString(valueOf(0.25f)));
+        assertEquals("0x1.3ffp15", toHexString(MAX_VALUE));
+        assertEquals("0x0.1p-14", toHexString(MIN_VALUE));
+        assertEquals("0x1.0p-14", toHexString(MIN_NORMAL));
+        assertEquals("-0x1.3ffp15", toHexString(LOWEST_VALUE));
+    }
+
+    @Test
+    public void string() {
+        assertEquals("NaN", Half.toString(NaN));
+        assertEquals("Infinity", Half.toString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", Half.toString(NEGATIVE_INFINITY));
+        assertEquals("0.0", Half.toString(POSITIVE_ZERO));
+        assertEquals("-0.0", Half.toString(NEGATIVE_ZERO));
+        assertEquals("1.0", Half.toString(valueOf(1.0f)));
+        assertEquals("-1.0", Half.toString(valueOf(-1.0f)));
+        assertEquals("2.0", Half.toString(valueOf(2.0f)));
+        assertEquals("256.0", Half.toString(valueOf(256.0f)));
+        assertEquals("0.5", Half.toString(valueOf(0.5f)));
+        assertEquals("0.25", Half.toString(valueOf(0.25f)));
+        assertEquals("65504.0", Half.toString(MAX_VALUE));
+        assertEquals("5.9604645E-8", Half.toString(MIN_VALUE));
+        assertEquals("6.1035156E-5", Half.toString(MIN_NORMAL));
+        assertEquals("-65504.0", Half.toString(LOWEST_VALUE));
+    }
+
+    @Test
+    public void exponent() {
+        assertEquals(16, getExponent(POSITIVE_INFINITY));
+        assertEquals(16, getExponent(NEGATIVE_INFINITY));
+        assertEquals(16, getExponent(NaN));
+        assertEquals(-15, getExponent(POSITIVE_ZERO));
+        assertEquals(-15, getExponent(NEGATIVE_ZERO));
+        assertEquals(0, getExponent(valueOf(1.0f)));
+        assertEquals(-4, getExponent(valueOf(0.1f)));
+        assertEquals(-10, getExponent(valueOf(0.001f)));
+        assertEquals(7, getExponent(valueOf(128.8f)));
+    }
+
+    @Test
+    public void significand() {
+        assertEquals(0, getSignificand(POSITIVE_INFINITY));
+        assertEquals(0, getSignificand(NEGATIVE_INFINITY));
+        assertEquals(512, getSignificand(NaN));
+        assertEquals(0, getSignificand(POSITIVE_ZERO));
+        assertEquals(0, getSignificand(NEGATIVE_ZERO));
+        assertEquals(614, getSignificand(valueOf(0.1f)));
+        assertEquals(25, getSignificand(valueOf(0.001f)));
+        assertEquals(6, getSignificand(valueOf(128.8f)));
+    }
+
+    @Test
+    public void sign() {
+        assertEquals(1, getSign(POSITIVE_INFINITY));
+        assertEquals(-1, getSign(NEGATIVE_INFINITY));
+        assertEquals(1, getSign(POSITIVE_ZERO));
+        assertEquals(-1, getSign(NEGATIVE_ZERO));
+        assertEquals(1, getSign(NaN));
+        assertEquals(1, getSign(valueOf(12.4f)));
+        assertEquals(-1, getSign(valueOf(-12.4f)));
+    }
+
+    @Test
+    public void isInfinite() {
+        assertTrue(Half.isInfinite(POSITIVE_INFINITY));
+        assertTrue(Half.isInfinite(NEGATIVE_INFINITY));
+        assertFalse(Half.isInfinite(POSITIVE_ZERO));
+        assertFalse(Half.isInfinite(NEGATIVE_ZERO));
+        assertFalse(Half.isInfinite(NaN));
+        assertFalse(Half.isInfinite(MAX_VALUE));
+        assertFalse(Half.isInfinite(LOWEST_VALUE));
+        assertFalse(Half.isInfinite(valueOf(-128.3f)));
+        assertFalse(Half.isInfinite(valueOf(128.3f)));
+    }
+
+    @Test
+    public void isNaN() {
+        assertFalse(Half.isNaN(POSITIVE_INFINITY));
+        assertFalse(Half.isNaN(NEGATIVE_INFINITY));
+        assertFalse(Half.isNaN(POSITIVE_ZERO));
+        assertFalse(Half.isNaN(NEGATIVE_ZERO));
+        assertTrue(Half.isNaN(NaN));
+        assertTrue(Half.isNaN((short) 0x7c01));
+        assertTrue(Half.isNaN((short) 0x7c18));
+        assertTrue(Half.isNaN((short) 0xfc01));
+        assertTrue(Half.isNaN((short) 0xfc98));
+        assertFalse(Half.isNaN(MAX_VALUE));
+        assertFalse(Half.isNaN(LOWEST_VALUE));
+        assertFalse(Half.isNaN(valueOf(-128.3f)));
+        assertFalse(Half.isNaN(valueOf(128.3f)));
+    }
+
+    @Test
+    public void isNormalized() {
+        assertFalse(Half.isNormalized(POSITIVE_INFINITY));
+        assertFalse(Half.isNormalized(NEGATIVE_INFINITY));
+        assertFalse(Half.isNormalized(POSITIVE_ZERO));
+        assertFalse(Half.isNormalized(NEGATIVE_ZERO));
+        assertFalse(Half.isNormalized(NaN));
+        assertTrue(Half.isNormalized(MAX_VALUE));
+        assertTrue(Half.isNormalized(MIN_NORMAL));
+        assertTrue(Half.isNormalized(LOWEST_VALUE));
+        assertTrue(Half.isNormalized(valueOf(-128.3f)));
+        assertTrue(Half.isNormalized(valueOf(128.3f)));
+        assertTrue(Half.isNormalized(valueOf(0.3456f)));
+        assertFalse(Half.isNormalized(MIN_VALUE));
+        assertFalse(Half.isNormalized((short) 0x3ff));
+        assertFalse(Half.isNormalized((short) 0x200));
+        assertFalse(Half.isNormalized((short) 0x100));
+    }
+
+    @Test
+    public void abs() {
+        assertShortEquals(POSITIVE_INFINITY, Half.abs(POSITIVE_INFINITY));
+        assertShortEquals(POSITIVE_INFINITY, Half.abs(NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.abs(POSITIVE_ZERO));
+        assertShortEquals(POSITIVE_ZERO, Half.abs(NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.abs(NaN));
+        assertShortEquals(MAX_VALUE, Half.abs(LOWEST_VALUE));
+        assertShortEquals(valueOf(12.12345f), Half.abs(valueOf(-12.12345f)));
+        assertShortEquals(valueOf(12.12345f), Half.abs(valueOf( 12.12345f)));
+    }
+
+    @Test
+    public void ceil() {
+        assertShortEquals(POSITIVE_INFINITY, Half.ceil(POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, Half.ceil(NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.ceil(POSITIVE_ZERO));
+        assertShortEquals(NEGATIVE_ZERO, Half.ceil(NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.ceil(NaN));
+        assertShortEquals(LOWEST_VALUE, Half.ceil(LOWEST_VALUE));
+        assertEquals(1.0f, toFloat(Half.ceil(MIN_NORMAL)), 1e-6f);
+        assertEquals(1.0f, toFloat(Half.ceil((short) 0x3ff)), 1e-6f);
+        assertEquals(1.0f, toFloat(Half.ceil(valueOf(0.2f))), 1e-6f);
+        assertShortEquals(NEGATIVE_ZERO, Half.ceil(valueOf(-0.2f)));
+        assertEquals(1.0f, toFloat(Half.ceil(valueOf(0.7f))), 1e-6f);
+        assertShortEquals(NEGATIVE_ZERO, Half.ceil(valueOf(-0.7f)));
+        assertEquals(125.0f, toFloat(Half.ceil(valueOf(124.7f))), 1e-6f);
+        assertEquals(-124.0f, toFloat(Half.ceil(valueOf(-124.7f))), 1e-6f);
+        assertEquals(125.0f, toFloat(Half.ceil(valueOf(124.2f))), 1e-6f);
+        assertEquals(-124.0f, toFloat(Half.ceil(valueOf(-124.2f))), 1e-6f);
+    }
+
+    @Test
+    public void copySign() {
+        assertShortEquals(valueOf(7.5f), Half.copySign(valueOf(-7.5f), POSITIVE_INFINITY));
+        assertShortEquals(valueOf(7.5f), Half.copySign(valueOf(-7.5f), POSITIVE_ZERO));
+        assertShortEquals(valueOf(-7.5f), Half.copySign(valueOf(7.5f), NEGATIVE_INFINITY));
+        assertShortEquals(valueOf(-7.5f), Half.copySign(valueOf(7.5f), NEGATIVE_ZERO));
+        assertShortEquals(valueOf(7.5f), Half.copySign(valueOf(7.5f), NaN));
+        assertShortEquals(valueOf(7.5f), Half.copySign(valueOf(7.5f), valueOf(12.4f)));
+        assertShortEquals(valueOf(-7.5f), Half.copySign(valueOf(7.5f), valueOf(-12.4f)));
+    }
+
+    @Test
+    public void equals() {
+        assertTrue(Half.equals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.equals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.equals(POSITIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(Half.equals(NEGATIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(Half.equals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(Half.equals(NaN, valueOf(12.4f)));
+        assertFalse(Half.equals(valueOf(12.4f), NaN));
+        assertFalse(Half.equals(NaN, NaN));
+        assertTrue(Half.equals(valueOf(12.4f), valueOf(12.4f)));
+        assertTrue(Half.equals(valueOf(-12.4f), valueOf(-12.4f)));
+        assertFalse(Half.equals(valueOf(12.4f), valueOf(0.7f)));
+    }
+
+    @Test
+    public void floor() {
+        assertShortEquals(POSITIVE_INFINITY, Half.floor(POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, Half.floor(NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.floor(POSITIVE_ZERO));
+        assertShortEquals(NEGATIVE_ZERO, Half.floor(NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.floor(NaN));
+        assertShortEquals(LOWEST_VALUE, Half.floor(LOWEST_VALUE));
+        assertShortEquals(POSITIVE_ZERO, Half.floor(MIN_NORMAL));
+        assertShortEquals(POSITIVE_ZERO, Half.floor((short) 0x3ff));
+        assertShortEquals(POSITIVE_ZERO, Half.floor(valueOf(0.2f)));
+        assertEquals(-1.0f, toFloat(Half.floor(valueOf(-0.2f))), 1e-6f);
+        assertEquals(-1.0f, toFloat(Half.floor(valueOf(-0.7f))), 1e-6f);
+        assertShortEquals(POSITIVE_ZERO, Half.floor(valueOf(0.7f)));
+        assertEquals(124.0f, toFloat(Half.floor(valueOf(124.7f))), 1e-6f);
+        assertEquals(-125.0f, toFloat(Half.floor(valueOf(-124.7f))), 1e-6f);
+        assertEquals(124.0f, toFloat(Half.floor(valueOf(124.2f))), 1e-6f);
+        assertEquals(-125.0f, toFloat(Half.floor(valueOf(-124.2f))), 1e-6f);
+    }
+
+    @Test
+    public void round() {
+        assertShortEquals(POSITIVE_INFINITY, Half.round(POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, Half.round(NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.round(POSITIVE_ZERO));
+        assertShortEquals(NEGATIVE_ZERO, Half.round(NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.round(NaN));
+        assertShortEquals(LOWEST_VALUE, Half.round(LOWEST_VALUE));
+        assertShortEquals(POSITIVE_ZERO, Half.round(MIN_VALUE));
+        assertShortEquals(POSITIVE_ZERO, Half.round((short) 0x200));
+        assertShortEquals(POSITIVE_ZERO, Half.round((short) 0x3ff));
+        assertShortEquals(POSITIVE_ZERO, Half.round(valueOf(0.2f)));
+        assertShortEquals(NEGATIVE_ZERO, Half.round(valueOf(-0.2f)));
+        assertEquals(1.0f, toFloat(Half.round(valueOf(0.7f))), 1e-6f);
+        assertEquals(-1.0f, toFloat(Half.round(valueOf(-0.7f))), 1e-6f);
+        assertEquals(1.0f, toFloat(Half.round(valueOf(0.5f))), 1e-6f);
+        assertEquals(-1.0f, toFloat(Half.round(valueOf(-0.5f))), 1e-6f);
+        assertEquals(125.0f, toFloat(Half.round(valueOf(124.7f))), 1e-6f);
+        assertEquals(-125.0f, toFloat(Half.round(valueOf(-124.7f))), 1e-6f);
+        assertEquals(124.0f, toFloat(Half.round(valueOf(124.2f))), 1e-6f);
+        assertEquals(-124.0f, toFloat(Half.round(valueOf(-124.2f))), 1e-6f);
+    }
+
+    @Test
+    public void trunc() {
+        assertShortEquals(POSITIVE_INFINITY, Half.trunc(POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, Half.trunc(NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.trunc(POSITIVE_ZERO));
+        assertShortEquals(NEGATIVE_ZERO, Half.trunc(NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.trunc(NaN));
+        assertShortEquals(LOWEST_VALUE, Half.trunc(LOWEST_VALUE));
+        assertShortEquals(POSITIVE_ZERO, Half.trunc(valueOf(0.2f)));
+        assertShortEquals(NEGATIVE_ZERO, Half.trunc(valueOf(-0.2f)));
+        assertEquals(0.0f, toFloat(Half.trunc(valueOf(0.7f))), 1e-6f);
+        assertEquals(-0.0f, toFloat(Half.trunc(valueOf(-0.7f))), 1e-6f);
+        assertEquals(124.0f, toFloat(Half.trunc(valueOf(124.7f))), 1e-6f);
+        assertEquals(-124.0f, toFloat(Half.trunc(valueOf(-124.7f))), 1e-6f);
+        assertEquals(124.0f, toFloat(Half.trunc(valueOf(124.2f))), 1e-6f);
+        assertEquals(-124.0f, toFloat(Half.trunc(valueOf(-124.2f))), 1e-6f);
+    }
+
+    @Test
+    public void less() {
+        assertTrue(Half.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.less(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(Half.less(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(Half.less(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(Half.less(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertFalse(Half.less(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(Half.less(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(Half.less(NaN, valueOf(12.3f)));
+        assertFalse(Half.less(valueOf(12.3f), NaN));
+        assertTrue(Half.less(MIN_VALUE, MIN_NORMAL));
+        assertFalse(Half.less(MIN_NORMAL, MIN_VALUE));
+        assertTrue(Half.less(valueOf(12.3f), valueOf(12.4f)));
+        assertFalse(Half.less(valueOf(12.4f), valueOf(12.3f)));
+        assertFalse(Half.less(valueOf(-12.3f), valueOf(-12.4f)));
+        assertTrue(Half.less(valueOf(-12.4f), valueOf(-12.3f)));
+        assertTrue(Half.less(MIN_VALUE, (short) 0x3ff));
+    }
+
+    @Test
+    public void lessEquals() {
+        assertTrue(Half.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.lessEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(Half.lessEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(Half.lessEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(Half.lessEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(Half.lessEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(Half.lessEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(Half.lessEquals(NaN, valueOf(12.3f)));
+        assertFalse(Half.lessEquals(valueOf(12.3f), NaN));
+        assertTrue(Half.lessEquals(MIN_VALUE, MIN_NORMAL));
+        assertFalse(Half.lessEquals(MIN_NORMAL, MIN_VALUE));
+        assertTrue(Half.lessEquals(valueOf(12.3f), valueOf(12.4f)));
+        assertFalse(Half.lessEquals(valueOf(12.4f), valueOf(12.3f)));
+        assertFalse(Half.lessEquals(valueOf(-12.3f), valueOf(-12.4f)));
+        assertTrue(Half.lessEquals(valueOf(-12.4f), valueOf(-12.3f)));
+        assertTrue(Half.less(MIN_VALUE, (short) 0x3ff));
+        assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.lessEquals(valueOf(12.12356f), valueOf(12.12356f)));
+        assertTrue(Half.lessEquals(valueOf(-12.12356f), valueOf(-12.12356f)));
+    }
+
+    @Test
+    public void greater() {
+        assertTrue(Half.greater(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.greater(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(Half.greater(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(Half.greater(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(Half.greater(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertFalse(Half.greater(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(Half.greater(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(Half.greater(valueOf(12.3f), NaN));
+        assertFalse(Half.greater(NaN, valueOf(12.3f)));
+        assertTrue(Half.greater(MIN_NORMAL, MIN_VALUE));
+        assertFalse(Half.greater(MIN_VALUE, MIN_NORMAL));
+        assertTrue(Half.greater(valueOf(12.4f), valueOf(12.3f)));
+        assertFalse(Half.greater(valueOf(12.3f), valueOf(12.4f)));
+        assertFalse(Half.greater(valueOf(-12.4f), valueOf(-12.3f)));
+        assertTrue(Half.greater(valueOf(-12.3f), valueOf(-12.4f)));
+        assertTrue(Half.greater((short) 0x3ff, MIN_VALUE));
+    }
+
+    @Test
+    public void greaterEquals() {
+        assertTrue(Half.greaterEquals(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.greaterEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(Half.greaterEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(Half.greaterEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(Half.greaterEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(Half.greaterEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(Half.greaterEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(Half.greaterEquals(valueOf(12.3f), NaN));
+        assertFalse(Half.greaterEquals(NaN, valueOf(12.3f)));
+        assertTrue(Half.greaterEquals(MIN_NORMAL, MIN_VALUE));
+        assertFalse(Half.greaterEquals(MIN_VALUE, MIN_NORMAL));
+        assertTrue(Half.greaterEquals(valueOf(12.4f), valueOf(12.3f)));
+        assertFalse(Half.greaterEquals(valueOf(12.3f), valueOf(12.4f)));
+        assertFalse(Half.greaterEquals(valueOf(-12.4f), valueOf(-12.3f)));
+        assertTrue(Half.greaterEquals(valueOf(-12.3f), valueOf(-12.4f)));
+        assertTrue(Half.greater((short) 0x3ff, MIN_VALUE));
+        assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(Half.lessEquals(valueOf(12.12356f), valueOf(12.12356f)));
+        assertTrue(Half.lessEquals(valueOf(-12.12356f), valueOf(-12.12356f)));
+    }
+
+    @Test
+    public void min() {
+        assertShortEquals(NEGATIVE_INFINITY, Half.min(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertShortEquals(NEGATIVE_ZERO, Half.min(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.min(NaN, LOWEST_VALUE));
+        assertShortEquals(NaN, Half.min(LOWEST_VALUE, NaN));
+        assertShortEquals(NEGATIVE_INFINITY, Half.min(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertShortEquals(MAX_VALUE, Half.min(POSITIVE_INFINITY, MAX_VALUE));
+        assertShortEquals(MIN_VALUE, Half.min(MIN_VALUE, MIN_NORMAL));
+        assertShortEquals(POSITIVE_ZERO, Half.min(MIN_VALUE, POSITIVE_ZERO));
+        assertShortEquals(POSITIVE_ZERO, Half.min(MIN_NORMAL, POSITIVE_ZERO));
+        assertShortEquals(valueOf(-3.456f), Half.min(valueOf(-3.456f), valueOf(-3.453f)));
+        assertShortEquals(valueOf(3.453f), Half.min(valueOf(3.456f), valueOf(3.453f)));
+    }
+
+    @Test
+    public void max() {
+        assertShortEquals(POSITIVE_INFINITY, Half.max(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertShortEquals(POSITIVE_ZERO, Half.max(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertShortEquals(NaN, Half.max(NaN, MAX_VALUE));
+        assertShortEquals(NaN, Half.max(MAX_VALUE, NaN));
+        assertShortEquals(LOWEST_VALUE, Half.max(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertShortEquals(POSITIVE_INFINITY, Half.max(POSITIVE_INFINITY, MAX_VALUE));
+        assertShortEquals(MIN_NORMAL, Half.max(MIN_VALUE, MIN_NORMAL));
+        assertShortEquals(MIN_VALUE, Half.max(MIN_VALUE, POSITIVE_ZERO));
+        assertShortEquals(MIN_NORMAL, Half.max(MIN_NORMAL, POSITIVE_ZERO));
+        assertShortEquals(valueOf(-3.453f), Half.max(valueOf(-3.456f), valueOf(-3.453f)));
+        assertShortEquals(valueOf(3.456f), Half.max(valueOf(3.456f), valueOf(3.453f)));
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/JsonReaderTest.java b/tests/tests/util/src/android/util/cts/JsonReaderTest.java
index 5a9b336..9ac3fc3 100644
--- a/tests/tests/util/src/android/util/cts/JsonReaderTest.java
+++ b/tests/tests/util/src/android/util/cts/JsonReaderTest.java
@@ -16,19 +16,31 @@
 
 package android.util.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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.MalformedJsonException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.Arrays;
-import junit.framework.TestCase;
 
-import android.util.MalformedJsonException;
-import android.util.JsonReader;
-import android.util.JsonToken;
-
-public final class JsonReaderTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class JsonReaderTest {
 
     private static final int READER_BUFFER_SIZE = 1024;
 
+    @Test
     public void testReadArray() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true, true]"));
         reader.beginArray();
@@ -38,6 +50,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testReadEmptyArray() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[]"));
         reader.beginArray();
@@ -46,6 +59,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testReadObject() throws IOException {
         JsonReader reader = new JsonReader(new StringReader(
                 "{\"a\": \"android\", \"b\": \"banana\"}"));
@@ -58,6 +72,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testReadEmptyObject() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{}"));
         reader.beginObject();
@@ -66,6 +81,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testSkipObject() throws IOException {
         JsonReader reader = new JsonReader(new StringReader(
                 "{\"a\": { \"c\": [], \"d\": [true, true, {}] }, \"b\": \"banana\"}"));
@@ -78,26 +94,23 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test(expected=IllegalStateException.class)
     public void testSkipBeforeEndOfObject() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{}"));
         reader.beginObject();
-        try {
-            reader.skipValue();
-            fail("Should not be possible to skip without elements.");
-        } catch (IllegalStateException expected) {
-        }
+        // Should not be possible to skip without elements
+        reader.skipValue();
     }
 
+    @Test(expected=IllegalStateException.class)
     public void testSkipBeforeEndOfArray() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[]"));
         reader.beginArray();
-        try {
-            reader.skipValue();
-            fail("Should not be possible to skip without elements.");
-        } catch (IllegalStateException expected) {
-        }
+        // Should not be possible to skip without elements
+        reader.skipValue();
     }
 
+    @Test
     public void testSkipAfterEndOfDocument() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{}"));
         reader.beginObject();
@@ -110,6 +123,7 @@
         }
     }
 
+    @Test
     public void testHelloWorld() throws IOException {
         String json = "{\n" +
                 "   \"hello\": true,\n" +
@@ -127,32 +141,27 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test(expected=NullPointerException.class)
     public void testNulls() {
-        try {
-            new JsonReader(null);
-            fail();
-        } catch (NullPointerException expected) {
-        }
+        new JsonReader(null);
     }
 
-    public void testEmptyString() throws IOException {
-        try {
-            new JsonReader(new StringReader("")).beginArray();
-        } catch (IOException expected) {
-        }
-        try {
-            new JsonReader(new StringReader("")).beginObject();
-        } catch (IOException expected) {
-        }
+    @Test(expected=IOException.class)
+    public void testEmptyString1() throws IOException {
+        new JsonReader(new StringReader("")).beginArray();
     }
 
+    @Test(expected=IOException.class)
+    public void testEmptyString2() throws IOException {
+        new JsonReader(new StringReader("")).beginObject();
+    }
+
+    @Test(expected=IOException.class)
     public void testNoTopLevelObject() throws IOException {
-        try {
-            new JsonReader(new StringReader("true")).nextBoolean();
-        } catch (IOException expected) {
-        }
+        new JsonReader(new StringReader("true")).nextBoolean();
     }
 
+    @Test
     public void testCharacterUnescaping() throws IOException {
         String json = "[\"a\","
                 + "\"a\\\"\","
@@ -199,14 +208,16 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testIntegersWithFractionalPartSpecified() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[1.0,1.0,1.0]"));
         reader.beginArray();
-        assertEquals(1.0, reader.nextDouble());
+        assertEquals(1.0, reader.nextDouble(), 0.0f);
         assertEquals(1, reader.nextInt());
         assertEquals(1L, reader.nextLong());
     }
 
+    @Test
     public void testDoubles() throws IOException {
         String json = "[-0.0,"
                 + "1.0,"
@@ -225,24 +236,25 @@
                 + "]";
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.beginArray();
-        assertEquals(-0.0, reader.nextDouble());
-        assertEquals(1.0, reader.nextDouble());
-        assertEquals(1.7976931348623157E308, reader.nextDouble());
-        assertEquals(4.9E-324, reader.nextDouble());
-        assertEquals(0.0, reader.nextDouble());
-        assertEquals(-0.5, reader.nextDouble());
-        assertEquals(2.2250738585072014E-308, reader.nextDouble());
-        assertEquals(3.141592653589793, reader.nextDouble());
-        assertEquals(2.718281828459045, reader.nextDouble());
-        assertEquals(1,0, reader.nextDouble());
-        assertEquals(11.0, reader.nextDouble());
+        assertEquals(-0.0, reader.nextDouble(), 0.0f);
+        assertEquals(1.0, reader.nextDouble(), 0.0f);
+        assertEquals(1.7976931348623157E308, reader.nextDouble(), 0.0f);
+        assertEquals(4.9E-324, reader.nextDouble(), 0.0f);
+        assertEquals(0.0, reader.nextDouble(), 0.0f);
+        assertEquals(-0.5, reader.nextDouble(), 0.0f);
+        assertEquals(2.2250738585072014E-308, reader.nextDouble(), 0.0f);
+        assertEquals(3.141592653589793, reader.nextDouble(), 0.0f);
+        assertEquals(2.718281828459045, reader.nextDouble(), 0.0f);
+        assertEquals(1.0, reader.nextDouble(), 0.0f);
+        assertEquals(11.0, reader.nextDouble(), 0.0f);
         assertTrue(Double.isNaN(reader.nextDouble()));
-        assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble());
-        assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble());
+        assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble(), 0.0f);
+        assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble(), 0.0f);
         reader.endArray();
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testLenientDoubles() throws IOException {
         String json = "["
                 + "011.0,"
@@ -255,7 +267,7 @@
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.setLenient(true);
         reader.beginArray();
-        assertEquals(11.0, reader.nextDouble());
+        assertEquals(11.0, reader.nextDouble(), 0.0f);
         assertTrue(Double.isNaN(reader.nextDouble()));
         try {
             reader.nextDouble();
@@ -263,18 +275,19 @@
         } catch (NumberFormatException expected) {
         }
         assertEquals("NAN", reader.nextString());
-        assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble());
+        assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble(), 0.0f);
         try {
             reader.nextDouble();
             fail();
         } catch (NumberFormatException expected) {
         }
         assertEquals("INFINITY", reader.nextString());
-        assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble());
+        assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble(), 0.0f);
         reader.endArray();
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testBufferBoundary() throws IOException {
         char[] pad = new char[READER_BUFFER_SIZE - 8];
         Arrays.fill(pad, '5');
@@ -287,6 +300,7 @@
         assertEquals(33333, reader.nextInt());
     }
 
+    @Test
     public void testTruncatedBufferBoundary() throws IOException {
         char[] pad = new char[READER_BUFFER_SIZE - 8];
         Arrays.fill(pad, '5');
@@ -305,15 +319,17 @@
         }
     }
 
+    @Test
     public void testLongestSupportedNumericLiterals() throws IOException {
-        testLongNumericLiterals(READER_BUFFER_SIZE - 1, JsonToken.NUMBER);
+        verifyLongNumericLiterals(READER_BUFFER_SIZE - 1, JsonToken.NUMBER);
     }
 
+    @Test
     public void testLongerNumericLiterals() throws IOException {
-        testLongNumericLiterals(READER_BUFFER_SIZE, JsonToken.STRING);
+        verifyLongNumericLiterals(READER_BUFFER_SIZE, JsonToken.STRING);
     }
 
-    private void testLongNumericLiterals(int length, JsonToken expectedToken) throws IOException {
+    private void verifyLongNumericLiterals(int length, JsonToken expectedToken) throws IOException {
         char[] longNumber = new char[length];
         Arrays.fill(longNumber, '9');
         longNumber[0] = '1';
@@ -324,10 +340,11 @@
         reader.setLenient(true);
         reader.beginArray();
         assertEquals(expectedToken, reader.peek());
-        assertEquals(2.0d, reader.nextDouble());
+        assertEquals(2.0d, reader.nextDouble(), 0.0f);
         reader.endArray();
     }
 
+    @Test
     public void testLongs() throws IOException {
         String json = "[0,0,0,"
                 + "1,1,1,"
@@ -344,13 +361,13 @@
         reader.beginArray();
         assertEquals(0L, reader.nextLong());
         assertEquals(0, reader.nextInt());
-        assertEquals(0.0, reader.nextDouble());
+        assertEquals(0.0, reader.nextDouble(), 0.0f);
         assertEquals(1L, reader.nextLong());
         assertEquals(1, reader.nextInt());
-        assertEquals(1.0, reader.nextDouble());
+        assertEquals(1.0, reader.nextDouble(), 0.0f);
         assertEquals(-1L, reader.nextLong());
         assertEquals(-1, reader.nextInt());
-        assertEquals(-1.0, reader.nextDouble());
+        assertEquals(-1.0, reader.nextDouble(), 0.0f);
         try {
             reader.nextInt();
             fail();
@@ -372,6 +389,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testHighPrecisionDouble_losesPrecision() throws IOException {
         // The presence of a fractional part forces us to use Double.parseDouble
         // instead of Long.parseLong (even though the fractional part is 0).
@@ -394,6 +412,7 @@
         reader.endArray();
     }
 
+    @Test
     public void testMatchingValidNumbers() throws IOException {
         String json = "[-1,99,-0,0,0e1,0e+1,0e-1,0E1,0E+1,0E-1,0.0,1.0,-1.0,1.0e0,1.0e+1,1.0e-1]";
         JsonReader reader = new JsonReader(new StringReader(json));
@@ -405,6 +424,7 @@
         reader.endArray();
     }
 
+    @Test
     public void testRecognizingInvalidNumbers() throws IOException {
         String json = "[-00,00,001,+1,1f,0x,0xf,0x0,0f1,0ee1,1..0,1e0.1,1.-01,1.+1,1.0x,1.0+]";
         JsonReader reader = new JsonReader(new StringReader(json));
@@ -417,6 +437,7 @@
         reader.endArray();
     }
 
+    @Test
     public void testNonFiniteDouble() throws IOException {
         String json = "[NaN]";
         JsonReader reader = new JsonReader(new StringReader(json));
@@ -428,6 +449,7 @@
         }
     }
 
+    @Test
     public void testNumberWithHexPrefix() throws IOException {
         String json = "[0x11]";
         JsonReader reader = new JsonReader(new StringReader(json));
@@ -439,6 +461,7 @@
         }
     }
 
+    @Test
     public void testNumberWithOctalPrefix() throws IOException {
         String json = "[01]";
         JsonReader reader = new JsonReader(new StringReader(json));
@@ -450,6 +473,7 @@
         }
     }
 
+    @Test
     public void testBooleans() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true,false]"));
         reader.beginArray();
@@ -459,6 +483,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testMixedCaseLiterals() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[True,TruE,False,FALSE,NULL,nulL]"));
         reader.beginArray();
@@ -472,6 +497,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testMissingValue() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\":}"));
         reader.beginObject();
@@ -483,6 +509,7 @@
         }
     }
 
+    @Test
     public void testPrematureEndOfInput() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\":true,"));
         reader.beginObject();
@@ -495,6 +522,7 @@
         }
     }
 
+    @Test
     public void testPrematurelyClosed() throws IOException {
         try {
             JsonReader reader = new JsonReader(new StringReader("{\"a\":[]}"));
@@ -525,6 +553,7 @@
         }
     }
 
+    @Test
     public void testNextFailuresDoNotAdvance() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\":true}"));
         reader.beginObject();
@@ -585,26 +614,21 @@
         reader.close();
     }
 
+    @Test(expected=IllegalStateException.class)
     public void testStringNullIsNotNull() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[\"null\"]"));
         reader.beginArray();
-        try {
-            reader.nextNull();
-            fail();
-        } catch (IllegalStateException expected) {
-        }
+        reader.nextNull();
     }
 
+    @Test(expected=IllegalStateException.class)
     public void testNullLiteralIsNotAString() throws IOException {
-       JsonReader reader = new JsonReader(new StringReader("[null]"));
+        JsonReader reader = new JsonReader(new StringReader("[null]"));
         reader.beginArray();
-        try {
-            reader.nextString();
-            fail();
-        } catch (IllegalStateException expected) {
-        }
+        reader.nextString();
     }
 
+    @Test
     public void testStrictNameValueSeparator() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\"=true}"));
         reader.beginObject();
@@ -625,6 +649,7 @@
         }
     }
 
+    @Test
     public void testLenientNameValueSeparator() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\"=true}"));
         reader.setLenient(true);
@@ -639,6 +664,7 @@
         assertEquals(true, reader.nextBoolean());
     }
 
+    @Test
     public void testStrictComments() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[// comment \n true]"));
         reader.beginArray();
@@ -665,6 +691,7 @@
         }
     }
 
+    @Test
     public void testLenientComments() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[// comment \n true]"));
         reader.setLenient(true);
@@ -682,6 +709,7 @@
         assertEquals(true, reader.nextBoolean());
     }
 
+    @Test
     public void testStrictUnquotedNames() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{a:true}"));
         reader.beginObject();
@@ -692,6 +720,7 @@
         }
     }
 
+    @Test
     public void testLenientUnquotedNames() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{a:true}"));
         reader.setLenient(true);
@@ -699,6 +728,7 @@
         assertEquals("a", reader.nextName());
     }
 
+    @Test
     public void testStrictSingleQuotedNames() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{'a':true}"));
         reader.beginObject();
@@ -709,6 +739,7 @@
         }
     }
 
+    @Test
     public void testLenientSingleQuotedNames() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{'a':true}"));
         reader.setLenient(true);
@@ -716,16 +747,14 @@
         assertEquals("a", reader.nextName());
     }
 
+    @Test(expected=MalformedJsonException.class)
     public void testStrictUnquotedStrings() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[a]"));
         reader.beginArray();
-        try {
-            reader.nextString();
-            fail();
-        } catch (MalformedJsonException expected) {
-        }
+        reader.nextString();
     }
 
+    @Test
     public void testLenientUnquotedStrings() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[a]"));
         reader.setLenient(true);
@@ -733,6 +762,7 @@
         assertEquals("a", reader.nextString());
     }
 
+    @Test
     public void testStrictSingleQuotedStrings() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("['a']"));
         reader.beginArray();
@@ -743,6 +773,7 @@
         }
     }
 
+    @Test
     public void testLenientSingleQuotedStrings() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("['a']"));
         reader.setLenient(true);
@@ -750,6 +781,7 @@
         assertEquals("a", reader.nextString());
     }
 
+    @Test
     public void testStrictSemicolonDelimitedArray() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true;true]"));
         reader.beginArray();
@@ -761,6 +793,7 @@
         }
     }
 
+    @Test
     public void testLenientSemicolonDelimitedArray() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true;true]"));
         reader.setLenient(true);
@@ -769,6 +802,7 @@
         assertEquals(true, reader.nextBoolean());
     }
 
+    @Test
     public void testStrictSemicolonDelimitedNameValuePair() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\":true;\"b\":true}"));
         reader.beginObject();
@@ -781,6 +815,7 @@
         }
     }
 
+    @Test
     public void testLenientSemicolonDelimitedNameValuePair() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("{\"a\":true;\"b\":true}"));
         reader.setLenient(true);
@@ -790,6 +825,7 @@
         assertEquals("b", reader.nextName());
     }
 
+    @Test
     public void testStrictUnnecessaryArraySeparators() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true,,true]"));
         reader.beginArray();
@@ -826,6 +862,7 @@
         }
     }
 
+    @Test
     public void testLenientUnnecessaryArraySeparators() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[true,,true]"));
         reader.setLenient(true);
@@ -857,6 +894,7 @@
         reader.endArray();
     }
 
+    @Test
     public void testStrictMultipleTopLevelValues() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[] []"));
         reader.beginArray();
@@ -868,6 +906,7 @@
         }
     }
 
+    @Test
     public void testLenientMultipleTopLevelValues() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[] true {}"));
         reader.setLenient(true);
@@ -879,6 +918,7 @@
         assertEquals(JsonToken.END_DOCUMENT, reader.peek());
     }
 
+    @Test
     public void testStrictTopLevelValueType() {
         JsonReader reader = new JsonReader(new StringReader("true"));
         try {
@@ -888,12 +928,14 @@
         }
     }
 
+    @Test
     public void testLenientTopLevelValueType() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("true"));
         reader.setLenient(true);
         assertEquals(true, reader.nextBoolean());
     }
 
+    @Test
     public void testStrictNonExecutePrefix() {
         JsonReader reader = new JsonReader(new StringReader(")]}'\n []"));
         try {
@@ -903,12 +945,14 @@
         }
     }
 
+    @Test
     public void testBomIgnoredAsFirstCharacterOfDocument() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("\ufeff[]"));
         reader.beginArray();
         reader.endArray();
     }
 
+    @Test
     public void testBomForbiddenAsOtherCharacterInDocument() throws IOException {
         JsonReader reader = new JsonReader(new StringReader("[\ufeff]"));
         reader.beginArray();
@@ -919,23 +963,26 @@
         }
     }
 
+    @Test
     public void testFailWithPosition() throws IOException {
-        testFailWithPosition("Expected literal value at line 6 column 3",
+        verifyFailWithPosition("Expected literal value at line 6 column 3",
                 "[\n\n\n\n\n0,}]");
     }
 
+    @Test
     public void testFailWithPositionIsOffsetByBom() throws IOException {
-        testFailWithPosition("Expected literal value at line 1 column 4",
+        verifyFailWithPosition("Expected literal value at line 1 column 4",
                 "\ufeff[0,}]");
     }
 
+    @Test
     public void testFailWithPositionGreaterThanBufferSize() throws IOException {
         String spaces = repeat(' ', 8192);
-        testFailWithPosition("Expected literal value at line 6 column 3",
+        verifyFailWithPosition("Expected literal value at line 6 column 3",
                 "[\n\n" + spaces + "\n\n\n0,}]");
     }
 
-    private void testFailWithPosition(String message, String json) throws IOException {
+    private void verifyFailWithPosition(String message, String json) throws IOException {
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.beginArray();
         reader.nextInt();
diff --git a/tests/tests/util/src/android/util/cts/JsonWriterTest.java b/tests/tests/util/src/android/util/cts/JsonWriterTest.java
index d0207d2..79819a2 100644
--- a/tests/tests/util/src/android/util/cts/JsonWriterTest.java
+++ b/tests/tests/util/src/android/util/cts/JsonWriterTest.java
@@ -16,16 +16,25 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.JsonWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.io.StringWriter;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import junit.framework.TestCase;
 
-import android.util.JsonWriter;
-
-public final class JsonWriterTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class JsonWriterTest {
+    @Test
     public void testWrongTopLevelType() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -36,6 +45,7 @@
         }
     }
 
+    @Test
     public void testTwoNames() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -48,6 +58,7 @@
         }
     }
 
+    @Test
     public void testNameWithoutValue() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -60,6 +71,7 @@
         }
     }
 
+    @Test
     public void testValueWithoutName() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -71,6 +83,7 @@
         }
     }
 
+    @Test
     public void testMultipleTopLevelValues() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -82,6 +95,7 @@
         }
     }
 
+    @Test
     public void testBadNestingObject() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -94,6 +108,7 @@
         }
     }
 
+    @Test
     public void testBadNestingArray() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -106,6 +121,7 @@
         }
     }
 
+    @Test
     public void testNullName() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -117,6 +133,7 @@
         }
     }
 
+    @Test
     public void testNullStringValue() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -127,6 +144,7 @@
         assertEquals("{\"a\":null}", stringWriter.toString());
     }
 
+    @Test
     public void testNonFiniteDoubles() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -148,6 +166,7 @@
         }
     }
 
+    @Test
     public void testNonFiniteBoxedDoubles() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -169,6 +188,7 @@
         }
     }
 
+    @Test
     public void testDoubles() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -195,6 +215,7 @@
                 + "2.718281828459045]", stringWriter.toString());
     }
 
+    @Test
     public void testLongs() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -213,6 +234,7 @@
                 + "9223372036854775807]", stringWriter.toString());
     }
 
+    @Test
     public void testNumbers() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -229,6 +251,7 @@
                 + "3.141592653589793238462643383]", stringWriter.toString());
     }
 
+    @Test
     public void testBooleans() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -239,6 +262,7 @@
         assertEquals("[true,false]", stringWriter.toString());
     }
 
+    @Test
     public void testNulls() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -248,6 +272,7 @@
         assertEquals("[null]", stringWriter.toString());
     }
 
+    @Test
     public void testStrings() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -291,6 +316,7 @@
                 + "\"\\u0019\"]", stringWriter.toString());
     }
 
+    @Test
     public void testUnicodeLineBreaksEscaped() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -300,6 +326,7 @@
         assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString());
     }
 
+    @Test
     public void testEmptyArray() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -308,6 +335,7 @@
         assertEquals("[]", stringWriter.toString());
     }
 
+    @Test
     public void testEmptyObject() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -316,6 +344,7 @@
         assertEquals("{}", stringWriter.toString());
     }
 
+    @Test
     public void testObjectsInArrays() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -333,6 +362,7 @@
                 + "{\"c\":6,\"d\":true}]", stringWriter.toString());
     }
 
+    @Test
     public void testArraysInObjects() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -352,6 +382,7 @@
                 + "\"b\":[6,true]}", stringWriter.toString());
     }
 
+    @Test
     public void testDeepNestingArrays() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -364,6 +395,7 @@
         assertEquals("[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]", stringWriter.toString());
     }
 
+    @Test
     public void testDeepNestingObjects() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -381,6 +413,7 @@
                 + "}}}}}}}}}}}}}}}}}}}}}", stringWriter.toString());
     }
 
+    @Test
     public void testRepeatedName() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -392,6 +425,7 @@
         assertEquals("{\"a\":true,\"a\":false}", stringWriter.toString());
     }
 
+    @Test
     public void testPrettyPrintObject() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -429,6 +463,7 @@
         assertEquals(expected, stringWriter.toString());
     }
 
+    @Test
     public void testPrettyPrintArray() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/tests/tests/util/src/android/util/cts/LogPrinterTest.java b/tests/tests/util/src/android/util/cts/LogPrinterTest.java
index 7411f9c..bd139ef 100644
--- a/tests/tests/util/src/android/util/cts/LogPrinterTest.java
+++ b/tests/tests/util/src/android/util/cts/LogPrinterTest.java
@@ -16,27 +16,31 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.util.LogPrinter;
 
-public class LogPrinterTest extends AndroidTestCase {
-    private final String mTag="LogPrinterTest";
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LogPrinterTest {
+    private static final String TAG = "LogPrinterTest";
+
+    @Test
     public void testConstructor() {
         int[] priorities = { Log.ASSERT, Log.DEBUG, Log.ERROR, Log.INFO,
                 Log.VERBOSE, Log.WARN };
         for (int i = 0; i < priorities.length; i++) {
-            new LogPrinter(priorities[i], mTag);
+            new LogPrinter(priorities[i], TAG);
         }
     }
 
+    @Test
     public void testPrintln() {
-        LogPrinter logPrinter = new LogPrinter(Log.DEBUG, mTag);
+        LogPrinter logPrinter = new LogPrinter(Log.DEBUG, TAG);
         String mMessage = "testMessage";
         logPrinter.println(mMessage);
     }
diff --git a/tests/tests/util/src/android/util/cts/LogTest.java b/tests/tests/util/src/android/util/cts/LogTest.java
index 80d0111..ada7af7 100644
--- a/tests/tests/util/src/android/util/cts/LogTest.java
+++ b/tests/tests/util/src/android/util/cts/LogTest.java
@@ -16,17 +16,21 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-/**
- * 
- * Test Log
- *
- */
-public class LogTest extends AndroidTestCase{
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LogTest {
     private static final String TAG = "LogTest";
 
+    @Test
     public void testLogOperations() {
         final String msg = "Test Log operations.";
         Exception tr = null;
diff --git a/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java b/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
index e5b23f8..fd19f7d 100644
--- a/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/LongSparseArrayTest.java
@@ -16,22 +16,33 @@
 
 package android.util.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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.LongSparseArray;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for {@link LongSparseArray}.
  */
-public class LongSparseArrayTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSparseArrayTest {
     private static final long[] KEYS = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
     private static final Integer[] VALUES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
     private static final int LENGTH = VALUES.length;
     private static final long NON_EXISTED_KEY = 123;
     private static final Integer VALUE_FOR_NON_EXISTED_KEY = -1;
 
+    @Test
     public void testSparseArrayWithDefaultCapacity() {
-        LongSparseArray<Integer> sparseArray = new LongSparseArray<Integer>();
+        LongSparseArray<Integer> sparseArray = new LongSparseArray<>();
         assertEquals(0, sparseArray.size());
 
         int length = VALUES.length;
@@ -95,8 +106,9 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testSparseArrayWithSpecifiedCapacity() {
-        LongSparseArray<Integer> sparseArray = new LongSparseArray<Integer>(5);
+        LongSparseArray<Integer> sparseArray = new LongSparseArray<>(5);
         assertEquals(0, sparseArray.size());
 
         int length = VALUES.length;
@@ -160,8 +172,9 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testIterationOrder() {
-        LongSparseArray<Long> sparseArray = new LongSparseArray<Long>();
+        LongSparseArray<Long> sparseArray = new LongSparseArray<>();
         // No matter in which order they are inserted.
         sparseArray.put(1L, Long.valueOf(2L));
         sparseArray.put(10L, Long.valueOf(20L));
@@ -179,4 +192,20 @@
         assertEquals(Long.MIN_VALUE, sparseArray.valueAt(3).longValue());
     }
 
+    @Test
+    public void testIndexOfValueByValue() {
+        LongSparseArray<String> sparseArray = new LongSparseArray<>();
+        // 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/MonthDisplayHelperTest.java b/tests/tests/util/src/android/util/cts/MonthDisplayHelperTest.java
index fc4dda1..df9916c 100644
--- a/tests/tests/util/src/android/util/cts/MonthDisplayHelperTest.java
+++ b/tests/tests/util/src/android/util/cts/MonthDisplayHelperTest.java
@@ -16,123 +16,118 @@
 
 package android.util.cts;
 
-import java.util.Calendar;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.MonthDisplayHelper;
 
-public class MonthDisplayHelperTest extends AndroidTestCase {
-    private MonthDisplayHelper mHelper;
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.util.Calendar;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MonthDisplayHelperTest {
+    @Test
     public void testConstructor() {
-
-        try {
-            mHelper = new MonthDisplayHelper(2008,
-                    Calendar.DECEMBER, Calendar.MONDAY);
-            mHelper = new MonthDisplayHelper(2008, Calendar.DECEMBER);
-        } catch (Exception e) {
-            fail("shouldn't throw exception");
-        }
-
-        try {
-            mHelper = new MonthDisplayHelper(2008,
-                    Calendar.DECEMBER, Calendar.SUNDAY - 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-        try {
-            mHelper = new MonthDisplayHelper(2008,
-                    Calendar.DECEMBER, Calendar.SATURDAY + 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-        try {
-            mHelper = new MonthDisplayHelper(-1, Calendar.DECEMBER,
-                    Calendar.SATURDAY + 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-        try {
-            mHelper = new MonthDisplayHelper(-1,
-                    Calendar.DECEMBER + 1, Calendar.SATURDAY + 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
-
+        new MonthDisplayHelper(2008, Calendar.DECEMBER, Calendar.MONDAY);
+        new MonthDisplayHelper(2008, Calendar.DECEMBER);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorInvalidDay1() {
+        new MonthDisplayHelper(2008, Calendar.DECEMBER, Calendar.SUNDAY - 1);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorInvalidDay2() {
+        new MonthDisplayHelper(2008, Calendar.DECEMBER, Calendar.SATURDAY + 1);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorInvalidYearAndDay() {
+        new MonthDisplayHelper(-1, Calendar.DECEMBER, Calendar.SATURDAY + 1);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorInvalidYearAndMonthAndDay() {
+        new MonthDisplayHelper(-1, Calendar.DECEMBER + 1, Calendar.SATURDAY + 1);
+    }
+
+    @Test
     public void testNumberOfDaysInCurrentMonth() {
-        assertEquals(30, new MonthDisplayHelper(2007, Calendar.SEPTEMBER)
-                .getNumberOfDaysInMonth());
-        assertEquals(28, new MonthDisplayHelper(2007, Calendar.FEBRUARY)
-        .getNumberOfDaysInMonth());
-        assertEquals(29, new MonthDisplayHelper(2008, Calendar.FEBRUARY)
-        .getNumberOfDaysInMonth());
+        assertEquals(30,
+                new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth());
+        assertEquals(28,
+                new MonthDisplayHelper(2007, Calendar.FEBRUARY).getNumberOfDaysInMonth());
+        assertEquals(29,
+                new MonthDisplayHelper(2008, Calendar.FEBRUARY).getNumberOfDaysInMonth());
     }
 
+    @Test
     public void testNextMonth() {
-        mHelper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
 
-        assertArraysEqual(new int[] { 29, 30, 31, 1, 2, 3, 4 }, mHelper
-                .getDigitsForRow(0));
+        assertArrayEquals(new int[] { 29, 30, 31, 1, 2, 3, 4 }, helper.getDigitsForRow(0));
 
-        mHelper.nextMonth();
+        helper.nextMonth();
 
-        assertEquals(Calendar.SEPTEMBER, mHelper.getMonth());
-        assertArraysEqual(new int[] { 26, 27, 28, 29, 30, 31, 1 }, mHelper
-                .getDigitsForRow(0));
+        assertEquals(Calendar.SEPTEMBER, helper.getMonth());
+        assertArrayEquals(new int[] { 26, 27, 28, 29, 30, 31, 1 }, helper.getDigitsForRow(0));
     }
 
+    @Test
     public void testGetRowOf() {
-        mHelper = new MonthDisplayHelper(2007,
-                Calendar.AUGUST, Calendar.SUNDAY);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
 
-        assertEquals(0, mHelper.getRowOf(2));
-        assertEquals(0, mHelper.getRowOf(4));
-        assertEquals(2, mHelper.getRowOf(12));
-        assertEquals(2, mHelper.getRowOf(18));
-        assertEquals(3, mHelper.getRowOf(19));
+        assertEquals(0, helper.getRowOf(2));
+        assertEquals(0, helper.getRowOf(4));
+        assertEquals(2, helper.getRowOf(12));
+        assertEquals(2, helper.getRowOf(18));
+        assertEquals(3, helper.getRowOf(19));
     }
 
+    @Test
     public void testHelperProperties() {
-        mHelper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
 
-        assertEquals(1, mHelper.getWeekStartDay());
-        assertEquals(3, mHelper.getOffset());
-        mHelper = new MonthDisplayHelper(2007, Calendar.AUGUST);
-        assertEquals(1, mHelper.getWeekStartDay());
-        assertEquals(3, mHelper.getOffset());
+        assertEquals(1, helper.getWeekStartDay());
+        assertEquals(3, helper.getOffset());
+        helper = new MonthDisplayHelper(2007, Calendar.AUGUST);
+        assertEquals(1, helper.getWeekStartDay());
+        assertEquals(3, helper.getOffset());
     }
 
+    @Test
     public void testMonthRows() {
-        mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER);
 
-        assertArraysEqual(new int[] { 26, 27, 28, 29, 30, 31, 1 }, mHelper
+        assertArrayEquals(new int[] { 26, 27, 28, 29, 30, 31, 1 }, helper
                 .getDigitsForRow(0));
-        assertArraysEqual(new int[] { 2, 3, 4, 5, 6, 7, 8 }, mHelper
+        assertArrayEquals(new int[] { 2, 3, 4, 5, 6, 7, 8 }, helper
                 .getDigitsForRow(1));
-        assertArraysEqual(new int[] { 30, 1, 2, 3, 4, 5, 6 }, mHelper
+        assertArrayEquals(new int[] { 30, 1, 2, 3, 4, 5, 6 }, helper
                 .getDigitsForRow(5));
 
-        mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER,
-                Calendar.MONDAY);
+        helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER, Calendar.MONDAY);
 
-        assertArraysEqual(new int[] { 27, 28, 29, 30, 31, 1, 2 }, mHelper
+        assertArrayEquals(new int[] { 27, 28, 29, 30, 31, 1, 2 }, helper
                 .getDigitsForRow(0));
-        assertArraysEqual(new int[] { 3, 4, 5, 6, 7, 8, 9 }, mHelper
+        assertArrayEquals(new int[] { 3, 4, 5, 6, 7, 8, 9 }, helper
                 .getDigitsForRow(1));
-        assertArraysEqual(new int[] { 24, 25, 26, 27, 28, 29, 30 }, mHelper
+        assertArrayEquals(new int[] { 24, 25, 26, 27, 28, 29, 30 }, helper
                 .getDigitsForRow(4));
-        assertArraysEqual(new int[] { 1, 2, 3, 4, 5, 6, 7 }, mHelper
+        assertArrayEquals(new int[] { 1, 2, 3, 4, 5, 6, 7 }, helper
                 .getDigitsForRow(5));
     }
 
+    @Test
     public void testFirstDayOfMonth() {
-
         assertEquals("august 2007", Calendar.WEDNESDAY, new MonthDisplayHelper(
                 2007, Calendar.AUGUST).getFirstDayOfMonth());
 
@@ -141,36 +136,35 @@
                         .getFirstDayOfMonth());
     }
 
+    @Test
     public void testGetColumnOf() {
-        mHelper= new MonthDisplayHelper(2007,
-                Calendar.AUGUST, Calendar.SUNDAY);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
 
-        assertEquals(3, mHelper.getColumnOf(1));
-        assertEquals(4, mHelper.getColumnOf(9));
-        assertEquals(5, mHelper.getColumnOf(17));
-        assertEquals(6, mHelper.getColumnOf(25));
-        assertEquals(0, mHelper.getColumnOf(26));
+        assertEquals(3, helper.getColumnOf(1));
+        assertEquals(4, helper.getColumnOf(9));
+        assertEquals(5, helper.getColumnOf(17));
+        assertEquals(6, helper.getColumnOf(25));
+        assertEquals(0, helper.getColumnOf(26));
     }
 
+    @Test
     public void testGetDayAt() {
-        mHelper = new MonthDisplayHelper(2007,
-                Calendar.AUGUST, Calendar.SUNDAY);
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.AUGUST, Calendar.SUNDAY);
 
-        assertEquals(30, mHelper.getDayAt(0, 1));
+        assertEquals(30, helper.getDayAt(0, 1));
     }
 
+    @Test
     public void testPrevMonth() {
-        mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER,
+        MonthDisplayHelper mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER,
                 Calendar.SUNDAY);
 
-        assertArraysEqual(new int[] { 26, 27, 28, 29, 30, 31, 1 }, mHelper
-                .getDigitsForRow(0));
+        assertArrayEquals(new int[] { 26, 27, 28, 29, 30, 31, 1 }, mHelper.getDigitsForRow(0));
 
         mHelper.previousMonth();
 
         assertEquals(Calendar.AUGUST, mHelper.getMonth());
-        assertArraysEqual(new int[] { 29, 30, 31, 1, 2, 3, 4 }, mHelper
-                .getDigitsForRow(0));
+        assertArrayEquals(new int[] { 29, 30, 31, 1, 2, 3, 4 }, mHelper.getDigitsForRow(0));
 
         mHelper = new MonthDisplayHelper(2007, Calendar.JANUARY);
 
@@ -180,8 +174,9 @@
         assertEquals(Calendar.DECEMBER, mHelper.getMonth());
     }
 
+    @Test
     public void testIsWithinCurrentMonth() {
-        mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER,
+        MonthDisplayHelper mHelper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER,
                 Calendar.SUNDAY);
 
         // out of bounds
@@ -202,13 +197,5 @@
         // last day in month
         assertTrue(mHelper.isWithinCurrentMonth(5, 0));
     }
-
-    private void assertArraysEqual(int[] expected, int[] actual) {
-        assertEquals("array length", expected.length, actual.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("index " + i,
-                    expected[i], actual[i]);
-        }
-    }
 }
 
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/PatternsTest.java b/tests/tests/util/src/android/util/cts/PatternsTest.java
index 61755ef..3a8df11 100644
--- a/tests/tests/util/src/android/util/cts/PatternsTest.java
+++ b/tests/tests/util/src/android/util/cts/PatternsTest.java
@@ -16,15 +16,22 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Patterns;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Patterns}.
  */
-public class PatternsTest extends TestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PatternsTest {
+    @Test
     public void testWebUrl_matchesUrlsWithCommasInRequestParameterValues() throws Exception {
         String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
         assertTrue("WEB_URL pattern should match commas", Patterns.WEB_URL.matcher(url).matches());
diff --git a/tests/tests/util/src/android/util/cts/PrintStreamPrinterTest.java b/tests/tests/util/src/android/util/cts/PrintStreamPrinterTest.java
index ed391191..59a6ee2 100644
--- a/tests/tests/util/src/android/util/cts/PrintStreamPrinterTest.java
+++ b/tests/tests/util/src/android/util/cts/PrintStreamPrinterTest.java
@@ -16,6 +16,18 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.PrintStreamPrinter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -24,52 +36,49 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintStream;
-import android.test.AndroidTestCase;
-import android.util.PrintStreamPrinter;
 
-public class PrintStreamPrinterTest extends AndroidTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PrintStreamPrinterTest {
     private File mFile;
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mFile = new File(getContext().getFilesDir(), "PrintStreamPrinter.log");
+
+    @Before
+    public void setup() throws IOException {
+        mFile = new File(InstrumentationRegistry.getTargetContext().getFilesDir(),
+                "PrintStreamPrinter.log");
         if (!mFile.exists()) {
             mFile.createNewFile();
         }
     }
 
+    @After
+    public void teardown() throws Exception {
+        if (mFile.exists()) {
+            mFile.delete();
+        }
+    }
+
+    @Test
     public void testConstructor() throws FileNotFoundException {
         new PrintStreamPrinter(new PrintStream(mFile));
     }
 
-    public void testPrintln() throws FileNotFoundException, SecurityException, IOException {
-        PrintStreamPrinter printStreamPrinter = null;
+    @Test
+    public void testPrintln() throws SecurityException, IOException {
         final String message = "testMessageOfPrintStreamPrinter";
-        InputStream is = null;
 
         PrintStream ps = new PrintStream(mFile);
-        printStreamPrinter = new PrintStreamPrinter(ps);
+        PrintStreamPrinter printStreamPrinter = new PrintStreamPrinter(ps);
         printStreamPrinter.println(message);
         ps.flush();
         ps.close();
         String mLine;
 
-        try {
-            is = new FileInputStream(mFile);
+        try (InputStream is = new FileInputStream(mFile)){
             BufferedReader reader = new BufferedReader(new InputStreamReader(is));
             mLine = reader.readLine();
             assertEquals(message, mLine);
             reader.close();
-        } finally {
-            is.close();
         }
     }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mFile.exists()) {
-            mFile.delete();
-        }
-        super.tearDown();
-    }
 }
diff --git a/tests/tests/util/src/android/util/cts/PrintWriterPrinterTest.java b/tests/tests/util/src/android/util/cts/PrintWriterPrinterTest.java
index 77f2d19..d7ae859 100644
--- a/tests/tests/util/src/android/util/cts/PrintWriterPrinterTest.java
+++ b/tests/tests/util/src/android/util/cts/PrintWriterPrinterTest.java
@@ -16,51 +16,61 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.PrintWriterPrinter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.util.PrintWriterPrinter;
-
-public class PrintWriterPrinterTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PrintWriterPrinterTest {
     private File mFile;
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        File dbDir = getContext().getDir("tests", Context.MODE_PRIVATE);
+
+    @Before
+    public void setup() throws IOException {
+        File dbDir = InstrumentationRegistry.getTargetContext().getDir("tests",
+                Context.MODE_PRIVATE);
         mFile = new File(dbDir,"print.log");
-        if (!mFile.exists())
+        if (!mFile.exists()) {
             mFile.createNewFile();
-    }
-
-    public void testConstructor() {
-
-        PrintWriterPrinter printWriterPrinter = null;
-
-        try {
-            PrintWriter pw = new PrintWriter(mFile);
-            printWriterPrinter = new PrintWriterPrinter(pw);
-        } catch (FileNotFoundException e) {
-            fail("shouldn't throw exception");
         }
     }
 
-    public void testPrintln() {
-        PrintWriterPrinter printWriterPrinter = null;
+    @After
+    public void teardown() throws Exception {
+        if (mFile.exists()) {
+            mFile.delete();
+        }
+    }
+
+    @Test
+    public void testConstructor() throws FileNotFoundException {
+        PrintWriter pw = new PrintWriter(mFile);
+        new PrintWriterPrinter(pw);
+    }
+
+    @Test
+    public void testPrintln() throws FileNotFoundException {
         String mMessage = "testMessage";
-        PrintWriter pw = null;
-        try {
-            pw = new PrintWriter(mFile);
-            printWriterPrinter = new PrintWriterPrinter(pw);
-        } catch (FileNotFoundException e) {
-            fail("shouldn't throw exception");
-        }
+        PrintWriter pw = new PrintWriter(mFile);
+        PrintWriterPrinter printWriterPrinter = new PrintWriterPrinter(pw);
         printWriterPrinter.println(mMessage);
         pw.flush();
         pw.close();
@@ -74,12 +84,5 @@
         }
         assertEquals(mMessage, mLine);
     }
-
-    @Override
-    protected void tearDown() throws Exception {
-        if (mFile.exists())
-            mFile.delete();
-    }
-
 }
 
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/RangeTest.java b/tests/tests/util/src/android/util/cts/RangeTest.java
index abab17b..5121ce1 100644
--- a/tests/tests/util/src/android/util/cts/RangeTest.java
+++ b/tests/tests/util/src/android/util/cts/RangeTest.java
@@ -16,150 +16,142 @@
 
 package android.util.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Range;
 import android.util.Rational;
 
-public class RangeTest extends junit.framework.TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @SmallTest
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangeTest {
+
+    @Test
     public void testConstructor() {
         // Trivial, same range
-        Range<Integer> intRange = new Range<Integer>(1, 1);
+        Range<Integer> intRange = new Range<>(1, 1);
 
-        assertLower(intRange, 1);
-        assertUpper(intRange, 1);
+        verifyLower(intRange, 1);
+        verifyUpper(intRange, 1);
 
         // Different values in range
-        Range<Integer> intRange2 = new Range<Integer>(100, 200);
-        assertLower(intRange2, 100);
-        assertUpper(intRange2, 200);
+        Range<Integer> intRange2 = new Range<>(100, 200);
+        verifyLower(intRange2, 100);
+        verifyUpper(intRange2, 200);
 
-        Range<Float> floatRange = new Range<Float>(Float.NEGATIVE_INFINITY,
+        Range<Float> floatRange = new Range<>(Float.NEGATIVE_INFINITY,
                 Float.POSITIVE_INFINITY);
-        assertLower(floatRange, Float.NEGATIVE_INFINITY);
-        assertUpper(floatRange, Float.POSITIVE_INFINITY);
+        verifyLower(floatRange, Float.NEGATIVE_INFINITY);
+        verifyUpper(floatRange, Float.POSITIVE_INFINITY);
     }
 
-    @SmallTest
-    public void testIllegalValues() {
-        // Test NPEs
-        try {
-            new Range<Integer>(null, null);
-            fail("Expected exception to be thrown for (null, null)");
-        } catch (NullPointerException e) {
-            // OK: both args are null
-        }
-
-        try {
-            new Range<Integer>(null, 0);
-            fail("Expected exception to be thrown for (null, 0)");
-        } catch (NullPointerException e) {
-            // OK: left arg is null
-        }
-
-        try {
-            new Range<Integer>(0, null);
-            fail("Expected exception to be thrown for (0, null)");
-        } catch (NullPointerException e) {
-            // OK: right arg is null
-        }
-
-        // Test IAEs
-
-        try {
-            new Range<Integer>(50, -50);
-            fail("Expected exception to be thrown for (50, -50)");
-        } catch (IllegalArgumentException e) {
-            // OK: 50 > -50 so it fails
-        }
-
-        try {
-            new Range<Float>(0.0f, Float.NEGATIVE_INFINITY);
-            fail("Expected exception to be thrown for (0.0f, -Infinity)");
-        } catch (IllegalArgumentException e) {
-            // OK: 0.0f is > NEGATIVE_INFINITY, so it fails
-        }
+    @Test(expected=NullPointerException.class)
+    public void testIntegerRangeNullBoth() {
+        new Range<Integer>(null, null);
     }
 
-    @SmallTest
+    @Test(expected=NullPointerException.class)
+    public void testIntegerRangeNullLower() {
+        new Range<>(null, 0);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testIntegerRangeNullUpper() {
+        new Range<>(0, null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testIntegerRangeLowerMoreThanHigher() {
+        new Range<>(50, -50);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testFloatRangeLowerMoreThanHigher() {
+        new Range<>(0.0f, Float.NEGATIVE_INFINITY);
+    }
+
+    @Test
     public void testEquals() {
         Range<Float> oneHalf = Range.create(1.0f, 2.0f);
-        Range<Float> oneHalf2 = new Range<Float>(1.0f, 2.0f);
+        Range<Float> oneHalf2 = new Range<>(1.0f, 2.0f);
         assertEquals(oneHalf, oneHalf2);
-        assertHashCodeEquals(oneHalf, oneHalf2);
+        verifyHashCodeEquals(oneHalf, oneHalf2);
 
-        Range<Float> twoThirds = new Range<Float>(2.0f, 3.0f);
+        Range<Float> twoThirds = new Range<>(2.0f, 3.0f);
         Range<Float> twoThirds2 = Range.create(2.0f, 3.0f);
         assertEquals(twoThirds, twoThirds2);
-        assertHashCodeEquals(twoThirds, twoThirds2);
+        verifyHashCodeEquals(twoThirds, twoThirds2);
 
         Range<Rational> negativeOneTenthPositiveOneTenth =
-                new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
+                new Range<>(new Rational(-1, 10), new Rational(1, 10));
         Range<Rational> negativeOneTenthPositiveOneTenth2 =
                 Range.create(new Rational(-1, 10), new Rational(1, 10));
         assertEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
-        assertHashCodeEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
+        verifyHashCodeEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
     }
 
-    @SmallTest
+    @Test
     public void testInRange() {
         Range<Integer> hundredOneTwo = Range.create(100, 200);
 
-        assertInRange(hundredOneTwo, 100);
-        assertInRange(hundredOneTwo, 200);
-        assertInRange(hundredOneTwo, 150);
-        assertOutOfRange(hundredOneTwo, 99);
-        assertOutOfRange(hundredOneTwo, 201);
-        assertOutOfRange(hundredOneTwo, 100000);
+        verifyInRange(hundredOneTwo, 100);
+        verifyInRange(hundredOneTwo, 200);
+        verifyInRange(hundredOneTwo, 150);
+        verifyOutOfRange(hundredOneTwo, 99);
+        verifyOutOfRange(hundredOneTwo, 201);
+        verifyOutOfRange(hundredOneTwo, 100000);
 
         Range<Float> infinities = Range.create(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
 
-        assertInRange(infinities, Float.NEGATIVE_INFINITY);
-        assertInRange(infinities, Float.POSITIVE_INFINITY);
-        assertInRange(infinities, 0.0f);
-        assertOutOfRange(infinities, Float.NaN);
+        verifyInRange(infinities, Float.NEGATIVE_INFINITY);
+        verifyInRange(infinities, Float.POSITIVE_INFINITY);
+        verifyInRange(infinities, 0.0f);
+        verifyOutOfRange(infinities, Float.NaN);
 
         Range<Rational> negativeOneTenthPositiveOneTenth =
-                new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
-        assertInRange(negativeOneTenthPositiveOneTenth, new Rational(-1, 10));
-        assertInRange(negativeOneTenthPositiveOneTenth, new Rational(1, 10));
-        assertInRange(negativeOneTenthPositiveOneTenth, Rational.ZERO);
-        assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(-100, 1));
-        assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(100, 1));
+                new Range<>(new Rational(-1, 10), new Rational(1, 10));
+        verifyInRange(negativeOneTenthPositiveOneTenth, new Rational(-1, 10));
+        verifyInRange(negativeOneTenthPositiveOneTenth, new Rational(1, 10));
+        verifyInRange(negativeOneTenthPositiveOneTenth, Rational.ZERO);
+        verifyOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(-100, 1));
+        verifyOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(100, 1));
     }
 
-    private static <T extends Comparable<? super T>> void assertInRange(Range<T> object, T needle) {
-        assertAction("in-range", object, needle, true, object.contains(needle));
+    private static <T extends Comparable<? super T>> void verifyInRange(Range<T> object, T needle) {
+        verifyAction("in-range", object, needle, true, object.contains(needle));
     }
 
-    private static <T extends Comparable<? super T>> void assertOutOfRange(Range<T> object,
+    private static <T extends Comparable<? super T>> void verifyOutOfRange(Range<T> object,
             T needle) {
-        assertAction("out-of-range", object, needle, false, object.contains(needle));
+        verifyAction("out-of-range", object, needle, false, object.contains(needle));
     }
 
-    private static <T extends Comparable<? super T>> void assertUpper(Range<T> object, T expected) {
-        assertAction("upper", object, expected, object.getUpper());
+    private static <T extends Comparable<? super T>> void verifyUpper(Range<T> object, T expected) {
+        verifyAction("upper", object, expected, object.getUpper());
     }
 
-    private static <T extends Comparable<? super T>> void assertLower(Range<T> object, T expected) {
-        assertAction("lower", object, expected, object.getLower());
+    private static <T extends Comparable<? super T>> void verifyLower(Range<T> object, T expected) {
+        verifyAction("lower", object, expected, object.getLower());
     }
 
-    private static <T, T2> void assertAction(String action, T object, T2 expected,
+    private static <T, T2> void verifyAction(String action, T object, T2 expected,
             T2 actual) {
         assertEquals("Expected " + object + " " + action + " to be ",
                 expected, actual);
     }
 
-    private static <T, T2> void assertAction(String action, T object, T2 needle, boolean expected,
+    private static <T, T2> void verifyAction(String action, T object, T2 needle, boolean expected,
             boolean actual) {
         String expectedMessage = expected ? action : ("not " + action);
         assertEquals("Expected " + needle + " to be " + expectedMessage + " of " + object,
                 expected, actual);
     }
 
-    private static <T extends Comparable<? super T>> void assertHashCodeEquals(
+    private static <T extends Comparable<? super T>> void verifyHashCodeEquals(
             Range<T> left, Range<T> right) {
         assertEquals("Left hash code for " + left +
                 " expected to be equal to right hash code for " + right,
diff --git a/tests/tests/util/src/android/util/cts/RationalTest.java b/tests/tests/util/src/android/util/cts/RationalTest.java
index ab5c063..84b2ece 100644
--- a/tests/tests/util/src/android/util/cts/RationalTest.java
+++ b/tests/tests/util/src/android/util/cts/RationalTest.java
@@ -16,9 +16,23 @@
 
 package android.util.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static android.util.Rational.NEGATIVE_INFINITY;
+import static android.util.Rational.NaN;
+import static android.util.Rational.POSITIVE_INFINITY;
+import static android.util.Rational.ZERO;
+
+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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Rational;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -28,14 +42,14 @@
 import java.io.Serializable;
 import java.lang.reflect.Field;
 
-import static android.util.Rational.*;
-
-public class RationalTest extends junit.framework.TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RationalTest {
 
     /** (1,1) */
     private static final Rational UNIT = new Rational(1, 1);
 
-    @SmallTest
+    @Test
     public void testConstructor() {
 
         // Simple case
@@ -74,7 +88,7 @@
         assertEquals(0, r.getDenominator());
     }
 
-    @SmallTest
+    @Test
     public void testEquals() {
         Rational r = new Rational(1, 2);
         assertEquals(1, r.getNumerator());
@@ -145,7 +159,7 @@
         assertFalse(nan.equals(negInf));
     }
 
-    @SmallTest
+    @Test
     public void testReduction() {
         Rational moreComplicated = new Rational(5 * 78, 7 * 78);
         assertEquals(new Rational(5, 7), moreComplicated);
@@ -176,153 +190,153 @@
         assertEquals(2, flipAndReduce.getDenominator());
     }
 
-    @SmallTest
+    @Test
     public void testCompareTo() {
         // unit is equal to itself
-        assertCompareEquals(UNIT, new Rational(1, 1));
+        verifyCompareEquals(UNIT, new Rational(1, 1));
 
         // NaN is greater than anything but NaN
-        assertCompareEquals(NaN, new Rational(0, 0));
-        assertGreaterThan(NaN, UNIT);
-        assertGreaterThan(NaN, POSITIVE_INFINITY);
-        assertGreaterThan(NaN, NEGATIVE_INFINITY);
-        assertGreaterThan(NaN, ZERO);
+        verifyCompareEquals(NaN, new Rational(0, 0));
+        verifyGreaterThan(NaN, UNIT);
+        verifyGreaterThan(NaN, POSITIVE_INFINITY);
+        verifyGreaterThan(NaN, NEGATIVE_INFINITY);
+        verifyGreaterThan(NaN, ZERO);
 
         // Positive infinity is greater than any other non-NaN
-        assertCompareEquals(POSITIVE_INFINITY, new Rational(1, 0));
-        assertGreaterThan(POSITIVE_INFINITY, UNIT);
-        assertGreaterThan(POSITIVE_INFINITY, NEGATIVE_INFINITY);
-        assertGreaterThan(POSITIVE_INFINITY, ZERO);
+        verifyCompareEquals(POSITIVE_INFINITY, new Rational(1, 0));
+        verifyGreaterThan(POSITIVE_INFINITY, UNIT);
+        verifyGreaterThan(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+        verifyGreaterThan(POSITIVE_INFINITY, ZERO);
 
         // Negative infinity is smaller than any other non-NaN
-        assertCompareEquals(NEGATIVE_INFINITY, new Rational(-1, 0));
-        assertLessThan(NEGATIVE_INFINITY, UNIT);
-        assertLessThan(NEGATIVE_INFINITY, POSITIVE_INFINITY);
-        assertLessThan(NEGATIVE_INFINITY, ZERO);
+        verifyCompareEquals(NEGATIVE_INFINITY, new Rational(-1, 0));
+        verifyLessThan(NEGATIVE_INFINITY, UNIT);
+        verifyLessThan(NEGATIVE_INFINITY, POSITIVE_INFINITY);
+        verifyLessThan(NEGATIVE_INFINITY, ZERO);
 
         // A finite number with the same denominator is trivially comparable
-        assertGreaterThan(new Rational(3, 100), new Rational(1, 100));
-        assertGreaterThan(new Rational(3, 100), ZERO);
+        verifyGreaterThan(new Rational(3, 100), new Rational(1, 100));
+        verifyGreaterThan(new Rational(3, 100), ZERO);
 
         // Compare finite numbers with different divisors
-        assertGreaterThan(new Rational(5, 25), new Rational(1, 10));
-        assertGreaterThan(new Rational(5, 25), ZERO);
+        verifyGreaterThan(new Rational(5, 25), new Rational(1, 10));
+        verifyGreaterThan(new Rational(5, 25), ZERO);
 
         // Compare finite numbers with different signs
-        assertGreaterThan(new Rational(5, 25), new Rational(-1, 10));
-        assertLessThan(new Rational(-5, 25), ZERO);
+        verifyGreaterThan(new Rational(5, 25), new Rational(-1, 10));
+        verifyLessThan(new Rational(-5, 25), ZERO);
     }
 
-    @SmallTest
+    @Test
     public void testConvenienceMethods() {
         // isFinite
-        assertFinite(ZERO, true);
-        assertFinite(NaN, false);
-        assertFinite(NEGATIVE_INFINITY, false);
-        assertFinite(POSITIVE_INFINITY, false);
-        assertFinite(UNIT, true);
+        verifyFinite(ZERO, true);
+        verifyFinite(NaN, false);
+        verifyFinite(NEGATIVE_INFINITY, false);
+        verifyFinite(POSITIVE_INFINITY, false);
+        verifyFinite(UNIT, true);
 
         // isInfinite
-        assertInfinite(ZERO, false);
-        assertInfinite(NaN, false);
-        assertInfinite(NEGATIVE_INFINITY, true);
-        assertInfinite(POSITIVE_INFINITY, true);
-        assertInfinite(UNIT, false);
+        verifyInfinite(ZERO, false);
+        verifyInfinite(NaN, false);
+        verifyInfinite(NEGATIVE_INFINITY, true);
+        verifyInfinite(POSITIVE_INFINITY, true);
+        verifyInfinite(UNIT, false);
 
         // isNaN
-        assertNaN(ZERO, false);
-        assertNaN(NaN, true);
-        assertNaN(NEGATIVE_INFINITY, false);
-        assertNaN(POSITIVE_INFINITY, false);
-        assertNaN(UNIT, false);
+        verifyNaN(ZERO, false);
+        verifyNaN(NaN, true);
+        verifyNaN(NEGATIVE_INFINITY, false);
+        verifyNaN(POSITIVE_INFINITY, false);
+        verifyNaN(UNIT, false);
 
         // isZero
-        assertZero(ZERO, true);
-        assertZero(NaN, false);
-        assertZero(NEGATIVE_INFINITY, false);
-        assertZero(POSITIVE_INFINITY, false);
-        assertZero(UNIT, false);
+        verifyZero(ZERO, true);
+        verifyZero(NaN, false);
+        verifyZero(NEGATIVE_INFINITY, false);
+        verifyZero(POSITIVE_INFINITY, false);
+        verifyZero(UNIT, false);
     }
 
-    @SmallTest
+    @Test
     public void testValueConversions() {
         // Unit, simple case
-        assertValueEquals(UNIT, 1.0f);
-        assertValueEquals(UNIT, 1.0);
-        assertValueEquals(UNIT, 1L);
-        assertValueEquals(UNIT, 1);
-        assertValueEquals(UNIT, (short)1);
+        verifyValueEquals(UNIT, 1.0f);
+        verifyValueEquals(UNIT, 1.0);
+        verifyValueEquals(UNIT, 1L);
+        verifyValueEquals(UNIT, 1);
+        verifyValueEquals(UNIT, (short)1);
 
         // Zero, simple case
-        assertValueEquals(ZERO, 0.0f);
-        assertValueEquals(ZERO, 0.0);
-        assertValueEquals(ZERO, 0L);
-        assertValueEquals(ZERO, 0);
-        assertValueEquals(ZERO, (short)0);
+        verifyValueEquals(ZERO, 0.0f);
+        verifyValueEquals(ZERO, 0.0);
+        verifyValueEquals(ZERO, 0L);
+        verifyValueEquals(ZERO, 0);
+        verifyValueEquals(ZERO, (short)0);
 
         // NaN is 0 for integers, not-a-number for floating point
-        assertValueEquals(NaN, Float.NaN);
-        assertValueEquals(NaN, Double.NaN);
-        assertValueEquals(NaN, 0L);
-        assertValueEquals(NaN, 0);
-        assertValueEquals(NaN, (short)0);
+        verifyValueEquals(NaN, Float.NaN);
+        verifyValueEquals(NaN, Double.NaN);
+        verifyValueEquals(NaN, 0L);
+        verifyValueEquals(NaN, 0);
+        verifyValueEquals(NaN, (short)0);
 
         // Positive infinity, saturates upwards for integers
-        assertValueEquals(POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
-        assertValueEquals(POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
-        assertValueEquals(POSITIVE_INFINITY, Long.MAX_VALUE);
-        assertValueEquals(POSITIVE_INFINITY, Integer.MAX_VALUE);
-        assertValueEquals(POSITIVE_INFINITY, (short)-1);
+        verifyValueEquals(POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+        verifyValueEquals(POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+        verifyValueEquals(POSITIVE_INFINITY, Long.MAX_VALUE);
+        verifyValueEquals(POSITIVE_INFINITY, Integer.MAX_VALUE);
+        verifyValueEquals(POSITIVE_INFINITY, (short)-1);
 
         // Negative infinity, saturates downwards for integers
-        assertValueEquals(NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
-        assertValueEquals(NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
-        assertValueEquals(NEGATIVE_INFINITY, Long.MIN_VALUE);
-        assertValueEquals(NEGATIVE_INFINITY, Integer.MIN_VALUE);
-        assertValueEquals(NEGATIVE_INFINITY, (short)0);
+        verifyValueEquals(NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+        verifyValueEquals(NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+        verifyValueEquals(NEGATIVE_INFINITY, Long.MIN_VALUE);
+        verifyValueEquals(NEGATIVE_INFINITY, Integer.MIN_VALUE);
+        verifyValueEquals(NEGATIVE_INFINITY, (short)0);
 
         // Normal finite values, round down for integers
         final Rational oneQuarter = new Rational(1, 4);
-        assertValueEquals(oneQuarter, 1.0f / 4.0f);
-        assertValueEquals(oneQuarter, 1.0 / 4.0);
-        assertValueEquals(oneQuarter, 0L);
-        assertValueEquals(oneQuarter, 0);
-        assertValueEquals(oneQuarter, (short)0);
+        verifyValueEquals(oneQuarter, 1.0f / 4.0f);
+        verifyValueEquals(oneQuarter, 1.0 / 4.0);
+        verifyValueEquals(oneQuarter, 0L);
+        verifyValueEquals(oneQuarter, 0);
+        verifyValueEquals(oneQuarter, (short)0);
 
         final Rational nineFifths = new Rational(9, 5);
-        assertValueEquals(nineFifths, 9.0f / 5.0f);
-        assertValueEquals(nineFifths, 9.0 / 5.0);
-        assertValueEquals(nineFifths, 1L);
-        assertValueEquals(nineFifths, 1);
-        assertValueEquals(nineFifths, (short)1);
+        verifyValueEquals(nineFifths, 9.0f / 5.0f);
+        verifyValueEquals(nineFifths, 9.0 / 5.0);
+        verifyValueEquals(nineFifths, 1L);
+        verifyValueEquals(nineFifths, 1);
+        verifyValueEquals(nineFifths, (short)1);
 
         final Rational negativeHundred = new Rational(-1000, 10);
-        assertValueEquals(negativeHundred, -100.f / 1.f);
-        assertValueEquals(negativeHundred, -100.0 / 1.0);
-        assertValueEquals(negativeHundred, -100L);
-        assertValueEquals(negativeHundred, -100);
-        assertValueEquals(negativeHundred, (short)-100);
+        verifyValueEquals(negativeHundred, -100.f / 1.f);
+        verifyValueEquals(negativeHundred, -100.0 / 1.0);
+        verifyValueEquals(negativeHundred, -100L);
+        verifyValueEquals(negativeHundred, -100);
+        verifyValueEquals(negativeHundred, (short)-100);
 
         // Short truncates if the result is too large
-        assertValueEquals(new Rational(Integer.MAX_VALUE, 1), (short)Integer.MAX_VALUE);
-        assertValueEquals(new Rational(0x00FFFFFF, 1), (short)0x00FFFFFF);
-        assertValueEquals(new Rational(0x00FF00FF, 1), (short)0x00FF00FF);
+        verifyValueEquals(new Rational(Integer.MAX_VALUE, 1), (short)Integer.MAX_VALUE);
+        verifyValueEquals(new Rational(0x00FFFFFF, 1), (short)0x00FFFFFF);
+        verifyValueEquals(new Rational(0x00FF00FF, 1), (short)0x00FF00FF);
     }
 
-    @SmallTest
+    @Test
     public void testSerialize() throws ClassNotFoundException, IOException {
         /*
          * Check correct [de]serialization
          */
-        assertEqualsAfterSerializing(ZERO);
-        assertEqualsAfterSerializing(NaN);
-        assertEqualsAfterSerializing(NEGATIVE_INFINITY);
-        assertEqualsAfterSerializing(POSITIVE_INFINITY);
-        assertEqualsAfterSerializing(UNIT);
-        assertEqualsAfterSerializing(new Rational(100, 200));
-        assertEqualsAfterSerializing(new Rational(-100, 200));
-        assertEqualsAfterSerializing(new Rational(5, 1));
-        assertEqualsAfterSerializing(new Rational(Integer.MAX_VALUE, Integer.MIN_VALUE));
+        verifyEqualsAfterSerializing(ZERO);
+        verifyEqualsAfterSerializing(NaN);
+        verifyEqualsAfterSerializing(NEGATIVE_INFINITY);
+        verifyEqualsAfterSerializing(POSITIVE_INFINITY);
+        verifyEqualsAfterSerializing(UNIT);
+        verifyEqualsAfterSerializing(new Rational(100, 200));
+        verifyEqualsAfterSerializing(new Rational(-100, 200));
+        verifyEqualsAfterSerializing(new Rational(5, 1));
+        verifyEqualsAfterSerializing(new Rational(Integer.MAX_VALUE, Integer.MIN_VALUE));
 
         /*
          * Check bad deserialization fails
@@ -369,69 +383,95 @@
         }
     }
 
-    private static void assertValueEquals(Rational object, float expected) {
+    @Test
+    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"));
+
+        Rational r = new Rational(10, 15);
+        assertEquals(r, Rational.parseRational(r.toString()));
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testParseRationalInvalid1() {
+        Rational.parseRational("1.5");
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testParseRationalInvalid2() {
+        Rational.parseRational("239");
+    }
+
+    private static void verifyValueEquals(Rational object, float expected) {
         assertEquals("Checking floatValue() for " + object + ";",
-                expected, object.floatValue());
+                expected, object.floatValue(), 0.0f);
     }
 
-    private static void assertValueEquals(Rational object, double expected) {
+    private static void verifyValueEquals(Rational object, double expected) {
         assertEquals("Checking doubleValue() for " + object + ";",
-                expected, object.doubleValue());
+                expected, object.doubleValue(), 0.0f);
     }
 
-    private static void assertValueEquals(Rational object, long expected) {
+    private static void verifyValueEquals(Rational object, long expected) {
         assertEquals("Checking longValue() for " + object + ";",
                 expected, object.longValue());
     }
 
-    private static void assertValueEquals(Rational object, int expected) {
+    private static void verifyValueEquals(Rational object, int expected) {
         assertEquals("Checking intValue() for " + object + ";",
                 expected, object.intValue());
     }
 
-    private static void assertValueEquals(Rational object, short expected) {
+    private static void verifyValueEquals(Rational object, short expected) {
         assertEquals("Checking shortValue() for " + object + ";",
                 expected, object.shortValue());
     }
 
-    private static void assertFinite(Rational object, boolean expected) {
-        assertAction("finite", object, expected, object.isFinite());
+    private static void verifyFinite(Rational object, boolean expected) {
+        verifyAction("finite", object, expected, object.isFinite());
     }
 
-    private static void assertInfinite(Rational object, boolean expected) {
-        assertAction("infinite", object, expected, object.isInfinite());
+    private static void verifyInfinite(Rational object, boolean expected) {
+        verifyAction("infinite", object, expected, object.isInfinite());
     }
 
-    private static void assertNaN(Rational object, boolean expected) {
-        assertAction("NaN", object, expected, object.isNaN());
+    private static void verifyNaN(Rational object, boolean expected) {
+        verifyAction("NaN", object, expected, object.isNaN());
     }
 
-    private static void assertZero(Rational object, boolean expected) {
-        assertAction("zero", object, expected, object.isZero());
+    private static void verifyZero(Rational object, boolean expected) {
+        verifyAction("zero", object, expected, object.isZero());
     }
 
-    private static <T> void assertAction(String action, T object, boolean expected,
+    private static <T> void verifyAction(String action, T object, boolean expected,
             boolean actual) {
         String expectedMessage = expected ? action : ("not " + action);
         assertEquals("Expected " + object + " to be " + expectedMessage,
                 expected, actual);
     }
 
-    private static <T extends Comparable<? super T>> void assertLessThan(T left, T right) {
+    private static <T extends Comparable<? super T>> void verifyLessThan(T left, T right) {
         assertTrue("Expected (LR) left " + left + " to be less than right " + right,
                 left.compareTo(right) < 0);
         assertTrue("Expected (RL) left " + left + " to be less than right " + right,
                 right.compareTo(left) > 0);
     }
 
-    private static <T extends Comparable<? super T>> void assertGreaterThan(T left, T right) {
+    private static <T extends Comparable<? super T>> void verifyGreaterThan(T left, T right) {
         assertTrue("Expected (LR) left " + left + " to be greater than right " + right,
                 left.compareTo(right) > 0);
         assertTrue("Expected (RL) left " + left + " to be greater than right " + right,
                 right.compareTo(left) < 0);
     }
 
-    private static <T extends Comparable<? super T>> void assertCompareEquals(T left, T right) {
+    private static <T extends Comparable<? super T>> void verifyCompareEquals(T left, T right) {
         assertTrue("Expected (LR) left " + left + " to be compareEquals to right " + right,
                 left.compareTo(right) == 0);
         assertTrue("Expected (RL) left " + left + " to be compareEquals to right " + right,
@@ -463,7 +503,7 @@
         return serialized;
     }
 
-    private static <T extends Serializable> void assertEqualsAfterSerializing(T obj)
+    private static <T extends Serializable> void verifyEqualsAfterSerializing(T obj)
             throws ClassNotFoundException, IOException {
         T serialized = serializeRoundTrip(obj);
         assertEquals("Expected values to be equal after serialization round-trip", obj, serialized);
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..f274945
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/SizeTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Size;
+import android.util.SizeF;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@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(expected=NumberFormatException.class)
+    public void testParseSizeInvalid() {
+        Size.parseSize("2by4");
+    }
+
+    @Test
+    public void testParseSize() {
+        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(expected=NumberFormatException.class)
+    public void testParseSizeFInvalid() {
+        SizeF.parseSizeF("2by4");
+    }
+
+    @Test
+    public void testParseSizeF() {
+        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..06bd085 100644
--- a/tests/tests/util/src/android/util/cts/SparseArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/SparseArrayTest.java
@@ -16,18 +16,30 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+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 android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
-public class SparseArrayTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseArrayTest {
     private static final int[] KEYS = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
     private static final Integer[] VALUES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
     private static final int LENGTH = VALUES.length;
     private static final int NON_EXISTED_KEY = 123;
     private static final Integer VALUE_FOR_NON_EXISTED_KEY = -1;
 
+    @Test
     public void testSparseArrayWithDefaultCapacity() {
-        SparseArray<Integer> sparseArray = new SparseArray<Integer>();
+        SparseArray<Integer> sparseArray = new SparseArray<>();
         assertEquals(0, sparseArray.size());
 
         int length = VALUES.length;
@@ -91,8 +103,9 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testSparseArrayWithSpecifiedCapacity() {
-        SparseArray<Integer> sparseArray = new SparseArray<Integer>(5);
+        SparseArray<Integer> sparseArray = new SparseArray<>(5);
         assertEquals(0, sparseArray.size());
 
         int length = VALUES.length;
@@ -156,8 +169,9 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testIterationOrder() {
-        SparseArray<Long> sparseArray = new SparseArray<Long>();
+        SparseArray<Long> sparseArray = new SparseArray<>();
         // No matter in which order they are inserted.
         sparseArray.put(1, Long.valueOf(2L));
         sparseArray.put(10, Long.valueOf(20L));
@@ -174,4 +188,21 @@
         assertEquals(20L, sparseArray.valueAt(2).longValue());
         assertEquals(Long.MIN_VALUE, sparseArray.valueAt(3).longValue());
     }
+
+    @Test
+    public void testIndexOfValueByValue() {
+        SparseArray<String> sparseArray = new SparseArray<>();
+        // 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/SparseBooleanArrayTest.java b/tests/tests/util/src/android/util/cts/SparseBooleanArrayTest.java
index 0ac8ea4..6a533f5 100644
--- a/tests/tests/util/src/android/util/cts/SparseBooleanArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/SparseBooleanArrayTest.java
@@ -16,21 +16,26 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseBooleanArray;
 
-public class SparseBooleanArrayTest extends AndroidTestCase {
-    private static final int[] KEYS   = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseBooleanArrayTest {
+    private static final int[] KEYS = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
     private static final boolean[] VALUES =
-        {true,  false, true, false, false, true, true, true, true, false, false, false, false};
+        {true, false, true, false, false, true, true, true, true, false, false, false, false};
     private static final int NON_EXISTED_KEY = 123;
     private static final boolean VALUE_FOR_NON_EXISTED_KEY = true;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+    @Test
     public void testSparseBooleanArrayWithDefaultCapacity() {
         SparseBooleanArray sparseBooleanArray = new SparseBooleanArray();
         assertEquals(0, sparseBooleanArray.size());
@@ -87,6 +92,7 @@
         assertEquals(0, sparseBooleanArray.size());
     }
 
+    @Test
     public void testSparseBooleanArrayWithSpecifiedCapacity() {
         SparseBooleanArray sparseBooleanArray = new SparseBooleanArray(5);
         assertEquals(0, sparseBooleanArray.size());
@@ -143,6 +149,7 @@
         assertEquals(0, sparseBooleanArray.size());
     }
 
+    @Test
     public void testIterationOrder() {
         SparseBooleanArray sparseArray = new SparseBooleanArray();
         // No matter in which order they are inserted.
diff --git a/tests/tests/util/src/android/util/cts/SparseIntArrayTest.java b/tests/tests/util/src/android/util/cts/SparseIntArrayTest.java
index d0e4447..9c554fa 100644
--- a/tests/tests/util/src/android/util/cts/SparseIntArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/SparseIntArrayTest.java
@@ -16,23 +16,25 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseIntArray;
 
-import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-
-public class SparseIntArrayTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseIntArrayTest {
     private static final int[] KEYS   = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
     private static final int[] VALUES = {0,  1,  2, 3, 4, 5, 6, 7,   8,  9, 10, 11,  12};
     private static final int   NON_EXISTED_KEY = 123;
     private static final int   VALUE_FOR_NON_EXISTED_KEY = -1;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+    @Test
     public void testSparseIntArrayWithDefaultCapacity() {
         SparseIntArray sparseIntArray = new SparseIntArray();
         assertEquals(0, sparseIntArray.size());
@@ -82,6 +84,7 @@
         assertEquals(0, sparseIntArray.size());
     }
 
+    @Test
     public void testSparseIntArrayWithSpecifiedCapacity() {
         SparseIntArray sparseIntArray = new SparseIntArray(5);
         assertEquals(0, sparseIntArray.size());
@@ -130,6 +133,7 @@
         assertEquals(0, sparseIntArray.size());
     }
 
+    @Test
     public void testSparseIntArrayRemoveAt() {
         final int[] testData = {
             13, 42, 85932, 885932, -6, Integer.MAX_VALUE, 0, Integer.MIN_VALUE };
@@ -171,6 +175,7 @@
         }
     }
 
+    @Test
     public void testIterationOrder() {
         SparseIntArray sparseArray = new SparseIntArray();
         // No matter in which order they are inserted.
diff --git a/tests/tests/util/src/android/util/cts/SparseLongArrayTest.java b/tests/tests/util/src/android/util/cts/SparseLongArrayTest.java
index c40691c..501c788 100644
--- a/tests/tests/util/src/android/util/cts/SparseLongArrayTest.java
+++ b/tests/tests/util/src/android/util/cts/SparseLongArrayTest.java
@@ -16,20 +16,29 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseLongArray;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for {@link SparseLongArray}.
  */
-public class SparseLongArrayTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SparseLongArrayTest {
     private static final int[] KEYS = {12, 23, 4, 6, 8, 1, 3, -12, 0, -3, 11, 14, -23};
     private static final long[] VALUES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
     private static final int LENGTH = VALUES.length;
     private static final int NON_EXISTED_KEY = 123;
     private static final long VALUE_FOR_NON_EXISTED_KEY = -1;
 
+    @Test
     public void testSparseArrayWithDefaultCapacity() {
         SparseLongArray sparseArray = new SparseLongArray();
         assertEquals(0, sparseArray.size());
@@ -91,6 +100,7 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testSparseArrayWithSpecifiedCapacity() {
         SparseLongArray sparseArray = new SparseLongArray(5);
         assertEquals(0, sparseArray.size());
@@ -152,6 +162,7 @@
         assertEquals(0, sparseArray.size());
     }
 
+    @Test
     public void testIterationOrder() {
         SparseLongArray sparseArray = new SparseLongArray();
         // No matter in which order they are inserted.
diff --git a/tests/tests/util/src/android/util/cts/StateSetTest.java b/tests/tests/util/src/android/util/cts/StateSetTest.java
index cf71b7d..c3420eb 100644
--- a/tests/tests/util/src/android/util/cts/StateSetTest.java
+++ b/tests/tests/util/src/android/util/cts/StateSetTest.java
@@ -16,20 +16,24 @@
 
 package android.util.cts;
 
-import android.R;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.StateSet;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test StateSet
  */
-public class StateSetTest extends AndroidTestCase {
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StateSetTest {
+    @Test
     public void testTrimStateSet() {
         // state set's old size is equal to new size
         int[] stateSet = {1, 2, 3};
@@ -42,17 +46,19 @@
         }
     }
 
+    @Test
     public void testDump() {
-        int[] stateSet = {R.attr.state_window_focused,
-                          R.attr.state_pressed,
-                          R.attr.state_selected,
-                          R.attr.state_focused,
-                          R.attr.state_enabled,
+        int[] stateSet = {android.R.attr.state_window_focused,
+                          android.R.attr.state_pressed,
+                          android.R.attr.state_selected,
+                          android.R.attr.state_focused,
+                          android.R.attr.state_enabled,
                           1234325}; // irrelevant value
         String string = StateSet.dump(stateSet);
         assertEquals("W P S F E ", string);
     }
 
+    @Test
     public void testStateSetMatches() throws Exception {
          int[] stateSpec1 = new int[2];
          int[] stateSet1 = new int[3];
@@ -188,5 +194,4 @@
         stateSpec10 = StateSet.WILD_CARD;
         assertTrue(StateSet.stateSetMatches(stateSpec10, state3));
     }
-
 }
diff --git a/tests/tests/util/src/android/util/cts/StrictJarFileTest.java b/tests/tests/util/src/android/util/cts/StrictJarFileTest.java
index e7eedfd..3c18df7 100644
--- a/tests/tests/util/src/android/util/cts/StrictJarFileTest.java
+++ b/tests/tests/util/src/android/util/cts/StrictJarFileTest.java
@@ -16,60 +16,107 @@
 
 package android.util.cts;
 
-import android.test.AndroidTestCase;
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.OsConstants;
+import android.util.jar.StrictJarFile;
+
+import libcore.io.IoBridge;
+import libcore.io.Streams;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
-import java.io.InputStream;
+import java.io.FileDescriptor;
 import java.io.FileOutputStream;
-import java.io.OutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Iterator;
-import android.util.jar.StrictJarFile;
 import java.util.zip.ZipEntry;
-import libcore.io.Streams;
 
-public class StrictJarFileTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StrictJarFileTest {
     // A well formed jar file with 6 entries.
     private static final String JAR_1 = "hyts_patch.jar";
 
-    private File resources;
+    private File mResourcesFile;
 
-    @Override
-    protected void setUp() {
+    @Before
+    public void setup() {
         try {
-            resources = File.createTempFile("sjf_resources", "", null);
-            resources.delete();
-            resources.mkdirs();
+            mResourcesFile = File.createTempFile("sjf_resources", "", null);
+            mResourcesFile.delete();
+            mResourcesFile.mkdirs();
         } catch (IOException e) {
             throw new RuntimeException("Unable to create temp folder", e);
         }
-        resources.deleteOnExit();
+        mResourcesFile.deleteOnExit();
     }
 
-    public void testConstructor() throws Exception {
-        try {
-            StrictJarFile jarFile = new StrictJarFile("Wrong.file");
-            fail("Should throw IOException");
-        } catch (IOException e) {
-            // expected
-        }
+    @Test(expected=IOException.class)
+    public void testConstructorWrongFile() throws IOException {
+        new StrictJarFile("Wrong.file");
+    }
 
+    @Test(expected=IOException.class)
+    public void testConstructorWrongFile_FD() throws IOException {
+        new StrictJarFile(new FileDescriptor());
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWrongFile_FD_null() throws IOException {
+        new StrictJarFile((FileDescriptor) null);
+    }
+
+    @Test
+    public void testConstructor() throws Exception {
         copyFile(JAR_1);
-        String fileName = (new File(resources, JAR_1)).getCanonicalPath();
+        String fileName = (new File(mResourcesFile, JAR_1)).getCanonicalPath();
         StrictJarFile jarFile = new StrictJarFile(fileName);
         jarFile.close();
     }
 
+    @Test
+    public void testConstructor_FD() throws Exception {
+        copyFile(JAR_1);
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        jarFile.close();
+    }
+
+    @Test
     public void testIteration() throws Exception {
         copyFile(JAR_1);
-        StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
+        StrictJarFile jarFile =
+                new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
+        checkIteration(jarFile);
+    }
 
+    @Test
+    public void testIteration_FD() throws Exception {
+        copyFile(JAR_1);
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkIteration(jarFile);
+    }
+
+    private static void checkIteration(StrictJarFile jarFile) throws Exception {
         Iterator<ZipEntry> it = jarFile.iterator();
-        HashMap<String, ZipEntry> entries = new HashMap<String, ZipEntry>();
+        HashMap<String, ZipEntry> entries = new HashMap<>();
         while (it.hasNext()) {
             final ZipEntry ze = it.next();
             entries.put(ze.getName(), ze);
@@ -101,10 +148,24 @@
         assertEquals(225, ze.getCompressedSize());
     }
 
+    @Test
     public void testFindEntry() throws Exception {
         copyFile(JAR_1);
-        StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
+        StrictJarFile jarFile =
+                new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
+        checkFindEntry(jarFile);
+    }
 
+    @Test
+    public void testFindEntry_FD() throws Exception {
+        copyFile(JAR_1);
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkFindEntry(jarFile);
+    }
+
+    private static void checkFindEntry(StrictJarFile jarFile) throws Exception {
         assertNull(jarFile.findEntry("foobar"));
         assertNull(jarFile.findEntry("blah.txt"));
         assertNotNull(jarFile.findEntry("Blah.txt"));
@@ -116,17 +177,48 @@
                 Charset.forName("UTF-8")));
     }
 
+    @Test
     public void testGetManifest() throws Exception {
         copyFile(JAR_1);
-        StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
-
-        assertNotNull(jarFile.getManifest());
-        assertEquals("1.4.2 (IBM Corporation)", jarFile.getManifest().getMainAttributes().getValue("Created-By"));
+        StrictJarFile jarFile =
+                new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
+        checkGetManifest(jarFile);
     }
 
+    @Test
+    public void testGetManifest_FD() throws Exception {
+        copyFile(JAR_1);
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkGetManifest(jarFile);
+    }
+
+    private static void checkGetManifest(StrictJarFile jarFile) throws Exception {
+        assertNotNull(jarFile.getManifest());
+        assertEquals("1.4.2 (IBM Corporation)",
+                jarFile.getManifest().getMainAttributes().getValue("Created-By"));
+    }
+
+    @Test
     public void testJarSigning_wellFormed() throws IOException {
         copyFile("Integrate.jar");
-        StrictJarFile jarFile = new StrictJarFile(new File(resources, "Integrate.jar").getAbsolutePath());
+        StrictJarFile jarFile =
+                new StrictJarFile(new File(mResourcesFile, "Integrate.jar").getAbsolutePath());
+        checkJarSigning_wellFormed(jarFile);
+    }
+
+    @Test
+    public void testJarSigning_wellFormed_FD() throws IOException {
+        copyFile("Integrate.jar");
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, "Integrate.jar").getAbsolutePath(),
+                        OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkJarSigning_wellFormed(jarFile);
+    }
+
+    private static void checkJarSigning_wellFormed(StrictJarFile jarFile) throws IOException {
         Iterator<ZipEntry> entries = jarFile.iterator();
         while (entries.hasNext()) {
             ZipEntry zipEntry = entries.next();
@@ -138,11 +230,25 @@
         }
     }
 
-     public void testJarSigning_fudgedEntry() throws IOException {
+    @Test
+    public void testJarSigning_fudgedEntry() throws IOException {
         copyFile("Integrate.jar");
         StrictJarFile jarFile = new StrictJarFile(
-                new File(resources, "Integrate.jar").getAbsolutePath());
+                new File(mResourcesFile, "Integrate.jar").getAbsolutePath());
+        checkJarSigning_fudgedEntry(jarFile);
+    }
 
+    @Test
+    public void testJarSigning_fudgedEntry_FD() throws IOException {
+        copyFile("Integrate.jar");
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, "Integrate.jar").getAbsolutePath(),
+                        OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkJarSigning_fudgedEntry(jarFile);
+    }
+
+    private static void checkJarSigning_fudgedEntry(StrictJarFile jarFile) throws IOException {
         ZipEntry ze = jarFile.findEntry("Test.class");
         jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
 
@@ -155,11 +261,26 @@
         }
     }
 
+    @Test
     public void testJarSigning_modifiedClass() throws IOException {
         copyFile("Modified_Class.jar");
         StrictJarFile jarFile = new StrictJarFile(
-                new File(resources,  "Modified_Class.jar").getAbsolutePath());
+                new File(mResourcesFile,  "Modified_Class.jar").getAbsolutePath());
+        checkJarSigning_modifiedClass(jarFile);
+    }
 
+    @Test
+    public void testJarSigning_modifiedClass_FD() throws IOException {
+        copyFile("Modified_Class.jar");
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, "Modified_Class.jar").getAbsolutePath(),
+                        OsConstants.O_RDONLY);
+        StrictJarFile jarFile = new StrictJarFile(fd);
+        checkJarSigning_modifiedClass(jarFile);
+    }
+
+    private static void checkJarSigning_modifiedClass(StrictJarFile jarFile)
+            throws IOException {
         ZipEntry ze = jarFile.findEntry("Test.class");
         try {
             jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
@@ -168,39 +289,73 @@
         }
     }
 
+    @Test
     public void testJarSigning_brokenMainAttributes() throws Exception {
-        assertThrowsOnInit("Modified_Manifest_MainAttributes.jar");
+        verifyThrowsOnInit("Modified_Manifest_MainAttributes.jar");
     }
 
+    @Test
+    public void testJarSigning_brokenMainAttributes_FD() throws Exception {
+        verifyThrowsOnInitFD("Modified_Manifest_MainAttributes.jar");
+    }
+
+    @Test
     public void testJarSigning_brokenEntryAttributes() throws Exception {
-        assertThrowsOnInit("Modified_Manifest_EntryAttributes.jar");
+        verifyThrowsOnInit("Modified_Manifest_EntryAttributes.jar");
     }
 
+    @Test
+    public void testJarSigning_brokenEntryAttributes_FD() throws Exception {
+        verifyThrowsOnInitFD("Modified_Manifest_EntryAttributes.jar");
+    }
+
+    @Test
     public void testJarSigning_brokenSignatureFile() throws Exception {
-        assertThrowsOnInit("Modified_SF_EntryAttributes.jar");
+        verifyThrowsOnInit("Modified_SF_EntryAttributes.jar");
     }
 
+    @Test
+    public void testJarSigning_brokenSignatureFile_FD() throws Exception {
+        verifyThrowsOnInitFD("Modified_SF_EntryAttributes.jar");
+    }
+
+    @Test
     public void testJarSigning_removedEntry() throws Exception {
-        assertThrowsOnInit("removed.jar");
+        verifyThrowsOnInit("removed.jar");
     }
 
-    private void assertThrowsOnInit(String name) throws Exception {
-      copyFile(name);
+    @Test
+    public void testJarSigning_removedEntry_FD() throws Exception {
+        verifyThrowsOnInitFD("removed.jar");
+    }
+
+    private void verifyThrowsOnInit(String name) throws Exception {
+        copyFile(name);
         try {
-            StrictJarFile jarFile = new StrictJarFile(
-                    new File(resources,  name).getAbsolutePath());
+            new StrictJarFile(new File(mResourcesFile,  name).getAbsolutePath());
             fail();
         } catch (SecurityException expected) {
         }
     }
 
+    private void verifyThrowsOnInitFD(String name) throws Exception {
+        copyFile(name);
+        FileDescriptor fd = IoBridge.open(
+                new File(mResourcesFile, name).getAbsolutePath(),
+                        OsConstants.O_RDONLY);
+        try {
+            new StrictJarFile(fd);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
 
-    public File copyFile(String file) {
-        File dest = new File(resources.toString() + "/" + file);
+    private File copyFile(String file) {
+        File dest = new File(mResourcesFile.toString() + "/" + file);
 
         if (!dest.exists()) {
             try {
-                InputStream in = getContext().getAssets().open(file);
+                InputStream in = InstrumentationRegistry.getTargetContext().getAssets().open(file);
                 FileOutputStream out = new FileOutputStream(dest);
                 byte[] buffer = new byte[8192];
                 int c;
@@ -211,8 +366,8 @@
                 dest.deleteOnExit();
                 in.close();
             } catch (IOException e) {
-                throw new RuntimeException(
-                                           "Unable to copy file from resource " + file + " to file " + dest, e);
+                throw new RuntimeException("Unable to copy file from resource " + file
+                        + " to file " + dest, e);
             }
         }
         return dest;
diff --git a/tests/tests/util/src/android/util/cts/StringBuilderPrinterTest.java b/tests/tests/util/src/android/util/cts/StringBuilderPrinterTest.java
index c45f369..17e4603 100644
--- a/tests/tests/util/src/android/util/cts/StringBuilderPrinterTest.java
+++ b/tests/tests/util/src/android/util/cts/StringBuilderPrinterTest.java
@@ -15,10 +15,20 @@
  */
 package android.util.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.StringBuilderPrinter;
 
-public class StringBuilderPrinterTest extends AndroidTestCase{
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StringBuilderPrinterTest {
+    @Test
     public void testStringBuilderPrinter(){
         StringBuilder strBuilder = new StringBuilder("Hello");
         StringBuilderPrinter strBuilderPrinter = new StringBuilderPrinter(strBuilder);
diff --git a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
index 3176316..3362caf 100644
--- a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
+++ b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
@@ -15,14 +15,22 @@
  */
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.TimeUtils;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Calendar;
 import java.util.TimeZone;
 
-import junit.framework.TestCase;
-
-public class TimeUtilsTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimeUtilsTest {
+    @Test
     public void testUnitedStates() throws Exception {
         String[] mainstream = new String[] {
             "America/New_York", // Eastern
@@ -48,6 +56,7 @@
         }
     }
 
+    @Test
     public void testWeirdUnitedStates() throws Exception {
         String[] weird = new String[] {
             "America/Phoenix", // Mountain, no DST
@@ -65,6 +74,7 @@
         }
     }
 
+    @Test
     public void testOld() throws Exception {
         String[] old = new String[] {
             "America/Indiana/Indianapolis", // Eastern, formerly no DST
@@ -81,6 +91,7 @@
         }
     }
 
+    @Test
     public void testWorldWeird() throws Exception {
         String[] world = new String[] {
             // Distinguisable from Sydney only when DST not in effect
@@ -108,6 +119,7 @@
                                      country);
     }
 
+    @Test
     public void testFormatDuration() {
         assertFormatDuration("0", 0);
         assertFormatDuration("-1ms", -1);
@@ -124,6 +136,7 @@
         assertFormatDuration("+1d0h0m0s30ms", 86400030);
     }
 
+    @Test
     public void testFormatHugeDuration() {
         assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
         assertFormatDuration("-15542d1h11m11s555ms", -1342833071555L);
diff --git a/tests/tests/util/src/android/util/cts/TimingLoggerTest.java b/tests/tests/util/src/android/util/cts/TimingLoggerTest.java
index 4fab540..98f709e 100644
--- a/tests/tests/util/src/android/util/cts/TimingLoggerTest.java
+++ b/tests/tests/util/src/android/util/cts/TimingLoggerTest.java
@@ -16,13 +16,20 @@
 package android.util.cts;
 
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.TimingLogger;
 
-public class TimingLoggerTest extends AndroidTestCase{
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TimingLoggerTest {
     private static final String LOG_TAG = "TimingLoggerTest";
     private static final int SLEEPING_MSEC = 100;
 
+    @Test
     public void testTimingLogger() {
         TimingLogger timings = new TimingLogger(LOG_TAG, "testTimingLogger");
 
@@ -34,7 +41,7 @@
             }
 
             sleep();
-            timings.addSplit("fisrt sleep");
+            timings.addSplit("first sleep");
 
             sleep();
             timings.addSplit("second sleep");
diff --git a/tests/tests/util/src/android/util/cts/TypedValueTest.java b/tests/tests/util/src/android/util/cts/TypedValueTest.java
index 2ab91d9..9c454e4 100644
--- a/tests/tests/util/src/android/util/cts/TypedValueTest.java
+++ b/tests/tests/util/src/android/util/cts/TypedValueTest.java
@@ -16,24 +16,35 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
-import junit.framework.TestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 
-public class TypedValueTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TypedValueTest {
+    @Test
     public void testConstructor() {
         new TypedValue();
     }
 
+    @Test
     public void testGetFloat() {
-        final float EXPECTED = Float.intBitsToFloat(99);
+        final float expected = Float.intBitsToFloat(99);
         TypedValue tv = new TypedValue();
         tv.data = 99;
-        assertEquals(EXPECTED, tv.getFloat());
+        assertEquals(expected, tv.getFloat(), 0.0f);
     }
 
+    @Test
     public void testComplexToDimension() {
         DisplayMetrics dm = new DisplayMetrics();
         dm.density = 1.1f;
@@ -41,13 +52,14 @@
         dm.scaledDensity = 2.1f;
         dm.xdpi = 200f;
         dm.ydpi = 300f;
-        final float EXPECTED = TypedValue.applyDimension((10 >> TypedValue.COMPLEX_UNIT_SHIFT)
+        final float expected = TypedValue.applyDimension((10 >> TypedValue.COMPLEX_UNIT_SHIFT)
                 & TypedValue.COMPLEX_UNIT_MASK, TypedValue.complexToFloat(10), dm);
 
-        assertEquals(EXPECTED, TypedValue.complexToDimension(10, dm));
-        assertEquals((int)EXPECTED, TypedValue.complexToDimensionPixelOffset(10, dm));
+        assertEquals(expected, TypedValue.complexToDimension(10, dm), 0.0f);
+        assertEquals((int)expected, TypedValue.complexToDimensionPixelOffset(10, dm));
     }
 
+    @Test
     public void testSetTo() {
         TypedValue tv1 = new TypedValue();
         TypedValue tv2 = new TypedValue();
@@ -68,14 +80,16 @@
         assertEquals(5, tv2.type);
     }
 
+    @Test
     public void testGetFraction() {
         // set the expected value
-        final float EXPECTED = TypedValue.complexToFraction(10, 1.1f, 2.1f) ;
+        final float expected = TypedValue.complexToFraction(10, 1.1f, 2.1f) ;
         TypedValue tv = new TypedValue();
         tv.data = 10;
-        assertEquals(EXPECTED, tv.getFraction(1.1f, 2.1f));
+        assertEquals(expected, tv.getFraction(1.1f, 2.1f), 0.0f);
     }
 
+    @Test
     public void testComplexToDimensionPixelSize() {
         DisplayMetrics dm = new DisplayMetrics();
         dm.density = 1.1f;
@@ -95,8 +109,8 @@
 
     }
 
+    @Test
     public void testComplexToFraction() {
-
         final int data1 = 1;
         final float base1 = 1.1f;
         final float pbase1 = 2.2f;
@@ -106,12 +120,12 @@
         final float base2 = 1.1f;
         final float pbase2 = 2.2f;
         final float expected2 = 0.013092041f;
-        assertEquals(expected1, TypedValue.complexToFraction(data1, base1, pbase1));
-        assertEquals(expected2, TypedValue.complexToFraction(data2, base2, pbase2));
+        assertEquals(expected1, TypedValue.complexToFraction(data1, base1, pbase1), 0.0f);
+        assertEquals(expected2, TypedValue.complexToFraction(data2, base2, pbase2), 0.0f);
     }
 
+    @Test
     public void testToString() {
-
         TypedValue tv = new TypedValue();
         tv.assetCookie = 1;
         tv.changingConfigurations = 2;
@@ -125,6 +139,7 @@
         assertNotNull(tv.toString());
     }
 
+    @Test
     public void testApplyDimension() {
         DisplayMetrics dm = new DisplayMetrics();
         dm.density = 1.1f;
@@ -133,20 +148,22 @@
         dm.xdpi = 200f;
         dm.ydpi = 300f;
 
-        assertEquals(10.0f, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 10, dm));
+        assertEquals(10.0f, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 10, dm), 0.0f);
         assertEquals(10 * dm.density, TypedValue
-                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, dm));
+                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, dm), 0.0f);
         assertEquals(10 * dm.scaledDensity, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
-                10, dm));
+                10, dm), 0.0f);
         assertEquals(10 * dm.xdpi * (1.0f/72),
-                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, 10, dm));
-        assertEquals(10 * dm.xdpi, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_IN, 10, dm));
+                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, 10, dm), 0.0f);
+        assertEquals(10 * dm.xdpi, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_IN, 10, dm),
+                0.0f);
         assertEquals(10 * dm.xdpi * (1.0f / 25.4f), TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_MM, 10, dm));
+                TypedValue.COMPLEX_UNIT_MM, 10, dm), 0.0f);
 
-        assertEquals(0.0f, TypedValue.applyDimension(-1, 10, dm));
+        assertEquals(0.0f, TypedValue.applyDimension(-1, 10, dm), 0.0f);
     }
 
+    @Test
     public void testCoerceToString1() {
         TypedValue tv = new TypedValue();
         tv.assetCookie = 1;
@@ -162,6 +179,7 @@
         assertNotNull(tv.coerceToString());
     }
 
+    @Test
     public void testCoerceToString2() {
         assertNull(TypedValue.coerceToString(TypedValue.TYPE_NULL, 10));
         assertNotNull(TypedValue.coerceToString(TypedValue.TYPE_REFERENCE, 10));
@@ -178,19 +196,20 @@
         assertNull(TypedValue.coerceToString(-1, 10));
     }
 
+    @Test
     public void testComplexToFloat() {
-
         final int complex1 = 1;
         final float expected1 = 0.0f;
         final int complex2 = 17;
         final float expected2 = 0.0f;
         final int complex3 = 9999;
         final float expected3 = 39.0f;
-        assertEquals(expected1, TypedValue.complexToFloat(complex1));
-        assertEquals(expected2, TypedValue.complexToFloat(complex2));
-        assertEquals(expected3, TypedValue.complexToFloat(complex3));
+        assertEquals(expected1, TypedValue.complexToFloat(complex1), 0.0f);
+        assertEquals(expected2, TypedValue.complexToFloat(complex2), 0.0f);
+        assertEquals(expected3, TypedValue.complexToFloat(complex3), 0.0f);
     }
 
+    @Test
     public void testGetDimension() {
         DisplayMetrics dm = new DisplayMetrics();
         dm.density = 1.1f;
@@ -203,6 +222,27 @@
         tv.data = 10;
         tv.getDimension(dm);
 
-        assertEquals(TypedValue.complexToDimension(10, dm), tv.getDimension(dm));
+        assertEquals(TypedValue.complexToDimension(10, dm), tv.getDimension(dm), 0.0f);
+    }
+
+    @Test
+    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/util/src/android/util/cts/XmlEncodingTest.java b/tests/tests/util/src/android/util/cts/XmlEncodingTest.java
index 4c0c34b..8ce6b5f 100644
--- a/tests/tests/util/src/android/util/cts/XmlEncodingTest.java
+++ b/tests/tests/util/src/android/util/cts/XmlEncodingTest.java
@@ -16,25 +16,32 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Xml;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Vector;
-
-import junit.framework.TestCase;
-
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Vector;
+
 
 /**
  * TestCases for android.util.Xml.Encoding.
  */
 //FIXME: This is a duplicated testcase. Need to improve the coverage tool in future.
-public class XmlEncodingTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class XmlEncodingTest {
 
     private static final String STR_ISO_8859_1 = "ISO-8859-1";
     private static final String STR_US_ASCII = "US-ASCII";
@@ -68,8 +75,8 @@
     private static final String STR_START_TAG = "start:";
     private static final String STR_CHARACTERS_TAG = "characters:";
 
+    @Test
     public void testValueOf() {
-
         // test US-ASCII
         DefaultContentHandler dc = new DefaultContentHandler();
         try {
@@ -201,7 +208,7 @@
 
     class DefaultContentHandler implements ContentHandler {
 
-        public Vector<String> mVec = new Vector<String>();
+        public Vector<String> mVec = new Vector<>();
 
         public void characters(char[] ch, int start, int length) throws SAXException {
             mVec.add(STR_CHARACTERS_TAG + new String(ch));
diff --git a/tests/tests/util/src/android/util/cts/XmlTest.java b/tests/tests/util/src/android/util/cts/XmlTest.java
index 66918ce..400c141 100644
--- a/tests/tests/util/src/android/util/cts/XmlTest.java
+++ b/tests/tests/util/src/android/util/cts/XmlTest.java
@@ -16,6 +16,19 @@
 
 package android.util.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.res.XmlResourceParser;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
@@ -24,28 +37,21 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
-import android.util.Xml.Encoding;
-
-
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.Vector;
 
 /**
  * TestCase for android.util.Xml.
  */
-public class XmlTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class XmlTest {
 
     private static final String STR_INVALIDATE_EN_CODING = "invalidateEnCoding";
     private static final String STR_N2 = "-2";
@@ -84,6 +90,7 @@
     final String sourceStr = "<" + TAG_TEST + "><" + TAG_SON + " " + ATT_NAME + "=\"" + STR_ABC
             + "\"/></" + TAG_TEST + ">";
 
+    @Test
     public void testParseStringContentHandler() {
         final String xmlStr = "<Test><Son name=\"abc\"/></Test>";
         DefaultContentHandler dc = new DefaultContentHandler();
@@ -118,7 +125,7 @@
 
     class DefaultContentHandler implements ContentHandler {
 
-        public Vector<String> mVec = new Vector<String>();
+        public Vector<String> mVec = new Vector<>();
 
         public void characters(char[] ch, int start, int length) throws SAXException {
             mVec.add(STR_CHARACTERS_TAG + new String(ch));
@@ -183,6 +190,7 @@
 
     }
 
+    @Test
     public void testParseReaderContentHander() {
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
         DataOutputStream dout = new DataOutputStream(bout);
@@ -231,8 +239,8 @@
         }
     }
 
+    @Test
     public void testParseInputStreamEncodingContentHandler() {
-
         // test US-ASCII
         DefaultContentHandler dc = new DefaultContentHandler();
         try {
@@ -362,6 +370,7 @@
         }
     }
 
+    @Test
     public void testNewSerializer() {
         XmlSerializer xs = Xml.newSerializer();
         assertNotNull(xs);
@@ -370,6 +379,7 @@
         assertNotNull(xp);
     }
 
+    @Test
     public void testFindEncodingByName() {
 
         try {
@@ -389,9 +399,10 @@
         }
     }
 
+    @Test
     public void testAsAttributeSet() {
-        XmlResourceParser xp = getContext().getResources().getLayout(
-                android.util.cts.R.layout.xml_test);
+        XmlResourceParser xp = InstrumentationRegistry.getTargetContext().getResources().getLayout(
+                R.layout.xml_test);
         int eventType = -1;
         try {
             eventType = xp.getEventType();
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index ba4be93..9b505dd 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 := \
-    ctsdeviceutil \
+    android-support-test \
+    compatibility-device-util \
     ctstestrunner \
-    mockito-target \
-    ub-uiautomator \
-    android-support-test
+    mockito-target-minus-junit4 \
+    platform-test-annotations \
+    ub-uiautomator
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 43a448a..4d181e8 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -25,10 +25,9 @@
                 android:icon="@drawable/size_48x48"
                 android:maxRecents="1"
                 android:multiArch="true"
-                android:name="android.view.cts.MockApplication"
                 android:supportsRtl="true">
         <uses-library android:name="android.test.runner" />
-        
+
         <activity android:name="android.view.cts.ViewStubCtsActivity"
             android:label="ViewStubCtsActivity">
             <intent-filter>
@@ -36,7 +35,7 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.cts.UsingViewsCtsActivity"
             android:label="Using Views Test">
             <intent-filter>
@@ -44,7 +43,7 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.cts.FocusHandlingCtsActivity"
             android:label="Focus Handling Test">
             <intent-filter>
@@ -52,14 +51,14 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.cts.ViewGroupCtsActivity" android:label="ViewGroupCtsActivity">
             <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.view.cts.ViewTestCtsActivity"
             android:label="ViewTestCtsActivity">
             <intent-filter>
@@ -67,7 +66,7 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.cts.ViewLayoutPositionTestCtsActivity"
             android:label="ViewTestCtsActivity">
             <intent-filter>
@@ -84,7 +83,7 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.animation.cts.AnimationTestCtsActivity"
             android:label="AnimationTestCtsActivity" android:configChanges="orientation|screenSize">
             <intent-filter>
@@ -108,7 +107,7 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
-        
+
         <activity android:name="android.view.inputmethod.cts.InputMethodCtsActivity"
             android:label="InputMethodCtsActivity">
             <intent-filter>
@@ -125,14 +124,6 @@
                 android:resource="@xml/method" />
         </service>
 
-        <activity android:name="android.view.cts.MenuInflaterCtsActivity"
-            android:label="MenuInflaterCtsActivity">
-            <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.view.cts.SurfaceViewCtsActivity"
             android:label="SurfaceViewCtsActivity">
             <intent-filter>
@@ -150,12 +141,14 @@
         </activity>
 
         <activity android:name="android.view.cts.PixelCopyVideoSourceActivity"
-            android:label="PixelCopyVideoSourceActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
+                android:label="PixelCopyVideoSourceActivity" />
+
+        <activity android:name="android.view.cts.PixelCopyGLProducerCtsActivity"
+                android:label="PixelCopyGLProducerCtsActivity"/>
+
+        <activity android:name="android.view.cts.PixelCopyViewProducerActivity"
+                android:label="PixelCopyViewProducerActivity"
+                android:theme="@android:style/Theme.DeviceDefault.NoActionBar" />
 
         <activity android:name="android.view.cts.FocusFinderCtsActivity"
             android:label="FocusFinderCtsActivity">
@@ -173,8 +166,8 @@
             android:label="ScaleGestureDetectorCtsActivity"
             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
 
-        <activity android:name="android.view.cts.GLSurfaceViewCtsActivity"
-            android:label="GLSurfaceViewCts"/>
+        <activity android:name="android.view.cts.DisplayRefreshRateCtsActivity"
+                  android:label="DisplayRefreshRateCtsActivity"/>
 
         <activity android:name="android.view.cts.MockActivity" android:label="MockActivity">
             <meta-data android:name="android.view.merge"
@@ -241,6 +234,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.view.cts.PanicPressBackActivity"
+                  android:label="PanicPressBackActivity">
+            <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.view.cts.DragDropActivity"
                   android:label="DragDropActivity">
             <intent-filter>
@@ -250,7 +251,6 @@
         </activity>
 
         <activity android:name="android.view.cts.surfacevalidator.CapturedActivity"
-            android:configChanges="orientation|screenSize"
             android:screenOrientation="portrait"
             android:theme="@style/WhiteBackgroundTheme">
             <intent-filter>
@@ -258,6 +258,22 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity android:name="android.view.cts.HoverCtsActivity"
+                  android:theme="@style/WhiteBackgroundTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.view.cts.TooltipActivity"
+                  android:label="TooltipActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
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/res/layout/hover_layout.xml b/tests/tests/view/res/layout/hover_layout.xml
new file mode 100644
index 0000000..08bbede
--- /dev/null
+++ b/tests/tests/view/res/layout/hover_layout.xml
@@ -0,0 +1,114 @@
+<?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/top"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+            android:id="@+id/outer"
+            android:orientation="vertical"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:background="#eee">
+
+        <LinearLayout
+                android:id="@+id/middle1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/hover_target_margin"
+                android:background="#ddd">
+
+            <LinearLayout
+                    android:id="@+id/inner11"
+                    android:layout_width="@dimen/hover_target_size"
+                    android:layout_height="@dimen/hover_target_size"
+                    android:layout_margin="@dimen/hover_target_margin"
+                    android:background="#bbb"/>
+
+            <TextView
+                    android:id="@+id/inner12"
+                    android:layout_width="wrap_content"
+                    android:layout_height="@dimen/hover_target_size"
+                    android:layout_margin="@dimen/hover_target_margin"
+                    android:text="Text"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+                android:id="@+id/middle2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="@dimen/hover_target_margin"
+                android:background="#ddd">
+
+            <LinearLayout
+                    android:id="@+id/inner21"
+                    android:layout_width="@dimen/hover_target_size"
+                    android:layout_height="@dimen/hover_target_size"
+                    android:layout_margin="@dimen/hover_target_margin"
+                    android:background="#bbb"/>
+
+            <TextView
+                    android:id="@+id/inner22"
+                    android:layout_width="wrap_content"
+                    android:layout_height="@dimen/hover_target_size"
+                    android:layout_margin="@dimen/hover_target_margin"
+                    android:text="Text"/>
+
+        </LinearLayout>
+
+        <RelativeLayout
+                android:id="@+id/overlapping"
+                android:layout_width="@dimen/hover_target_size_double"
+                android:layout_height="@dimen/hover_target_size"
+                android:layout_margin="@dimen/hover_target_margin"
+                android:background="#ddd">
+
+            <View
+                    android:id="@+id/layer1"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+
+            <View
+                    android:id="@+id/layer2"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+
+            <View
+                    android:id="@+id/layer3"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+
+            <View
+                    android:id="@+id/layer4_left"
+                    android:layout_width="@dimen/hover_target_size"
+                    android:layout_height="match_parent"/>
+
+            <View
+                    android:id="@+id/layer4_right"
+                    android:layout_width="@dimen/hover_target_size"
+                    android:layout_height="match_parent"
+                    android:layout_toRightOf="@+id/layer4_left" />
+
+        </RelativeLayout>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/tests/view/res/layout/scrollview_layout.xml b/tests/tests/view/res/layout/scrollview_layout.xml
index c5b7b43..8c3cb8e 100644
--- a/tests/tests/view/res/layout/scrollview_layout.xml
+++ b/tests/tests/view/res/layout/scrollview_layout.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<android.view.cts.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/scroll_view"
     android:layout_width="100dip"
     android:layout_height="100dip">
@@ -102,4 +103,4 @@
             android:text="@string/vertical_text_3"/>
     </LinearLayout>
 
-</android.view.cts.MyScrollView>
+</ScrollView>
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/res/layout/tooltip_layout.xml b/tests/tests/view/res/layout/tooltip_layout.xml
new file mode 100644
index 0000000..8291b31
--- /dev/null
+++ b/tests/tests/view/res/layout/tooltip_layout.xml
@@ -0,0 +1,60 @@
+<?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/tooltip_layout"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+            android:id="@+id/tooltip_group"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+        <TextView
+                android:id="@+id/no_tooltip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="View with no tooltip"/>
+
+        <TextView
+                android:id="@+id/has_tooltip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="View with tooltip"
+                android:tooltip="tooltip text"/>
+
+    </LinearLayout>
+
+    <TextView
+            android:id="@+id/no_tooltip2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Another view with no tooltip"/>
+
+    <LinearLayout
+            android:id="@+id/empty_group"
+            android:layout_width="100dp"
+            android:layout_height="30dp"
+            android:layout_margin="10dp"
+            android:background="#ddd"/>
+
+</LinearLayout>
diff --git a/tests/tests/view/res/layout/view_padding.xml b/tests/tests/view/res/layout/view_padding.xml
new file mode 100644
index 0000000..e3b0deb
--- /dev/null
+++ b/tests/tests/view/res/layout/view_padding.xml
@@ -0,0 +1,148 @@
+<?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">
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view1"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:padding="@dimen/insetAll"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view2"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingLeft="@dimen/insetLeft"
+            android:paddingTop="@dimen/insetTop"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view3"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingRight="@dimen/insetRight"
+            android:paddingBottom="@dimen/insetBottom"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view4"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingLeft="@dimen/insetLeft"
+            android:paddingTop="@dimen/insetTop"
+            android:paddingRight="@dimen/insetRight"
+            android:paddingBottom="@dimen/insetBottom"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view5"/>
+    </LinearLayout>
+
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/insetHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view6"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingVertical="@dimen/insetVertical"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view7"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/insetHorizontal"
+            android:paddingVertical="@dimen/insetVertical"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view8"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/insetHorizontal"
+            android:paddingVertical="@dimen/insetVertical"
+            android:paddingLeft="0dp"
+            android:paddingTop="0dp"
+            android:paddingRight="0dp"
+            android:paddingBottom="0dp"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view9"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:padding="@dimen/insetAll"
+            android:paddingLeft="0dp"
+            android:paddingTop="0dp"
+            android:paddingRight="0dp"
+            android:paddingBottom="0dp"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view10"/>
+    </LinearLayout>
+
+</LinearLayout>
+
diff --git a/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml b/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml
new file mode 100644
index 0000000..a1c4051
--- /dev/null
+++ b/tests/tests/view/res/layout/viewgroup_margin_layout_verticalhorizontal.xml
@@ -0,0 +1,98 @@
+<?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">
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/view1"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="10dp"
+                android:id="@+id/view2"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginVertical="10dp"
+                android:id="@+id/view3"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="10dp"
+                android:layout_marginVertical="10dp"
+                android:id="@+id/view4"/>
+    </LinearLayout>
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="10dp"
+                android:layout_marginLeft="5dp"
+                android:layout_marginRight="2dp"
+                android:layout_marginVertical="10dp"
+                android:layout_marginTop="5dp"
+                android:layout_marginBottom="2dp"
+                android:id="@+id/view5"/>
+    </LinearLayout>
+
+
+    <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="100dp">
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="10dp"
+                android:layout_marginStart="5dp"
+                android:layout_marginEnd="2dp"
+                android:layout_marginVertical="10dp"
+                android:id="@+id/view6"/>
+    </LinearLayout>
+
+</LinearLayout>
+
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
index 16e5084..59369a7 100644
--- a/tests/tests/view/res/values/dimens.xml
+++ b/tests/tests/view/res/values/dimens.xml
@@ -20,4 +20,14 @@
     <dimen name="reset_state_value">50dp</dimen>
     <!-- this value is equal to the value in changing_state_list_animator. It is NOT referenced in the XML on purpose-->
     <dimen name="changing_state_list_anim_target_x_value">100dp</dimen>
+    <dimen name="insetLeft">5dp</dimen>
+    <dimen name="insetTop">6dp</dimen>
+    <dimen name="insetRight">7dp</dimen>
+    <dimen name="insetBottom">8dp</dimen>
+    <dimen name="insetAll">9dp</dimen>
+    <dimen name="insetHorizontal">10dp</dimen>
+    <dimen name="insetVertical">11dp</dimen>
+    <dimen name="hover_target_margin">4dp</dimen>
+    <dimen name="hover_target_size">8dp</dimen>
+    <dimen name="hover_target_size_double">16dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
index 440e390..926d707 100644
--- a/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AccelerateDecelerateInterpolatorTest.java
@@ -16,12 +16,17 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -31,25 +36,34 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
+import android.view.cts.R;
 
-public class AccelerateDecelerateInterpolatorTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AccelerateDecelerateInterpolatorTest {
     private static final float ALPHA_DELTA = 0.001f;
     /** It is defined in R.anim.accelarate_decelerate_alpha */
     private static final long ALPHA_DURATION = 2000;
 
-    public AccelerateDecelerateInterpolatorTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new AccelerateDecelerateInterpolator();
 
@@ -59,7 +73,8 @@
         new AccelerateDecelerateInterpolator(mActivity, attrs);
     }
 
-    public void testAccelerateDecelerateInterpolator() {
+    @Test
+    public void testAccelerateDecelerateInterpolator() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
 
         // XML file of R.anim.accelerate_decelerate_alpha
@@ -74,7 +89,7 @@
         assertTrue(anim instanceof AlphaAnimation);
         assertFalse(anim.hasStarted());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         Transformation transformation = new Transformation();
         long startTime = anim.getStartTime();
@@ -105,6 +120,7 @@
         assertTrue(delta3 > delta4);
     }
 
+    @Test
     public void testGetInterpolation() {
         Interpolator interpolator = new AccelerateDecelerateInterpolator();
 
diff --git a/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
index b2be24d..92fa08d 100644
--- a/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AccelerateInterpolatorTest.java
@@ -16,12 +16,17 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -31,26 +36,35 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
+import android.view.cts.R;
 
-public class AccelerateInterpolatorTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    public AccelerateInterpolatorTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
-    }
-
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AccelerateInterpolatorTest {
     private static final float ALPHA_DELTA = 0.001f;
 
     /** It is defined in R.anim.accelerate_alpha */
     private static final long ACCELERATE_ALPHA_DURATION = 1000;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
+    @Test
     public void testConstructor() {
         new AccelerateInterpolator();
 
@@ -61,7 +75,8 @@
         new AccelerateInterpolator(mActivity, attrs);
     }
 
-    public void testAccelerateInterpolator() {
+    @Test
+    public void testAccelerateInterpolator() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
 
         // XML file of R.anim.accelerate_alpha
@@ -80,7 +95,7 @@
         anim.setInterpolator(interpolator);
         assertFalse(anim.hasStarted());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         Transformation transformation = new Transformation();
         long startTime = anim.getStartTime();
@@ -114,7 +129,7 @@
         interpolator = new AccelerateInterpolator(1.5f);
         anim.setInterpolator(interpolator);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         transformation = new Transformation();
         startTime = anim.getStartTime();
@@ -148,6 +163,7 @@
         assertTrue(delta5 < delta1);
     }
 
+    @Test
     public void testGetInterpolation() {
         final float input = 0.25f;
         Interpolator interpolator1 = new AccelerateInterpolator(1.0f);
diff --git a/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
index 45eb418..605a339 100644
--- a/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AlphaAnimationTest.java
@@ -16,19 +16,38 @@
 
 package android.view.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Transformation;
-
 import android.view.cts.R;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link AlphaAnimation}.
  */
-public class AlphaAnimationTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlphaAnimationTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() {
         XmlResourceParser parser = mContext.getResources().getAnimation(R.anim.alpha);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -37,16 +56,19 @@
         new AlphaAnimation(0.0f, 1.0f);
     }
 
+    @Test
     public void testWillChangeBounds() {
         AlphaAnimation animation = new AlphaAnimation(mContext, null);
         assertFalse(animation.willChangeBounds());
     }
 
+    @Test
     public void testWillChangeTransformationMatrix() {
         AlphaAnimation animation = new AlphaAnimation(0.0f, 0.5f);
         assertFalse(animation.willChangeTransformationMatrix());
     }
 
+    @Test
     public void testApplyTransformation() {
         MyAlphaAnimation animation = new MyAlphaAnimation(0.0f, 1.0f);
         Transformation transformation = new Transformation();
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
index 49c51e0..36846f3 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationSetTest.java
@@ -16,12 +16,19 @@
 
 package android.view.animation.cts;
 
-import java.util.List;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.content.Context;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -32,13 +39,18 @@
 import android.view.animation.ScaleAnimation;
 import android.view.animation.Transformation;
 import android.view.animation.TranslateAnimation;
-
 import android.view.cts.R;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class AnimationSetTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+import java.util.List;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimationSetTest {
     private static final float DELTA = 0.001f;
     private static final long SHORT_CHILD_DURATION = 400;
     private static final long MEDIUM_CHILD_DURATION = 800;
@@ -48,18 +60,21 @@
      */
     private static final int INITIAL_SIZE = 100;
     private static final long ANIMATIONSET_DURATION = 1000;
+
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
-    public AnimationSetTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new AnimationSet(true);
 
@@ -71,6 +86,7 @@
         new AnimationSet(mActivity, attr);
     }
 
+    @Test
     public void testInitialize() {
         final AnimationSet animationSet = createAnimationSet();
         animationSet.setDuration(ANIMATIONSET_DURATION);
@@ -108,6 +124,7 @@
         return animationSet;
     }
 
+    @Test
     public void testSetFillAfter() {
         final AnimationSet animationSet = createAnimationSet();
         assertFalse(animationSet.getFillAfter());
@@ -125,6 +142,7 @@
         }
     }
 
+    @Test
     public void testSetFillBefore() {
         final AnimationSet animationSet = createAnimationSet();
         assertTrue(animationSet.getFillBefore());
@@ -142,6 +160,7 @@
         }
     }
 
+    @Test
     public void testAccessDuration() {
         final AnimationSet animationSet = createAnimationSet();
         assertEquals(LONG_CHILD_DURATION, animationSet.getDuration());
@@ -156,6 +175,7 @@
         }
     }
 
+    @Test
     public void testRestrictDuration() {
         final AnimationSet animationSet = new AnimationSet(false);
         Animation child = null;
@@ -188,6 +208,7 @@
         assertTrue(originChildRepeatCount[2] > children.get(2).getRepeatCount());
     }
 
+    @Test
     public void testComputeDurationHint() {
         final AnimationSet animationSet = createAnimationSet();
         final List<Animation> children = animationSet.getAnimations();
@@ -198,6 +219,7 @@
         assertEquals(expectedDuration, animationSet.computeDurationHint());
     }
 
+    @Test
     public void testScaleCurrentDuration() {
         final AnimationSet animationSet = createAnimationSet();
         List<Animation> children = animationSet.getAnimations();
@@ -214,6 +236,7 @@
         }
     }
 
+    @Test
     public void testAccessRepeatMode() {
         final AnimationSet animationSet = createAnimationSet();
         animationSet.setRepeatMode(Animation.RESTART);
@@ -233,6 +256,7 @@
         }
     }
 
+    @Test
     public void testAccessStartOffset() {
         final AnimationSet animationSet = createAnimationSet();
         assertEquals(0, animationSet.getStartOffset());
@@ -260,6 +284,7 @@
         }
     }
 
+    @Test
     public void testAccessStartTime() {
         final AnimationSet animationSet = createAnimationSet();
         final long[] originChildStartTime = {1000, 2000, 3000};
@@ -281,7 +306,8 @@
         }
     }
 
-    public void testGetTransformation() {
+    @Test
+    public void testGetTransformation() throws Throwable {
         final View animWindowParent = mActivity.findViewById(R.id.anim_window_parent);
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final AnimationSet animationSet = createAnimationSet();
@@ -289,7 +315,8 @@
         animationSet.initialize(animWindow.getWidth(), animWindow.getHeight(),
                 animWindowParent.getWidth(), animWindowParent.getHeight());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, animationSet);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                animationSet);
         final long startTime = animationSet.getStartTime();
 
         assertGetTransformation(animationSet, startTime, true);
@@ -325,6 +352,7 @@
         }
     }
 
+    @Test
     public void testAccessAnimations() {
         final AnimationSet animationSet = new AnimationSet(true);
         final Animation animation1 = new AlphaAnimation(0.0f, 1.0f);
@@ -341,6 +369,7 @@
         assertSame(animation3, children.get(2));
     }
 
+    @Test
     public void testWillChangeTransformationMatrix() {
         final AnimationSet animationSet = new AnimationSet(true);
         assertFalse(animationSet.willChangeTransformationMatrix());
@@ -358,6 +387,7 @@
         assertTrue(animationSet.willChangeBounds());
     }
 
+    @Test
     public void testClone() throws CloneNotSupportedException {
         final MyAnimationSet animationSet = new MyAnimationSet(false);
         final Animation alpha = new AlphaAnimation(0.0f, 1.0f);
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
index a465824..c47b4b1 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
@@ -16,24 +16,49 @@
 
 package android.view.animation.cts;
 
-import android.view.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.assertNotSame;
+import static org.junit.Assert.assertNull;
+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.never;
+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.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
-import android.view.animation.Animation.AnimationListener;
+import android.view.cts.R;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+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;
@@ -41,28 +66,31 @@
 /**
  * Test {@link Animation}.
  */
-public class AnimationTest extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-    private static final float ALPHA_DELTA = 0.001f;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimationTest {
+    private static final float COMPARISON_DELTA = 0.001f;
 
     /** It is defined in R.anim.accelerate_alpha */
-    private static final long ACCELERATE_ALPHA_DURATION = 1000;
+    private static final int ACCELERATE_ALPHA_DURATION = 1000;
 
     /** It is defined in R.anim.decelerate_alpha */
-    private static final long DECELERATE_ALPHA_DURATION = 2000;
+    private static final int DECELERATE_ALPHA_DURATION = 2000;
 
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
-    private Object mLockObject = new Object();
 
-    public AnimationTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         XmlResourceParser parser = mActivity.getResources().getAnimation(R.anim.alpha);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -73,6 +101,7 @@
         };
     }
 
+    @Test
     public void testAccessInterpolator() {
         // check default interpolator
         MyAnimation myAnimation = new MyAnimation();
@@ -99,6 +128,7 @@
         assertTrue(interpolator instanceof AccelerateInterpolator);
     }
 
+    @Test
     public void testDefaultFill() {
         Animation animation = new Animation() {
         };
@@ -106,7 +136,8 @@
         assertFalse(animation.getFillAfter());
     }
 
-    public void testAccessFill() {
+    @Test
+    public void testAccessFill() throws Throwable {
         View animWindow = mActivity.findViewById(R.id.anim_window);
         // XML file of R.anim.accelerate_alpha
         // <alpha xmlns:android="http://schemas.android.com/apk/res/android"
@@ -119,59 +150,63 @@
         assertTrue(animation.getFillBefore());
         assertFalse(animation.getFillAfter());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, animation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                animation);
 
         // fillBefore and fillAfter are ignored when fillEnabled is false
         Transformation transformation = new Transformation();
         // check alpha before start
         animation.getTransformation(animation.getStartTime() - 1, transformation);
         float alpha = transformation.getAlpha();
-        assertEquals(0.1f, alpha, ALPHA_DELTA);  // issue 1698355
+        assertEquals(0.1f, alpha, COMPARISON_DELTA);  // issue 1698355
 
         transformation = new Transformation();
         // check alpha after the end
         animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1,
                 transformation);
         alpha = transformation.getAlpha();
-        assertEquals(0.9f, alpha, ALPHA_DELTA);  // issue 1698355
+        assertEquals(0.9f, alpha, COMPARISON_DELTA);  // issue 1698355
 
         animation.setFillEnabled(true);
         animation.setFillBefore(false);
         assertTrue(animation.isFillEnabled());
         assertFalse(animation.getFillBefore());
         assertFalse(animation.getFillAfter());
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, animation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                animation);
 
         transformation = new Transformation();
         animation.getTransformation(animation.getStartTime() - 1, transformation);
         alpha = transformation.getAlpha();
-        assertEquals(1.0f, alpha, ALPHA_DELTA);
+        assertEquals(1.0f, alpha, COMPARISON_DELTA);
 
         transformation = new Transformation();
         animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1,
                 transformation);
         alpha = transformation.getAlpha();
-        assertEquals(1.0f, alpha, ALPHA_DELTA);
+        assertEquals(1.0f, alpha, COMPARISON_DELTA);
 
         animation.setFillBefore(true);
         animation.setFillAfter(true);
         assertTrue(animation.isFillEnabled());
         assertTrue(animation.getFillBefore());
         assertTrue(animation.getFillAfter());
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, animation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                animation);
 
         transformation = new Transformation();
         animation.getTransformation(animation.getStartTime() - 1, transformation);
         alpha = transformation.getAlpha();
-        assertEquals(0.1f, alpha, ALPHA_DELTA);
+        assertEquals(0.1f, alpha, COMPARISON_DELTA);
 
         transformation = new Transformation();
         animation.getTransformation(animation.getStartTime() + animation.getDuration() + 1,
                 transformation);
         alpha = transformation.getAlpha();
-        assertEquals(0.9f, alpha, ALPHA_DELTA);
+        assertEquals(0.9f, alpha, COMPARISON_DELTA);
     }
 
+    @Test
     public void testComputeDurationHint() {
         // start offset is 0, duration is 2000, repeat count is 0.
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
@@ -186,7 +221,8 @@
         assertEquals(8400, animation.computeDurationHint());
     }
 
-    public void testRepeatAnimation() {
+    @Test
+    public void testRepeatAnimation() throws Throwable {
         // check default repeatMode
         Animation animation = new Animation() {
         };
@@ -205,48 +241,34 @@
         long duration = anim.getDuration();
         assertEquals(DECELERATE_ALPHA_DURATION, duration);
         // repeat count is 0, repeat mode does not make sense.
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         // test repeat mode REVERSE
         anim.setRepeatCount(1);
         anim.setRepeatMode(Animation.REVERSE);
         // we have to PollingCheck the animation status on test thread,
-        // it cannot be done on UI thread, so we invoke runOnMainSync method here.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                animWindow.startAnimation(anim);
-            }
-        });
+        // it cannot be done on UI thread, so we invoke runOnUiThread method here.
+        mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim));
 
         // check whether animation has started
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return anim.hasStarted();
-            }
-        }.run();
+        PollingCheck.waitFor(anim::hasStarted);
 
         Transformation transformation = new Transformation();
         long startTime = anim.getStartTime();
         anim.getTransformation(startTime, transformation);
         float alpha1 = transformation.getAlpha();
-        assertEquals(0.0f, alpha1, ALPHA_DELTA);
+        assertEquals(0.0f, alpha1, COMPARISON_DELTA);
 
         anim.getTransformation(startTime + 1000, transformation);
         float alpha2 = transformation.getAlpha();
 
         anim.getTransformation(startTime + 2000, transformation);
         float alpha3 = transformation.getAlpha();
-        assertEquals(1.0f, alpha3, ALPHA_DELTA);
+        assertEquals(1.0f, alpha3, COMPARISON_DELTA);
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new PollingCheck(duration * 2 + 1000) {
-            @Override
-            protected boolean check() {
-                return anim.hasEnded();
-            }
-        }.run();
+        PollingCheck.waitFor(duration * 2 + 1000, anim::hasEnded);
 
         // get start time of reversing.
         startTime = anim.getStartTime();
@@ -255,7 +277,7 @@
 
         anim.getTransformation(startTime + 4000, transformation);
         float alpha5 = transformation.getAlpha();
-        assertEquals(0.0f, alpha5, ALPHA_DELTA);
+        assertEquals(0.0f, alpha5, COMPARISON_DELTA);
 
         // check decelerating delta alpha when reverse. alpha should change form 0.0f to 1.0f
         // and then from 1.0f to 0.0f
@@ -270,42 +292,28 @@
         // test repeat mode RESTART
         anim.setRepeatMode(Animation.RESTART);
         // we have to PollingCheck the animation status on test thread,
-        // it cannot be done on UI thread, so we invoke runOnMainSync method here.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                animWindow.startAnimation(anim);
-            }
-        });
+        // it cannot be done on UI thread, so we invoke runOnUiThread method here.
+        mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim));
 
         // check whether animation has started
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return anim.hasStarted();
-            }
-        }.run();
+        PollingCheck.waitFor(anim::hasStarted);
 
         transformation = new Transformation();
         startTime = anim.getStartTime();
         anim.getTransformation(startTime, transformation);
         alpha1 = transformation.getAlpha();
-        assertEquals(0.0f, alpha1, ALPHA_DELTA);
+        assertEquals(0.0f, alpha1, COMPARISON_DELTA);
 
         anim.getTransformation(startTime + 1000, transformation);
         alpha2 = transformation.getAlpha();
 
         anim.getTransformation(startTime + 2000, transformation);
         alpha3 = transformation.getAlpha();
-        assertEquals(1.0f, alpha3, ALPHA_DELTA);
+        assertEquals(1.0f, alpha3, COMPARISON_DELTA);
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new PollingCheck(duration * 2 + 1000) {
-            @Override
-            protected boolean check() {
-                return anim.hasEnded();
-            }
-        }.run();
+        PollingCheck.waitFor(duration * 2 + 1000, anim::hasEnded);
 
         // get start time of restarting.
         startTime = anim.getStartTime();
@@ -314,7 +322,7 @@
 
         anim.getTransformation(startTime + 4000, transformation);
         alpha5 = transformation.getAlpha();
-        assertEquals(1.0f, alpha5, ALPHA_DELTA);
+        assertEquals(1.0f, alpha5, COMPARISON_DELTA);
 
         // check decelerating delta alpha when restart. alpha should change form 0.0f to 1.0f
         // and then from 0.0f to 1.0f again
@@ -327,7 +335,8 @@
         assertTrue(delta3 > delta4);
     }
 
-    public void testAccessStartOffset() {
+    @Test
+    public void testAccessStartOffset() throws Throwable {
         final long startOffset = 800;
         // check default startOffset
         Animation animation = new Animation() {
@@ -345,24 +354,24 @@
         animation.setStartOffset(startOffset);
         assertEquals(startOffset, animation.getStartOffset());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow,
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
                 animation, ACCELERATE_ALPHA_DURATION + startOffset);
 
         Transformation transformation = new Transformation();
         long startTime = animation.getStartTime();
         animation.getTransformation(startTime, transformation);
         float alpha1 = transformation.getAlpha();
-        assertEquals(0.1f, alpha1, ALPHA_DELTA);
+        assertEquals(0.1f, alpha1, COMPARISON_DELTA);
 
         animation.getTransformation(startTime + 400, transformation);
         float alpha2 = transformation.getAlpha();
         // alpha is 0.1f during start offset
-        assertEquals(0.1f, alpha2, ALPHA_DELTA);
+        assertEquals(0.1f, alpha2, COMPARISON_DELTA);
 
         animation.getTransformation(startTime + startOffset, transformation);
         float alpha3 = transformation.getAlpha();
         // alpha is 0.1f during start offset
-        assertEquals(0.1f, alpha3, ALPHA_DELTA);
+        assertEquals(0.1f, alpha3, COMPARISON_DELTA);
 
         animation.getTransformation(startTime + startOffset + 1, transformation);
         float alpha4 = transformation.getAlpha();
@@ -370,7 +379,8 @@
         assertTrue(alpha4 > 0.1f);
     }
 
-    public void testRunAccelerateAlpha() {
+    @Test
+    public void testRunAccelerateAlpha() throws Throwable {
         // check default startTime
         Animation animation = new Animation() {
         };
@@ -391,10 +401,11 @@
         Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
         assertEquals(Animation.START_ON_FIRST_FRAME, anim.getStartTime());
         assertFalse(anim.hasStarted());
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
     }
 
-    public void testGetTransformation() {
+    @Test
+    public void testGetTransformation() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
 
         // XML file of R.anim.accelerate_alpha
@@ -407,20 +418,11 @@
         assertFalse(anim.hasStarted());
 
         // we have to PollingCheck the animation status on test thread,
-        // it cannot be done on UI thread, so we invoke runOnMainSync method here.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                animWindow.startAnimation(anim);
-            }
-        });
+        // it cannot be done on UI thread, so we invoke runOnUiThread method here.
+        mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim));
 
         // check whether animation has started
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return anim.hasStarted();
-            }
-        }.run();
+        PollingCheck.waitFor(anim::hasStarted);
 
         // check transformation objects that is provided by the
         // caller and will be filled in by the animation.
@@ -428,7 +430,7 @@
         long startTime = anim.getStartTime();
         assertTrue(anim.getTransformation(startTime, transformation));
         float alpha1 = transformation.getAlpha();
-        assertEquals(0.1f, alpha1, ALPHA_DELTA);
+        assertEquals(0.1f, alpha1, COMPARISON_DELTA);
 
         assertTrue(anim.getTransformation(startTime + 250, transformation));
         float alpha2 = transformation.getAlpha();
@@ -441,16 +443,11 @@
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new PollingCheck(2000) {
-            @Override
-            protected boolean check() {
-                return anim.hasEnded();
-            }
-        }.run();
+        PollingCheck.waitFor(2000, anim::hasEnded);
 
         assertFalse(anim.getTransformation(startTime + 1000, transformation));
         float alpha5 = transformation.getAlpha();
-        assertEquals(0.9f, alpha5, ALPHA_DELTA);
+        assertEquals(0.9f, alpha5, COMPARISON_DELTA);
 
         // check decelerating delta alpha
         float delta1 = alpha2 - alpha1;
@@ -462,6 +459,7 @@
         assertTrue(delta3 < delta4);
     }
 
+    @Test
     public void testAccessZAdjustment() {
         // check default zAdjustment
         Animation animation = new Animation() {
@@ -478,6 +476,7 @@
         assertEquals(Animation.ZORDER_BOTTOM, animation.getZAdjustment());
     }
 
+    @Test
     public void testInitialize() {
         Animation animation = new Animation() {
         };
@@ -487,23 +486,31 @@
         assertTrue(animation.isInitialized());
     }
 
+    @Test
     public void testResolveSize() {
         MyAnimation myAnimation = new MyAnimation();
 
-        assertEquals(1.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 1.0f, 0, 0));
-        assertEquals(2.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 2.0f, 0, 0));
+        assertEquals(1.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 1.0f, 0, 0),
+                COMPARISON_DELTA);
+        assertEquals(2.0f, myAnimation.resolveSize(Animation.ABSOLUTE, 2.0f, 0, 0),
+                COMPARISON_DELTA);
 
-        assertEquals(6.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 2, 0));
-        assertEquals(9.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 3, 0));
+        assertEquals(6.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 2, 0),
+                COMPARISON_DELTA);
+        assertEquals(9.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_SELF, 3.0f, 3, 0),
+                COMPARISON_DELTA);
 
-        assertEquals(18.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 6));
-        assertEquals(12.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 4));
+        assertEquals(18.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 6),
+                COMPARISON_DELTA);
+        assertEquals(12.0f, myAnimation.resolveSize(Animation.RELATIVE_TO_PARENT, 3.0f, 0, 4),
+                COMPARISON_DELTA);
 
         int unknownType = 7;
-        assertEquals(8.0f, myAnimation.resolveSize(unknownType, 8.0f, 3, 4));
-        assertEquals(10.0f, myAnimation.resolveSize(unknownType, 10.0f, 3, 4));
+        assertEquals(8.0f, myAnimation.resolveSize(unknownType, 8.0f, 3, 4), COMPARISON_DELTA);
+        assertEquals(10.0f, myAnimation.resolveSize(unknownType, 10.0f, 3, 4), COMPARISON_DELTA);
     }
 
+    @Test
     public void testRestrictDuration() {
         Animation animation = new Animation() {
         };
@@ -526,6 +533,7 @@
         assertEquals(1, animation.getRepeatCount());
     }
 
+    @Test
     public void testScaleCurrentDuration() {
         Animation animation = new Animation() {
         };
@@ -543,7 +551,9 @@
         assertEquals(-10, animation.getDuration());
     }
 
-    public void testSetAnimationListener() {
+    @LargeTest
+    @Test
+    public void testSetAnimationListener() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
 
         // XML file of R.anim.accelerate_alpha
@@ -553,48 +563,40 @@
         //      android:toAlpha="0.9"
         //      android:duration="1000" />
         final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
-        MockAnimationListener listener = new MockAnimationListener();
+        final AnimationListener listener = mock(AnimationListener.class);
         anim.setAnimationListener(listener);
-        assertFalse(listener.hasAnimationStarted());
-        assertFalse(listener.hasAnimationEnded());
-        assertFalse(listener.hasAnimationRepeated());
+        verifyZeroInteractions(listener);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
-        assertTrue(listener.hasAnimationStarted());
-        assertTrue(listener.hasAnimationEnded());
-        assertFalse(listener.hasAnimationRepeated());
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
+        verify(listener, times(1)).onAnimationStart(anim);
+        verify(listener, times(1)).onAnimationEnd(anim);
+        verify(listener, never()).onAnimationRepeat(anim);
 
-        listener.reset();
+        reset(listener);
         anim.setRepeatCount(2);
         anim.setRepeatMode(Animation.REVERSE);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim, 3000);
-        assertTrue(listener.hasAnimationStarted());
-        assertTrue(listener.hasAnimationRepeated());
-        assertTrue(listener.hasAnimationEnded());
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim,
+                3000);
+        verify(listener, times(1)).onAnimationStart(anim);
+        verify(listener, times(2)).onAnimationRepeat(anim);
+        verify(listener, times(1)).onAnimationEnd(anim);
 
-        listener.reset();
+        reset(listener);
         // onAnimationEnd will not be invoked and animation should not end
         anim.setRepeatCount(Animation.INFINITE);
 
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                animWindow.startAnimation(anim);
-            }
-        });
-        synchronized(mLockObject) {
-            try {
-                mLockObject.wait(4 * ACCELERATE_ALPHA_DURATION);
-            } catch (InterruptedException e) {
-                fail("thrown unexpected InterruptedException");
-            }
-        }
+        mActivityRule.runOnUiThread(() -> animWindow.startAnimation(anim));
+        // Verify that our animation doesn't call listener's onAnimationEnd even after a long
+        // period of time. We just sleep and then verify what's happened with the listener.
+        SystemClock.sleep(4 * ACCELERATE_ALPHA_DURATION);
 
-        assertTrue(listener.hasAnimationStarted());
-        assertTrue(listener.hasAnimationRepeated());
-        assertFalse(listener.hasAnimationEnded());
+        verify(listener, times(1)).onAnimationStart(anim);
+        verify(listener, atLeastOnce()).onAnimationRepeat(anim);
+        verify(listener, never()).onAnimationEnd(anim);
     }
 
+    @Test
     public void testStart() {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
         animation.setStartTime(0);
@@ -603,6 +605,7 @@
         assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime());
     }
 
+    @Test
     public void testStartNow() {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
         animation.setStartTime(0);
@@ -612,6 +615,7 @@
         assertEquals(currentTime, animation.getStartTime(), 100);
     }
 
+    @Test
     public void testWillChangeBounds() {
         Animation animation = new Animation() {
         };
@@ -619,6 +623,7 @@
         assertTrue(animation.willChangeBounds());
     }
 
+    @Test
     public void testWillChangeTransformationMatrix() {
         Animation animation = new Animation() {
         };
@@ -626,6 +631,7 @@
         assertTrue(animation.willChangeTransformationMatrix());
     }
 
+    @Test
     public void testClone() throws CloneNotSupportedException {
         MyAnimation myAnimation = new MyAnimation();
         myAnimation.setDuration(3000);
@@ -647,6 +653,7 @@
         assertEquals(myAnimation.getRepeatMode(), cloneAnimation.getRepeatMode());
     }
 
+    @Test
     public void testCancelImmediately() throws Throwable {
         MyAnimation anim = new MyAnimation();
         final CountDownLatch latch1 = new CountDownLatch(1);
@@ -655,6 +662,7 @@
         assertFalse(anim.isStillAnimating());
     }
 
+    @Test
     public void testRepeatingCancelImmediately() throws Throwable {
         MyAnimation anim = new MyAnimation();
         final CountDownLatch latch2 = new CountDownLatch(1);
@@ -663,6 +671,7 @@
         assertFalse(anim.isStillAnimating());
     }
 
+    @Test
     public void testCancelDelayed() throws Throwable {
         MyAnimation anim = new MyAnimation();
         final CountDownLatch latch3 = new CountDownLatch(1);
@@ -671,6 +680,7 @@
         assertFalse(anim.isStillAnimating());
     }
 
+    @Test
     public void testRepeatingCancelDelayed() throws Throwable {
         MyAnimation anim = new MyAnimation();
         final CountDownLatch latch4 = new CountDownLatch(1);
@@ -686,37 +696,22 @@
         // anymore. The trick is that cancel() will still allow one more frame to run,
         // so we have to insert some delay between when we cancel and when we can check
         // whether it is still animating.
-        runTestOnUiThread(new Runnable() {
-            final View view = mActivity.findViewById(R.id.anim_window);
-            public void run() {
-                anim.setDuration(delayed ? 150 : 100);
-                if (repeating) {
-                    anim.setRepeatCount(Animation.INFINITE);
-                }
-                view.startAnimation(anim);
-                if (!delayed) {
-                    anim.cancel();
-                } else {
-                    view.postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            anim.cancel();
-                        }
-                    }, 50);
-                }
-                view.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        anim.setStillAnimating(false);
-                        view.postDelayed(new Runnable() {
-                            @Override
-                            public void run() {
-                                latch.countDown();
-                            }
-                        }, 50);
-                    }
-                }, delayed ? 100 : 50);
+        final View view = mActivity.findViewById(R.id.anim_window);
+        mActivityRule.runOnUiThread(() -> {
+            anim.setDuration(delayed ? 150 : 100);
+            if (repeating) {
+                anim.setRepeatCount(Animation.INFINITE);
             }
+            view.startAnimation(anim);
+            if (!delayed) {
+                anim.cancel();
+            } else {
+                view.postDelayed(anim::cancel, 50);
+            }
+            view.postDelayed(() -> {
+                anim.setStillAnimating(false);
+                view.postDelayed(latch::countDown, 50);
+            }, delayed ? 100 : 50);
         });
     }
 
@@ -752,41 +747,4 @@
             return super.getTransformation(currentTime, outTransformation);
         }
     }
-
-    private class MockAnimationListener implements AnimationListener {
-        private boolean mHasAnimationStarted = false;
-        private boolean mHasAnimationEnded = false;
-        private boolean mHasAnimationRepeated = false;
-
-        public void onAnimationStart(Animation animation) {
-            mHasAnimationStarted = true;
-        }
-        public void onAnimationEnd(Animation animation) {
-            synchronized(mLockObject) {
-                mHasAnimationEnded = true;
-                mLockObject.notifyAll();
-            }
-        }
-        public void onAnimationRepeat(Animation animation) {
-            mHasAnimationRepeated = true;
-        }
-
-        public boolean hasAnimationStarted() {
-            return mHasAnimationStarted;
-        }
-
-        public boolean hasAnimationEnded() {
-            return mHasAnimationEnded;
-        }
-
-        public boolean hasAnimationRepeated() {
-            return mHasAnimationRepeated;
-        }
-
-        public void reset() {
-            mHasAnimationStarted = false;
-            mHasAnimationEnded = false;
-            mHasAnimationRepeated = false;
-        }
-    }
 }
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java b/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
index 0316f28..bf85d73 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTestCtsActivity.java
@@ -16,11 +16,9 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+import android.view.cts.R;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTestUtils.java b/tests/tests/view/src/android/view/animation/cts/AnimationTestUtils.java
index f9675c7..9c845c1 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTestUtils.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTestUtils.java
@@ -17,12 +17,15 @@
 package android.view.animation.cts;
 
 import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
+import android.os.SystemClock;
+import android.support.test.rule.ActivityTestRule;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
 import android.view.animation.LayoutAnimationController;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 /**
  * The utility methods for animation test.
  */
@@ -41,71 +44,58 @@
      * Assert run an animation successfully. Timeout is duration of animation.
      *
      * @param instrumentation to run animation.
+     * @param activityTestRule to run animation.
      * @param view view window to run animation.
      * @param animation will be run.
+     * @throws Throwable
      */
     public static void assertRunAnimation(final Instrumentation instrumentation,
-            final View view, final Animation animation) {
-        assertRunAnimation(instrumentation, view, animation, animation.getDuration());
+            final ActivityTestRule activityTestRule, final View view, final Animation animation)
+            throws Throwable {
+        assertRunAnimation(instrumentation, activityTestRule, view, animation,
+                animation.getDuration());
     }
 
     /**
      * Assert run an animation successfully.
      *
      * @param instrumentation to run animation.
+     * @param activityTestRule to run animation.
      * @param view window to run animation.
      * @param animation will be run.
      * @param duration in milliseconds.
+     * @throws Throwable
      */
     public static void assertRunAnimation(final Instrumentation instrumentation,
-            final View view, final Animation animation, final long duration) {
+            final ActivityTestRule activityTestRule, final View view, final Animation animation,
+            final long duration) throws Throwable {
 
-        instrumentation.runOnMainSync(new Runnable() {
-            public void run() {
-                view.startAnimation(animation);
-            }
-        });
+        activityTestRule.runOnUiThread(() -> view.startAnimation(animation));
 
         // check whether it has started
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return animation.hasStarted();
-            }
-        }.run();
+        PollingCheck.waitFor(animation::hasStarted);
 
         // check whether it has ended after duration
-        new PollingCheck(duration + TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return animation.hasEnded();
-            }
-        }.run();
+        PollingCheck.waitFor(duration + TIMEOUT_DELTA, animation::hasEnded);
 
         instrumentation.waitForIdleSync();
     }
 
     /**
-     * Assert run an AbsListView with LayoutAnimationController successfully.
-     * @param instrumentation
-     * @param view
-     * @param controller
-     * @param duration
-     * @throws InterruptedException
+     * Assert run an view with LayoutAnimationController successfully.
+     * @throws Throwable
      */
-    public static void assertRunController(final Instrumentation instrumentation,
+    public static void assertRunController(final ActivityTestRule activityTestRule,
             final ViewGroup view, final LayoutAnimationController controller,
-            final long duration) throws InterruptedException {
+            final long duration) throws Throwable {
 
-        instrumentation.runOnMainSync(new Runnable() {
-           public void run() {
-                view.setLayoutAnimation(controller);
-                view.requestLayout();
-           }
+        activityTestRule.runOnUiThread(() -> {
+            view.setLayoutAnimation(controller);
+            view.requestLayout();
         });
 
         // LayoutAnimationController.isDone() always returns true, it's no use for stopping
         // the running, so just using sleeping fixed time instead. we reported issue 1799434 for it.
-        Thread.sleep(duration + TIMEOUT_DELTA);
+        SystemClock.sleep(duration + TIMEOUT_DELTA);
     }
 }
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
index b47613f..3a8d270 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationUtilsTest.java
@@ -16,11 +16,14 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
+import android.app.Activity;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -28,22 +31,28 @@
 import android.view.animation.GridLayoutAnimationController;
 import android.view.animation.Interpolator;
 import android.view.animation.LayoutAnimationController;
+import android.view.cts.R;
 
-public class AnimationUtilsTest extends
-        ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private AnimationTestCtsActivity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimationUtilsTest {
+    private Activity mActivity;
 
-    public AnimationUtilsTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = (AnimationTestCtsActivity) getActivity();
-    }
-
+    @Test
     public void testLoad() {
         // XML file of android.view.cts.R.anim.anim_alpha
         // <alpha xmlns:android="http://schemas.android.com/apk/res/android"
@@ -74,6 +83,7 @@
         assertEquals(0.1f, controller.getDelay(), 0.001f);
     }
 
+    @Test
     public void testMakeAnimation() {
         Animation inAnimation = AnimationUtils.makeInAnimation(mActivity, true);
         assertNotNull(inAnimation);
@@ -84,6 +94,7 @@
         // TODO: How to assert these Animations.
     }
 
+    @Test
     public void testCurrentAnimationTimeMillis() {
         long time1 = AnimationUtils.currentAnimationTimeMillis();
         assertTrue(time1 > 0);
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
index e8cd62c..7e0808e 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
@@ -15,6 +15,12 @@
 */
 package android.view.animation.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 android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
@@ -24,28 +30,47 @@
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.content.Context;
+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.util.Log;
-import android.test.ActivityInstrumentationTestCase2;
 import android.view.Display;
 import android.view.Surface;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.cts.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import android.view.cts.R;
-
-public class AnimatorInflaterTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AnimatorInflaterTest {
     private static final String TAG = "AnimatorInflaterTest";
-    Set<Integer> identityHashes = new HashSet<Integer>();
 
-    public AnimatorInflaterTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private AnimationTestCtsActivity mActivity;
+    private View mTestView;
+
+    Set<Integer> identityHashes = new HashSet<>();
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTestView = mActivity.findViewById(R.id.anim_window);
     }
 
     private void assertUnique(Object object) {
@@ -55,17 +80,15 @@
     private void assertUnique(Object object, String msg) {
         final int code = System.identityHashCode(object);
         assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
-
     }
 
+    @Test
     public void testLoadAnimatorWithDifferentInterpolators() throws Throwable {
-        Animator anim1 = AnimatorInflater
-                .loadAnimator(getActivity(), R.anim.changing_test_animator);
+        Animator anim1 = AnimatorInflater .loadAnimator(mActivity, R.anim.changing_test_animator);
         if (!rotate()) {
             return;//cancel test
         }
-        Animator anim2 = AnimatorInflater
-                .loadAnimator(getActivity(), R.anim.changing_test_animator);
+        Animator anim2 = AnimatorInflater .loadAnimator(mActivity, R.anim.changing_test_animator);
         assertNotSame(anim1, anim2);
         assertNotSame("interpolater is orientation dependent, should change",
                 anim1.getInterpolator(), anim2.getInterpolator());
@@ -74,18 +97,19 @@
     /**
      * Tests animators with dimension references.
      */
+    @Test
     public void testLoadAnimator() throws Throwable {
         // to identify objects
-        Animator anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
-        Animator anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        Animator anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
+        Animator anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
         assertNotSame("a different animation should be returned", anim1, anim2);
         assertSame("interpolator should be shallow cloned", anim1.getInterpolator(),
                 anim2.getInterpolator());
         for (int i = 0; i < 2; i++) {
-            float targetX = getActivity().getResources()
+            float targetX = mActivity.getResources()
                     .getDimension(R.dimen.test_animator_target_x);
             // y value changes in landscape orientation
-            float targetY = getActivity().getResources()
+            float targetY = mActivity.getResources()
                     .getDimension(R.dimen.test_animator_target_y);
             for (Animator anim : new Animator[]{anim1, anim2}) {
                 assertTrue(anim instanceof AnimatorSet);
@@ -99,40 +123,37 @@
                 final ObjectAnimator child1 = (ObjectAnimator) set.getChildAnimations().get(0);
                 final ObjectAnimator child2 = (ObjectAnimator) set.getChildAnimations().get(1);
                 final DummyObject dummyObject = new DummyObject();
-                runTestOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        for (ObjectAnimator animator : new ObjectAnimator[]{child1, child2}) {
-                            animator.setTarget(dummyObject);
-                            animator.setupStartValues();
-                            animator.start();
-                            animator.end();
-                        }
+                mActivityRule.runOnUiThread(() -> {
+                    for (ObjectAnimator animator : new ObjectAnimator[]{child1, child2}) {
+                        animator.setTarget(dummyObject);
+                        animator.setupStartValues();
+                        animator.start();
+                        animator.end();
                     }
                 });
-                assertEquals(targetX, dummyObject.x);
-                assertEquals(targetY, dummyObject.y);
+                assertEquals(targetX, dummyObject.x, 0.0f);
+                assertEquals(targetY, dummyObject.y, 0.0f);
             }
             if (i == 0) {
                 if (!rotate()) {
                     return;//cancel test
                 }
             }
-            anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
-            anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+            anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
+            anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
 
         }
     }
 
     private boolean rotate() throws Throwable {
-        WindowManager mWindowManager = (WindowManager) getActivity()
+        WindowManager mWindowManager = (WindowManager) mActivity
                 .getSystemService(Context.WINDOW_SERVICE);
         Display display = mWindowManager.getDefaultDisplay();
-        int orientation = getActivity().getResources().getConfiguration().orientation;
+        int orientation = mActivity.getResources().getConfiguration().orientation;
 
         Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
-                getActivity().getClass().getName(), null, false);
-        getInstrumentation().addMonitor(monitor);
+                mActivity.getClass().getName(), null, false);
+        mInstrumentation.addMonitor(monitor);
         int nextRotation = 0;
         switch (display.getRotation()) {
             case Surface.ROTATION_0:
@@ -147,21 +168,21 @@
                 Log.e(TAG, "Cannot get rotation, test is canceled");
                 return false;
         }
-        boolean rotated = getInstrumentation().getUiAutomation().setRotation(nextRotation);
+        boolean rotated = mInstrumentation.getUiAutomation().setRotation(nextRotation);
         Thread.sleep(500);
         if (!rotated) {
             Log.e(TAG, "Rotation failed, test is canceled");
         }
-        getInstrumentation().waitForIdleSync();
-        if (!getActivity().waitUntilVisible()) {
+        mInstrumentation.waitForIdleSync();
+        if (!mActivity.waitUntilVisible()) {
             Log.e(TAG, "Activity failed to complete rotation, canceling test");
             return false;
         }
-        if (getActivity().getWindowManager().getDefaultDisplay().getRotation() != nextRotation) {
+        if (mActivity.getWindowManager().getDefaultDisplay().getRotation() != nextRotation) {
             Log.e(TAG, "New activity orientation does not match. Canceling test");
             return false;
         }
-        if (getActivity().getResources().getConfiguration().orientation == orientation) {
+        if (mActivity.getResources().getConfiguration().orientation == orientation) {
             Log.e(TAG, "Screen orientation didn't change, test is canceled");
             return false;
         }
@@ -171,10 +192,11 @@
     /**
      * Simple state list animator test that checks for cloning
      */
+    @Test
     public void testLoadStateListAnimator() {
-        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(),
+        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(mActivity,
                 R.anim.test_state_list_animator);
-        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(),
+        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(mActivity,
                 R.anim.test_state_list_animator);
         assertUnique(sla1);
         assertUnique(sla2);
@@ -184,6 +206,7 @@
      * Tests a state list animator which has an @anim reference that has different xmls per
      * orientation
      */
+    @Test
     public void testLoadStateListAnimatorWithChangingResetState() throws Throwable {
         loadStateListAnimatorWithChangingResetStateTest();
         if (!rotate()) {
@@ -194,26 +217,23 @@
     }
 
     private void loadStateListAnimatorWithChangingResetStateTest() throws Throwable {
-        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(getActivity(),
+        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(mActivity,
                 R.anim.test_state_list_animator_2);
-        final View testView = getTestView();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                testView.setStateListAnimator(sla);
-                testView.jumpDrawablesToCurrentState();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTestView.setStateListAnimator(sla);
+            mTestView.jumpDrawablesToCurrentState();
         });
-        float resetValue = getActivity().getResources().getDimension(R.dimen.reset_state_value);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(resetValue, testView.getX());
-        assertEquals(resetValue, testView.getY());
-        assertEquals(resetValue, testView.getZ());
+        float resetValue = mActivity.getResources().getDimension(R.dimen.reset_state_value);
+        mInstrumentation.waitForIdleSync();
+        assertEquals(resetValue, mTestView.getX(), 0.0f);
+        assertEquals(resetValue, mTestView.getY(), 0.0f);
+        assertEquals(resetValue, mTestView.getZ(), 0.0f);
     }
 
     /**
      * Tests a state list animator which has different xml descriptions per orientation.
      */
+    @Test
     public void testLoadChangingStateListAnimator() throws Throwable {
         loadChangingStateListAnimatorTest();
         if (!rotate()) {
@@ -223,27 +243,24 @@
     }
 
     private void loadChangingStateListAnimatorTest() throws Throwable {
-        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(getActivity(),
+        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(mActivity,
                 R.anim.changing_state_list_animator);
-        final View testView = getTestView();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                testView.setStateListAnimator(sla);
-                testView.jumpDrawablesToCurrentState();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTestView.setStateListAnimator(sla);
+            mTestView.jumpDrawablesToCurrentState();
         });
-        float targetValue = getActivity().getResources()
+        float targetValue = mActivity.getResources()
                 .getDimension(R.dimen.changing_state_list_anim_target_x_value);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(targetValue, testView.getX());
+        mInstrumentation.waitForIdleSync();
+        assertEquals(targetValue, mTestView.getX(), 0.0f);
     }
 
     /**
      * Tests that makes sure that reloaded animator is not affected by previous changes
      */
+    @Test
     public void testReloadedAnimatorIsNotModified() throws Throwable {
-        final Animator anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        final Animator anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
         final CountDownLatch mStarted = new CountDownLatch(1);
         final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
             @Override
@@ -257,15 +274,12 @@
                 mStarted.countDown();
             }
         };
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                anim1.setTarget(getTestView());
-                anim1.addListener(listener);
-                anim1.start();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            anim1.setTarget(mTestView);
+            anim1.addListener(listener);
+            anim1.start();
         });
-        Animator anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        Animator anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
         assertTrue(anim1.isStarted());
         assertFalse(anim2.isStarted());
         assertFalse("anim2 should not include the listener",
@@ -275,10 +289,6 @@
 
     }
 
-    public View getTestView() {
-        return getActivity().findViewById(R.id.anim_window);
-    }
-
     class DummyObject {
 
         float x;
diff --git a/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
index 3ac5950..372fd52 100644
--- a/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/CycleInterpolatorTest.java
@@ -16,9 +16,17 @@
 
 package android.view.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -28,32 +36,37 @@
 import android.view.animation.CycleInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
-
 import android.view.cts.R;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link CycleInterpolator}.
  */
-public class CycleInterpolatorTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
-    private Activity mActivity;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CycleInterpolatorTest {
     /** It is defined in R.anim.cycle_alpha */
     private static final long CYCLE_ALPHA_DURATION = 2000;
     private static final float ALPHA_DELTA = 0.001f;
 
-    public CycleInterpolatorTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructors() {
         new CycleInterpolator(1.0f);
 
@@ -62,7 +75,8 @@
         new CycleInterpolator(mActivity, attrs);
     }
 
-    public void testCycyleInterpolator() {
+    @Test
+    public void testCycleInterpolator() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.cycle_alpha);
         assertEquals(CYCLE_ALPHA_DURATION, anim.getDuration());
@@ -73,7 +87,7 @@
         anim.setInterpolator(interpolator);
         assertFalse(anim.hasStarted());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         Transformation transformation = new Transformation();
         long startTime = anim.getStartTime();
@@ -112,7 +126,7 @@
         interpolator = new CycleInterpolator(2.0f);
         anim.setInterpolator(interpolator);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         transformation = new Transformation();
         startTime = anim.getStartTime();
@@ -192,6 +206,7 @@
         assertEquals(delta12, delta4, ALPHA_DELTA);
     }
 
+    @Test
     public void testGetInterpolation() {
         CycleInterpolator cycleInterpolator = new CycleInterpolator(2.0f);
         final float out1 = cycleInterpolator.getInterpolation(0.0f);
diff --git a/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
index 2400291..1ecbe96 100644
--- a/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/DecelerateInterpolatorTest.java
@@ -16,12 +16,17 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -31,29 +36,38 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.Transformation;
+import android.view.cts.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link DecelerateInterpolator}.
  */
-public class DecelerateInterpolatorTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class DecelerateInterpolatorTest {
     private static final float ALPHA_DELTA = 0.001f;
 
     /** It is defined in R.anim.decelerate_alpha */
     private static final long DECELERATE_ALPHA_DURATION = 2000;
 
-    public DecelerateInterpolatorTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new DecelerateInterpolator();
 
@@ -64,7 +78,8 @@
         new DecelerateInterpolator(mActivity, attrs);
     }
 
-    public void testDecelerateInterpolator() {
+    @Test
+    public void testDecelerateInterpolator() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
 
         // XML file of R.anim.decelerate_alpha
@@ -83,7 +98,7 @@
         anim.setInterpolator(interpolator);
         assertFalse(anim.hasStarted());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         Transformation transformation = new Transformation();
         long startTime = anim.getStartTime();
@@ -117,7 +132,7 @@
         interpolator = new DecelerateInterpolator(1.5f);
         anim.setInterpolator(interpolator);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         transformation = new Transformation();
         startTime = anim.getStartTime();
@@ -151,6 +166,7 @@
         assertTrue(delta5 > delta1);
     }
 
+    @Test
     public void testGetInterpolation() {
         final float input = 0.25f;
         Interpolator interpolator1 = new DecelerateInterpolator(1.0f);
diff --git a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
index 371af41..b6bc8fb 100644
--- a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
+++ b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimCtsActivity.java
@@ -16,13 +16,12 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.cts.R;
 import android.widget.AbsListView;
 import android.widget.GridView;
 import android.widget.ImageView;
diff --git a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
index 58efa0e..00a88ca 100644
--- a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationControllerTest.java
@@ -16,12 +16,14 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-
-import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -29,19 +31,20 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.GridLayoutAnimationController;
-import android.view.animation.Transformation;
 import android.view.animation.GridLayoutAnimationController.AnimationParameters;
+import android.view.animation.Transformation;
+import android.view.cts.R;
 import android.widget.AbsListView;
 import android.widget.GridView;
 
-public class GridLayoutAnimationControllerTest
-    extends ActivityInstrumentationTestCase2<GridLayoutAnimCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private GridLayoutAnimCtsActivity mActivity;
-    private Animation mDefaultAnimation;
-    private GridLayoutAnimationController mController;
-    /** The GridView will be 3*3 */
-    private GridView mGridView;
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class GridLayoutAnimationControllerTest {
     /** Default delay of GridLayoutAnimationController */
     private static final float DEFAULT_DELAY = 0.5f;
     /** Default max duration of running */
@@ -57,14 +60,19 @@
     private static final int INDEX_OF_CHILD8 = 7;
     private static final int INDEX_OF_CHILD9 = 8;
 
-    public GridLayoutAnimationControllerTest() {
-        super("android.view.cts", GridLayoutAnimCtsActivity.class);
-    }
+    private GridLayoutAnimCtsActivity mActivity;
+    private Animation mDefaultAnimation;
+    private GridLayoutAnimationController mController;
+    /** The GridView will be 3*3 */
+    private GridView mGridView;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Rule
+    public ActivityTestRule<GridLayoutAnimCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GridLayoutAnimCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mDefaultAnimation = AnimationUtils.loadAnimation(mActivity,
                 R.anim.layout_anim_controller_animation);
         mController = new GridLayoutAnimationController(mDefaultAnimation, DEFAULT_DELAY,
@@ -72,6 +80,7 @@
         mGridView = mActivity.getGridView();
     }
 
+    @Test
     public void testConstructor() {
         XmlResourceParser parser = mActivity.getResources().getAnimation(
                 R.anim.accelerate_decelerate_alpha);
@@ -80,17 +89,18 @@
         GridLayoutAnimationController controller =
                 new GridLayoutAnimationController(mDefaultAnimation);
         // Default rowDelay and columnDelay is 0.5f
-        assertEquals(DEFAULT_DELAY, controller.getRowDelay());
-        assertEquals(DEFAULT_DELAY, controller.getColumnDelay());
+        assertEquals(DEFAULT_DELAY, controller.getRowDelay(), 0.0f);
+        assertEquals(DEFAULT_DELAY, controller.getColumnDelay(), 0.0f);
         new GridLayoutAnimationController(mDefaultAnimation, 0.5f, 0.5f);
     }
 
-    public void testAccessDelay() throws InterruptedException {
+    @Test
+    public void testAccessDelay() throws Throwable {
         float delay = 1.5f;
         long maxDuration = 13000;
         mController.setRowDelay(delay);
-        assertEquals(delay, mController.getRowDelay());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        assertEquals(delay, mController.getRowDelay(), 0.0f);
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 maxDuration);
 
         Animation childAnimation1 = mGridView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -99,8 +109,8 @@
         assertChildrenDelay(childAnimation1, childAnimation4, childAnimation7);
 
         mController.setColumnDelay(delay);
-        assertEquals(delay, mController.getColumnDelay());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        assertEquals(delay, mController.getColumnDelay(), 0.0f);
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 maxDuration);
 
         childAnimation1 = mGridView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -174,11 +184,12 @@
         assertTrue(alpha < 1.0f);
     }
 
-    public void testAccessDirection() throws InterruptedException {
+    @Test
+    public void testAccessDirection() throws Throwable {
         mController.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP);
         assertEquals(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP,
                 mController.getDirection());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 DEFAULT_MAX_DURATION);
 
         Animation childAnimation1 = mGridView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -225,7 +236,7 @@
         mController.setDirection(GridLayoutAnimationController.DIRECTION_TOP_TO_BOTTOM);
         assertEquals(GridLayoutAnimationController.DIRECTION_TOP_TO_BOTTOM,
                 mController.getDirection());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 DEFAULT_MAX_DURATION);
 
         transformation1 = new Transformation();
@@ -266,6 +277,7 @@
         assertIsRunningAnimation(transformation3.getAlpha());
     }
 
+    @Test
     public void testGetDelayForView() throws Throwable {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
         animation.setFillAfter(true);
@@ -299,21 +311,19 @@
         final View child7 = mGridView.getChildAt(INDEX_OF_CHILD7);
         final View child8 = mGridView.getChildAt(INDEX_OF_CHILD8);
         final View child9 = mGridView.getChildAt(INDEX_OF_CHILD9);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                child1.setLayoutParams(layoutParams1);
-                child2.setLayoutParams(layoutParams2);
-                child3.setLayoutParams(layoutParams3);
-                child4.setLayoutParams(layoutParams4);
-                child5.setLayoutParams(layoutParams5);
-                child6.setLayoutParams(layoutParams6);
-                child7.setLayoutParams(layoutParams7);
-                child8.setLayoutParams(layoutParams8);
-                child9.setLayoutParams(layoutParams9);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            child1.setLayoutParams(layoutParams1);
+            child2.setLayoutParams(layoutParams2);
+            child3.setLayoutParams(layoutParams3);
+            child4.setLayoutParams(layoutParams4);
+            child5.setLayoutParams(layoutParams5);
+            child6.setLayoutParams(layoutParams6);
+            child7.setLayoutParams(layoutParams7);
+            child8.setLayoutParams(layoutParams8);
+            child9.setLayoutParams(layoutParams9);
         });
 
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, controller,
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, controller,
                 DEFAULT_MAX_DURATION);
 
         assertEquals(0, controller.getDelayForView(child1));
@@ -337,10 +347,11 @@
         return layoutParams;
     }
 
-    public void testAccessDirectionPriority() throws InterruptedException {
+    @Test
+    public void testAccessDirectionPriority() throws Throwable {
         // Before setting DirectionPriority, childAnimation7 will be later than childAnimation2,
         // and childAnimation8 will be later than childAnimation3
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 DEFAULT_MAX_DURATION);
         Animation childAnimation1 = mGridView.getChildAt(INDEX_OF_CHILD1).getAnimation();
         Animation childAnimation2 = mGridView.getChildAt(INDEX_OF_CHILD2).getAnimation();
@@ -373,7 +384,7 @@
         mController.setDirectionPriority(GridLayoutAnimationController.PRIORITY_COLUMN);
         assertEquals(GridLayoutAnimationController.PRIORITY_COLUMN,
                 mController.getDirectionPriority());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mGridView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mGridView, mController,
                 DEFAULT_MAX_DURATION);
         childAnimation1 = mGridView.getChildAt(INDEX_OF_CHILD1).getAnimation();
         childAnimation2 = mGridView.getChildAt(INDEX_OF_CHILD2).getAnimation();
@@ -401,6 +412,7 @@
         assertIsRunningAnimation(transformation2.getAlpha());
     }
 
+    @Test
     public void testWillOverlap() {
         GridLayoutAnimationController controller = new GridLayoutAnimationController(
                 mDefaultAnimation);
diff --git a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationController_AnimationParametersTest.java b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationController_AnimationParametersTest.java
index 5fa9217..c3be382 100644
--- a/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationController_AnimationParametersTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/GridLayoutAnimationController_AnimationParametersTest.java
@@ -17,12 +17,17 @@
 package android.view.animation.cts;
 
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.GridLayoutAnimationController;
-import android.view.animation.GridLayoutAnimationController.AnimationParameters;
 
-public class GridLayoutAnimationController_AnimationParametersTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GridLayoutAnimationController_AnimationParametersTest {
+    @Test
     public void testConstructor() {
         new GridLayoutAnimationController.AnimationParameters();
     }
diff --git a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
index adc4192..90e7942 100644
--- a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationControllerTest.java
@@ -16,13 +16,15 @@
 
 package android.view.animation.cts;
 
-import android.view.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 android.app.ListActivity;
-import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -31,21 +33,22 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
 import android.view.animation.LayoutAnimationController;
+import android.view.animation.LayoutAnimationController.AnimationParameters;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.Transformation;
-import android.view.animation.LayoutAnimationController.AnimationParameters;
+import android.view.cts.R;
 import android.widget.AbsListView;
 import android.widget.ListView;
 
-public class LayoutAnimationControllerTest
-        extends ActivityInstrumentationTestCase2<LayoutAnimCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private ListActivity mActivity;
-    private Animation mDefaultAnimation;
-    private ListView mListView;
-    private LayoutAnimationController mController;
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class LayoutAnimationControllerTest {
     /** Duration defined in layout_anim_controller_animation.xml is 1000 */
     private static final int DURATION = 1000;
     private static final float DELTA = 0.1f;
@@ -57,26 +60,30 @@
     /** Default max duration of these three children */
     private static final long DEFAULT_MAX_DURATION = 2000;
 
-    public LayoutAnimationControllerTest() {
-        super("android.view.cts", LayoutAnimCtsActivity.class);
-    }
+    private LayoutAnimCtsActivity mActivity;
+    private Animation mDefaultAnimation;
+    private ListView mListView;
+    private LayoutAnimationController mController;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Rule
+    public ActivityTestRule<LayoutAnimCtsActivity> mActivityRule =
+            new ActivityTestRule<>(LayoutAnimCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mListView = mActivity.getListView();
         mDefaultAnimation = AnimationUtils.loadAnimation(mActivity,
                 R.anim.layout_anim_controller_animation);
         mController = new LayoutAnimationController(mDefaultAnimation, DEFAULT_DELAY);
     }
 
-    public void testAccessOrder() throws InterruptedException {
-
+    @Test
+    public void testAccessOrder() throws Throwable {
         mController.setOrder(LayoutAnimationController.ORDER_NORMAL);
         assertEquals(LayoutAnimationController.ORDER_NORMAL, mController.getOrder());
 
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
 
         Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -120,7 +127,7 @@
         // Test reverse order
         mController.setOrder(LayoutAnimationController.ORDER_REVERSE);
         assertEquals(LayoutAnimationController.ORDER_REVERSE, mController.getOrder());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
 
         transformation1 = new Transformation();
@@ -159,13 +166,14 @@
         assertEquals(1.0f, transformation3.getAlpha(), DELTA);
     }
 
-    public void testAccessDelay() throws InterruptedException {
+    @Test
+    public void testAccessDelay() throws Throwable {
         mController.setOrder(LayoutAnimationController.ORDER_NORMAL);
         float delay = 1.5f;
         mController.setDelay(delay);
-        assertEquals(delay, mController.getDelay());
+        assertEquals(delay, mController.getDelay(), 0.0f);
         long maxDuration = (long) (delay * INDEX_OF_CHILD3 * DURATION + DURATION);
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 maxDuration);
 
         Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -229,7 +237,8 @@
         assertTrue(alpha < 1.0f);
     }
 
-    public void testAccessAnimation() throws InterruptedException {
+    @Test
+    public void testAccessAnimation() throws Throwable {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
         animation.setFillAfter(true);
         // duration defined in decelerate_alpha.xml is 2000
@@ -237,7 +246,7 @@
         mController.setAnimation(animation);
         assertSame(animation, mController.getAnimation());
         long maxDuration = (long) (DEFAULT_DELAY * INDEX_OF_CHILD3 * duration + duration);
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 maxDuration);
 
         Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -251,7 +260,7 @@
         Animation actualAnimation = mController.getAnimation();
         assertEquals(DURATION, actualAnimation.getDuration());
         assertTrue(actualAnimation.getInterpolator() instanceof AccelerateInterpolator);
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
 
         childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -300,11 +309,12 @@
         }
     }
 
-    public void testAccessInterpolator() throws InterruptedException {
+    @Test
+    public void testAccessInterpolator() throws Throwable {
         DecelerateInterpolator interpolator = new DecelerateInterpolator(1.0f);
         mController.setInterpolator(interpolator);
         assertSame(interpolator, mController.getInterpolator());
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
 
         Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -317,7 +327,7 @@
 
         mController.setInterpolator(mActivity, android.R.anim.accelerate_interpolator);
         assertTrue(mController.getInterpolator() instanceof AccelerateInterpolator);
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
 
         childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
@@ -329,6 +339,7 @@
         assertTrue(delta2 > delta1);
     }
 
+    @Test
     public void testConstructor() {
         XmlResourceParser parser = mActivity.getResources().getAnimation(
                 R.anim.accelerate_decelerate_alpha);
@@ -336,9 +347,10 @@
         new LayoutAnimationController(mActivity, attrs);
         new LayoutAnimationController(mDefaultAnimation, DEFAULT_DELAY);
         LayoutAnimationController controller = new LayoutAnimationController(mDefaultAnimation);
-        assertEquals(DEFAULT_DELAY, controller.getDelay());
+        assertEquals(DEFAULT_DELAY, controller.getDelay(), 0.0f);
     }
 
+    @Test
     public void testGetDelayForView() throws Throwable {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
         animation.setFillAfter(true);
@@ -354,15 +366,13 @@
         final View child1 = mListView.getChildAt(INDEX_OF_CHILD1);
         final View child2 = mListView.getChildAt(INDEX_OF_CHILD2);
         final View child3 = mListView.getChildAt(INDEX_OF_CHILD3);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                child1.setLayoutParams(layoutParams1);
-                child2.setLayoutParams(layoutParams2);
-                child3.setLayoutParams(layoutParams3);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            child1.setLayoutParams(layoutParams1);
+            child2.setLayoutParams(layoutParams2);
+            child3.setLayoutParams(layoutParams3);
         });
 
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, controller,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, controller,
                 DEFAULT_MAX_DURATION);
 
         assertEquals(0, controller.getDelayForView(child1));
@@ -380,6 +390,7 @@
         return layoutParams;
     }
 
+    @Test
     public void testGetTransformedIndex() {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
         animation.setFillAfter(true);
@@ -406,6 +417,7 @@
         assertEquals(0, controller.getTransformedIndex(animationParams));
     }
 
+    @Test
     public void testStart() {
         Animation animation = new ScaleAnimation(0.0f, 10.0f, 0.0f, 20.0f);
         animation.setStartTime(500);
@@ -417,17 +429,19 @@
         assertEquals(Animation.START_ON_FIRST_FRAME, controller.getAnimation().getStartTime());
     }
 
-    public void testIsDone() throws InterruptedException {
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+    @Test
+    public void testIsDone() throws Throwable {
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
         assertTrue(mController.isDone());
     }
 
-    public void testGetAnimationForView() throws InterruptedException {
+    @Test
+    public void testGetAnimationForView() throws Throwable {
         Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
         animation.setFillAfter(true);
         mController.setAnimation(animation);
-        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
+        AnimationTestUtils.assertRunController(mActivityRule, mListView, mController,
                 DEFAULT_MAX_DURATION);
         Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
         Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
@@ -442,6 +456,7 @@
         assertEquals(2000, childAnimation3.getStartOffset());
     }
 
+    @Test
     public void testWillOverlap() {
         LayoutAnimationController controller = new LayoutAnimationController(mDefaultAnimation);
 
diff --git a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationController_AnimationParametersTest.java b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationController_AnimationParametersTest.java
index 21fd97b..57e050c 100644
--- a/tests/tests/view/src/android/view/animation/cts/LayoutAnimationController_AnimationParametersTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/LayoutAnimationController_AnimationParametersTest.java
@@ -16,12 +16,17 @@
 
 package android.view.animation.cts;
 
-
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.LayoutAnimationController;
 
-public class LayoutAnimationController_AnimationParametersTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LayoutAnimationController_AnimationParametersTest {
+    @Test
     public void testConstructor() {
         new LayoutAnimationController.AnimationParameters();
     }
diff --git a/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java b/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
index 23f8608..ddd1be4 100644
--- a/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/LinearInterpolatorTest.java
@@ -16,8 +16,16 @@
 
 package android.view.animation.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase2;
+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.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -25,37 +33,45 @@
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
-
 import android.view.cts.R;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link LinearInterpolator}.
  */
-public class LinearInterpolatorTest extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LinearInterpolatorTest {
     private static final float ALPHA_DELTA = 0.001f;
 
     /** It is defined in R.anim.alpha */
     private static final long LINEAR_ALPHA_DURATION = 500;
     private static final long LINEAR_ALPHA_TIME_STEP = LINEAR_ALPHA_DURATION / 5;
 
-    public LinearInterpolatorTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new LinearInterpolator();
         new LinearInterpolator(mActivity, null);
     }
 
+    @Test
     public void testGetInterpolation() {
         LinearInterpolator interpolator = new LinearInterpolator();
         final float delta1 = interpolator.getInterpolation(0.1f)
@@ -68,7 +84,8 @@
         assertEquals(delta2, delta3, ALPHA_DELTA);
     }
 
-    public void testLinearInterpolator() {
+    @Test
+    public void testLinearInterpolator() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.alpha);
         assertEquals(LINEAR_ALPHA_DURATION, anim.getDuration());
@@ -78,7 +95,7 @@
         anim.setInterpolator(interpolator);
         assertFalse(anim.hasStarted());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, anim);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow, anim);
 
         Transformation transformation = new Transformation();
         final long startTime = anim.getStartTime();
diff --git a/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
index afeba5c..e7961d5 100644
--- a/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/RotateAnimationTest.java
@@ -16,10 +16,19 @@
 
 package android.view.animation.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 android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
 import android.graphics.Matrix;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -27,32 +36,36 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.RotateAnimation;
 import android.view.animation.Transformation;
-
 import android.view.cts.R;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class RotateAnimationTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
-    private Activity mActivity;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RotateAnimationTest {
     private static final long DURATION = 1000;
     private static final float ROTATE_DELTA = 0.001f;
     private static final float FROM_DEGREE = 0.0f;
     private static final float TO_DEGREE = 90.0f;
 
-    public RotateAnimationTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructors() {
-
         // Test with null AttributeSet
         new RotateAnimation(mActivity, null);
 
@@ -79,7 +92,8 @@
         new RotateAnimation(-0.6f, -0.6f, Animation.ABSOLUTE, -0.6f, Animation.ABSOLUTE, -0.6f);
     }
 
-    public void testRotateAgainstOrigin(){
+    @Test
+    public void testRotateAgainstOrigin() throws Throwable {
         final View animWindowParent = mActivity.findViewById(R.id.anim_window_parent);
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         Transformation transformation = new Transformation();
@@ -93,7 +107,8 @@
                 animWindowParent.getWidth(), animWindowParent.getHeight());
         assertTrue(rotateAnimation.isInitialized());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, rotateAnimation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                rotateAnimation);
         final long startTime = rotateAnimation.getStartTime();
 
         Matrix expectedMatrix = new Matrix();
@@ -130,7 +145,8 @@
         }
     }
 
-    public void testRotateAgainstPoint(){
+    @Test
+    public void testRotateAgainstPoint() throws Throwable {
         final View animWindowParent = mActivity.findViewById(R.id.anim_window_parent);
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         Transformation transformation = new Transformation();
@@ -149,7 +165,8 @@
                 animWindowParent.getWidth(), animWindowParent.getHeight());
         assertTrue(rotateAnimation.isInitialized());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, rotateAnimation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                rotateAnimation);
         final long startTime = rotateAnimation.getStartTime();
 
         Matrix expectedMatrix = new Matrix();
diff --git a/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
index dc78fa9..c14d151 100644
--- a/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/ScaleAnimationTest.java
@@ -16,21 +16,34 @@
 
 package android.view.animation.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
 import android.graphics.Matrix;
-import android.test.ActivityInstrumentationTestCase2;
+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.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
 import android.view.animation.Animation;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.Transformation;
+import android.view.cts.R;
 
-public class ScaleAnimationTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScaleAnimationTest {
     private static long DURATION = 1000;
     private static float DELTA = 0.001f;
     private static float FROM_X = 1.0f;
@@ -41,18 +54,21 @@
     private static float PIVOT_Y = 0.6f;
     private static float MID_X = 0.8f;
     private static float MID_Y = 3.3f;
-    private AnimationTestCtsActivity mActivity;
 
-    public ScaleAnimationTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructors() {
         final XmlResourceParser parser = mActivity.getResources().getAnimation(
                 R.anim.anim_scale);
@@ -68,6 +84,7 @@
         new ScaleAnimation(FROM_X, TO_X, FROM_Y, TO_Y, PIVOT_X, PIVOT_Y);
     }
 
+    @Test
     public void testApplyTransformation() {
         final Transformation transformation = new Transformation();
         transformation.setTransformationType(Transformation.TYPE_MATRIX);
@@ -102,7 +119,8 @@
         assertTrue(Math.abs(trans2Y) < Math.abs(trans3Y));
     }
 
-    public void testApplyTransformationIndirectly() {
+    @Test
+    public void testApplyTransformationIndirectly() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final Transformation transformation = new Transformation();
         transformation.setTransformationType(Transformation.TYPE_MATRIX);
@@ -111,7 +129,8 @@
                 PIVOT_X, PIVOT_Y);
         scaleAnimation.setDuration(DURATION);
         scaleAnimation.initialize(50, 50, 100, 100);
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, scaleAnimation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                scaleAnimation);
 
         float values[] = new float[9];
         long startTime = scaleAnimation.getStartTime();
diff --git a/tests/tests/view/src/android/view/animation/cts/TransformationTest.java b/tests/tests/view/src/android/view/animation/cts/TransformationTest.java
index 7fe8c36..0c9e45f 100644
--- a/tests/tests/view/src/android/view/animation/cts/TransformationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/TransformationTest.java
@@ -16,16 +16,30 @@
 
 package android.view.animation.cts;
 
+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 android.graphics.Matrix;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.Transformation;
 
-public class TransformationTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TransformationTest {
+    private static final float COMPARISON_DELTA = 0.001f;
+
+    @Test
     public void testConstructor() {
         new Transformation();
     }
 
+    @Test
     public void testCompose() {
         final Transformation t1 = new Transformation();
         final Transformation t2 = new Transformation();
@@ -40,7 +54,7 @@
         Matrix expectedMatrix = new Matrix();
         expectedMatrix.setScale(9, 1);
         assertEquals(expectedMatrix, t2.getMatrix());
-        assertEquals(0.4f * 0.5f, t2.getAlpha());
+        assertEquals(0.4f * 0.5f, t2.getAlpha(), COMPARISON_DELTA);
         assertEquals(Transformation.TYPE_ALPHA, t2.getTransformationType());
 
         t1.setTransformationType(Transformation.TYPE_IDENTITY);
@@ -48,10 +62,11 @@
         expectedMatrix = new Matrix();
         expectedMatrix.setScale(27, 1);
         assertEquals(expectedMatrix, t2.getMatrix());
-        assertEquals(0.4f * 0.5f * 0.5f, t2.getAlpha());
+        assertEquals(0.4f * 0.5f * 0.5f, t2.getAlpha(), COMPARISON_DELTA);
         assertEquals(Transformation.TYPE_ALPHA, t2.getTransformationType());
     }
 
+    @Test
     public void testClear() {
         final Transformation t1 = new Transformation();
         final Transformation t2 = new Transformation();
@@ -76,11 +91,12 @@
     }
 
     private void assertTransformationEquals(Transformation expected, Transformation actual) {
-        assertEquals(expected.getAlpha(), actual.getAlpha());
+        assertEquals(expected.getAlpha(), actual.getAlpha(), COMPARISON_DELTA);
         assertEquals(expected.getMatrix(), actual.getMatrix());
         assertEquals(expected.getTransformationType(), actual.getTransformationType());
     }
 
+    @Test
     public void testAccessTransformationType() {
         final Transformation transformation = new Transformation();
 
@@ -100,6 +116,7 @@
         assertEquals(Transformation.TYPE_BOTH, transformation.getTransformationType());
     }
 
+    @Test
     public void testSet() {
         final Transformation t1 = new Transformation();
         t1.setAlpha(0.0f);
@@ -108,24 +125,27 @@
         assertTransformationEquals(t1, t2);
     }
 
+    @Test
     public void testAccessAlpha() {
         final Transformation transformation = new Transformation();
 
         transformation.setAlpha(0.0f);
-        assertEquals(0.0f, transformation.getAlpha());
+        assertEquals(0.0f, transformation.getAlpha(), 0.0f);
 
         transformation.setAlpha(0.5f);
-        assertEquals(0.5f, transformation.getAlpha());
+        assertEquals(0.5f, transformation.getAlpha(), 0.0f);
 
         transformation.setAlpha(1.0f);
-        assertEquals(1.0f, transformation.getAlpha());
+        assertEquals(1.0f, transformation.getAlpha(), 0.0f);
     }
 
+    @Test
     public void testToString() {
         assertNotNull(new Transformation().toString());
         assertNotNull(new Transformation().toShortString());
     }
 
+    @Test
     public void testGetMatrix() {
         final Matrix expected = new Matrix();
         final Transformation transformation = new Transformation();
diff --git a/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java b/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
index 06daa72..ee8b187 100644
--- a/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/TranslateAnimationTest.java
@@ -16,10 +16,19 @@
 
 package android.view.animation.cts;
 
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.XmlResourceParser;
 import android.graphics.Matrix;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -27,15 +36,17 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.view.animation.TranslateAnimation;
-
 import android.view.cts.R;
 
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class TranslateAnimationTest
-        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
-
-    private Activity mActivity;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TranslateAnimationTest {
     private static final long DURATION = 1000;
     private static final float POSITION_DELTA = 0.001f;
     private static final float FROM_X_DETLTA = 0.0f;
@@ -47,25 +58,28 @@
     private static final float RELATIVE_FROM_Y_DELTA = 0.0f;
     private static final float RELATIVE_TO_Y_DELTA = 0.4f;
 
-    public TranslateAnimationTest() {
-        super("android.view.cts", AnimationTestCtsActivity.class);
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AnimationTestCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructors() {
-
         // Test with null AttributeSet
         new TranslateAnimation(mActivity, null);
 
         final XmlResourceParser parser = mActivity.getResources().getAnimation(
                 R.anim.anim_translate);
         final AttributeSet attr = Xml.asAttributeSet(parser);
-        assertNotNull(attr);
+        Assert.assertNotNull(attr);
         // Test with real AttributeSet
         new TranslateAnimation(mActivity, attr);
 
@@ -83,7 +97,8 @@
                 Animation.RELATIVE_TO_SELF, -0.6f, Animation.RELATIVE_TO_SELF, -0.6f);
     }
 
-    public void testApplyTransformation(){
+    @Test
+    public void testApplyTransformation() throws Throwable {
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final Transformation transformation = new Transformation();
         final MyTranslateAnimation translateAnimation =
@@ -94,7 +109,8 @@
         translateAnimation.initialize(0, 0, 0, 0);
         assertTrue(translateAnimation.isInitialized());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, translateAnimation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                translateAnimation);
         final long startTime = translateAnimation.getStartTime();
 
         float values[] = new float[9];
@@ -141,7 +157,8 @@
         assertEquals(TO_Y_DELTA, values[Matrix.MTRANS_Y], POSITION_DELTA);
     }
 
-    public void testInitialize() {
+    @Test
+    public void testInitialize() throws Throwable {
         final View parent = mActivity.findViewById(R.id.anim_window_parent);
         final View animWindow = mActivity.findViewById(R.id.anim_window);
         final Transformation transformation = new Transformation();
@@ -162,7 +179,8 @@
         translateAnimation.setDuration(DURATION);
         translateAnimation.setInterpolator(new LinearInterpolator());
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), animWindow, translateAnimation);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
+                translateAnimation);
         final long startTime = translateAnimation.getStartTime();
 
         float values[] = new float[9];
@@ -187,7 +205,6 @@
     }
 
     private static class MyTranslateAnimation extends TranslateAnimation {
-
         public MyTranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta,
                 float toYDelta) {
             super(fromXDelta, toXDelta, fromYDelta, toYDelta);
diff --git a/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java b/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
index 3662e2c..ba781cf 100644
--- a/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
+++ b/tests/tests/view/src/android/view/cts/AbsSavedStateTest.java
@@ -16,85 +16,136 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+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.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.AbsSavedState;
 
-public class AbsSavedStateTest extends InstrumentationTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    // constant for test of writeToParcel
-    public static final int TEST_NUMBER = 1;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AbsSavedStateTest {
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorNullParcelable() {
+        new AbsSavedStateImpl((Parcelable) null);
+    }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullParcel() {
+        new AbsSavedStateImpl((Parcel) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullParcelAndClassLoader() {
+        new AbsSavedStateImpl(null, null);
+    }
+
+    @Test
     public void testConstructor() {
-        MockParcelable superState = new MockParcelable();
-        assertNotNull(superState);
-        new MockAbsSavedState(superState);
+        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);
+    @Test
+    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.
+        }
     }
 
+    @Test
     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/ActionModeCallback2Test.java b/tests/tests/view/src/android/view/cts/ActionModeCallback2Test.java
index e75b7ae..95b1929 100644
--- a/tests/tests/view/src/android/view/cts/ActionModeCallback2Test.java
+++ b/tests/tests/view/src/android/view/cts/ActionModeCallback2Test.java
@@ -16,17 +16,36 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
 import android.graphics.Rect;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
-public class ActionModeCallback2Test extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ActionModeCallback2Test {
     private static final int VIEW_WIDTH = 123;
     private static final int VIEW_HEIGHT = 456;
 
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testCallbackOnGetContentRectDefaultWithView() {
         View view = new View(mContext);
         view.setLeft(0);
@@ -35,7 +54,7 @@
         view.setBottom(VIEW_HEIGHT);
 
         Rect outRect = new Rect();
-        MockActionModeCallback2 callback = new MockActionModeCallback2();
+        ActionMode.Callback2 callback = new MockActionModeCallback2();
         callback.onGetContentRect(null, view, outRect);
 
         assertEquals(0, outRect.top);
@@ -44,9 +63,10 @@
         assertEquals(VIEW_WIDTH, outRect.right);
     }
 
+    @Test
     public void testCallbackOnGetContentRectDefaultWithoutView() {
         Rect outRect = new Rect();
-        MockActionModeCallback2 callback = new MockActionModeCallback2();
+        ActionMode.Callback2 callback = new MockActionModeCallback2();
         callback.onGetContentRect(null, null, outRect);
 
         assertEquals(0, outRect.top);
diff --git a/tests/tests/view/src/android/view/cts/ActionModeTest.java b/tests/tests/view/src/android/view/cts/ActionModeTest.java
index 534db31..e28173d 100644
--- a/tests/tests/view/src/android/view/cts/ActionModeTest.java
+++ b/tests/tests/view/src/android/view/cts/ActionModeTest.java
@@ -16,59 +16,96 @@
 
 package android.view.cts;
 
+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.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuInflater;
-import android.view.MenuItem;
 import android.view.View;
 
-public class ActionModeTest extends ActivityInstrumentationTestCase2<ActionModeCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    public ActionModeTest() {
-        super(ActionModeCtsActivity.class);
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ActionModeTest {
+    private Instrumentation mInstrumentation;
+    private ActionModeCtsActivity mActivity;
+
+    @Rule
+    public ActivityTestRule<ActionModeCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ActionModeCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
+    @Test
     public void testSetType() {
-        ActionMode actionMode = new MockActionMode();
-        assertEquals(ActionMode.TYPE_PRIMARY, actionMode.getType());
+        final ActionMode mockActionMode = new MockActionMode();
+        assertEquals(ActionMode.TYPE_PRIMARY, mockActionMode.getType());
 
-        actionMode.setType(ActionMode.TYPE_FLOATING);
-        assertEquals(ActionMode.TYPE_FLOATING, actionMode.getType());
+        mockActionMode.setType(ActionMode.TYPE_FLOATING);
+        assertEquals(ActionMode.TYPE_FLOATING, mockActionMode.getType());
 
-        actionMode.setType(ActionMode.TYPE_PRIMARY);
-        assertEquals(ActionMode.TYPE_PRIMARY, actionMode.getType());
+        mockActionMode.setType(ActionMode.TYPE_PRIMARY);
+        assertEquals(ActionMode.TYPE_PRIMARY, mockActionMode.getType());
     }
 
+    @Test
     public void testInvalidateContentRectDoesNotInvalidateFull() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode mockActionMode = spy(new MockActionMode());
 
-        actionMode.invalidateContentRect();
+        mockActionMode.invalidateContentRect();
 
-        assertFalse(actionMode.mInvalidateWasCalled);
+        verify(mockActionMode, never()).invalidate();
     }
 
-    public void testInvalidateContentRectOnFloatingCallsCallback() {
-        final View view = getActivity().contentView;
-        final MockActionModeCallback2 callback = new MockActionModeCallback2();
+    @Test
+    public void testInvalidateContentRectOnFloatingCallsCallback() throws Throwable {
+        final View view = mActivity.contentView;
+        final ActionMode.Callback2 mockCallback = mock(ActionMode.Callback2.class);
+        doReturn(Boolean.TRUE).when(mockCallback).onCreateActionMode(
+                any(ActionMode.class), any(Menu.class));
+        doReturn(Boolean.TRUE).when(mockCallback).onPrepareActionMode(
+                any(ActionMode.class), any(Menu.class));
 
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ActionMode mode = view.startActionMode(callback, ActionMode.TYPE_FLOATING);
-                assertNotNull(mode);
-                mode.invalidateContentRect();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            ActionMode mode = view.startActionMode(mockCallback, ActionMode.TYPE_FLOATING);
+            assertNotNull(mode);
+            mode.invalidateContentRect();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
-        assertTrue(callback.mIsOnGetContentRectCalled);
+        verify(mockCallback, atLeastOnce()).onGetContentRect(any(ActionMode.class), any(View.class),
+                any(Rect.class));
     }
 
+    @Test
     public void testSetAndGetTitleOptionalHint() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
 
         // Check default value.
         assertFalse(actionMode.getTitleOptionalHint());
@@ -79,8 +116,9 @@
         assertFalse(actionMode.getTitleOptionalHint());
     }
 
+    @Test
     public void testSetAndGetTag() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
         Object tag = new Object();
 
         // Check default value.
@@ -90,65 +128,39 @@
         assertSame(tag, actionMode.getTag());
     }
 
+    @Test
     public void testIsTitleOptional() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
 
         // Check default value.
         assertFalse(actionMode.isTitleOptional());
     }
 
+    @Test
     public void testIsUiFocusable() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
 
         // Check default value.
         assertTrue(actionMode.isUiFocusable());
     }
 
+    @Test
     public void testHide() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
 
         actionMode.hide(0);
         actionMode.hide(ActionMode.DEFAULT_HIDE_DURATION);
     }
 
+    @Test
     public void testOnWindowFocusChanged() {
-        MockActionMode actionMode = new MockActionMode();
+        final ActionMode actionMode = new MockActionMode();
 
         actionMode.onWindowFocusChanged(true);
         actionMode.onWindowFocusChanged(false);
     }
 
-    private static class MockActionModeCallback2 extends ActionMode.Callback2 {
-        boolean mIsOnGetContentRectCalled = false;
-
-        @Override
-        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            return true;
-        }
-
-        @Override
-        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-            return true;
-        }
-
-        @Override
-        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-            return false;
-        }
-
-        @Override
-        public void onDestroyActionMode(ActionMode mode) {}
-
-        @Override
-        public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
-            mIsOnGetContentRectCalled = true;
-            super.onGetContentRect(mode, view, outRect);
-        }
-    }
-
-    private static class MockActionMode extends ActionMode {
-        boolean mInvalidateWasCalled = false;
-
+    protected static class MockActionMode extends ActionMode {
         @Override
         public void setTitle(CharSequence title) {}
 
@@ -166,7 +178,6 @@
 
         @Override
         public void invalidate() {
-            mInvalidateWasCalled = true;
         }
 
         @Override
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
index 38f351c..6c95e1f 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerNativeTest.java
@@ -16,12 +16,20 @@
 
 package android.view.cts;
 
-import android.test.InstrumentationTestCase;
-import android.view.Choreographer;
+import static org.junit.Assert.fail;
 
-public class ChoreographerNativeTest extends InstrumentationTestCase {
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ChoreographerNativeTest {
     private long mChoreographerPtr;
-    private Choreographer mChoreographer;
 
     private static native long nativeGetChoreographer();
     private static native boolean nativePrepareChoreographerTests(long ptr);
@@ -32,24 +40,21 @@
         System.loadLibrary("ctsview_jni");
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mChoreographerPtr = nativeGetChoreographer();
-            }
-        });
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mChoreographerPtr = nativeGetChoreographer();
         if (!nativePrepareChoreographerTests(mChoreographerPtr)) {
             fail("Failed to setup choreographer tests");
         }
     }
 
+    @Test
     public void testPostCallbackWithoutDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithoutDelayEventuallyRunsCallbacks(mChoreographerPtr);
     }
 
+    @Test
     public void testPostCallbackWithDelayEventuallyRunsCallbacks() {
         nativeTestPostCallbackWithDelayEventuallyRunsCallbacks(mChoreographerPtr);
     }
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerTest.java b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
index 6862fac..d683759 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
@@ -16,10 +16,28 @@
 
 package android.view.cts;
 
-import android.test.InstrumentationTestCase;
+import static org.junit.Assert.assertEquals;
+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.verifyZeroInteractions;
+
+import android.os.SystemClock;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Choreographer;
 
-public class ChoreographerTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ChoreographerTest {
     private static final long NOMINAL_VSYNC_PERIOD = 16;
     private static final long DELAY_PERIOD = NOMINAL_VSYNC_PERIOD * 5;
     private static final long NANOS_PER_MS = 1000000;
@@ -27,17 +45,13 @@
 
     private Choreographer mChoreographer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mChoreographer = Choreographer.getInstance();
-            }
-        });
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mChoreographer = Choreographer.getInstance();
     }
 
+    @Test
     public void testFrameDelay() {
         assertTrue(Choreographer.getFrameDelay() > 0);
 
@@ -49,10 +63,11 @@
         Choreographer.setFrameDelay(oldFrameDelay);
     }
 
+    @Test
     public void testPostCallbackWithoutDelayEventuallyRunsCallbacks() {
-        MockRunnable addedCallback1 = new MockRunnable();
-        MockRunnable addedCallback2 = new MockRunnable();
-        MockRunnable removedCallback = new MockRunnable();
+        final Runnable addedCallback1 = mock(Runnable.class);
+        final Runnable addedCallback2 = mock(Runnable.class);
+        final Runnable removedCallback = mock(Runnable.class);
         try {
             // Add and remove a few callbacks.
             mChoreographer.postCallback(
@@ -65,21 +80,21 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
 
             // Sleep for a couple of frames.
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
             // We expect the remaining callbacks to have been invoked once.
-            assertEquals(1, addedCallback1.invocationCount);
-            assertEquals(1, addedCallback2.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            verify(addedCallback1, times(1)).run();
+            verify(addedCallback2, times(1)).run();
+            verifyZeroInteractions(removedCallback);
 
             // If we post a callback again, then it should be invoked again.
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
-            assertEquals(2, addedCallback1.invocationCount);
-            assertEquals(1, addedCallback2.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            verify(addedCallback1, times(2)).run();
+            verify(addedCallback2, times(1)).run();
+            verifyZeroInteractions(removedCallback);
 
             // If the token matches, the the callback should be removed.
             mChoreographer.postCallback(
@@ -88,9 +103,9 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
-            assertEquals(3, addedCallback1.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
+            verify(addedCallback1, times(3)).run();
+            verifyZeroInteractions(removedCallback);
 
             // If the action and token matches, then the callback should be removed.
             // If only the token matches, then the callback should not be removed.
@@ -100,9 +115,9 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
-            assertEquals(4, addedCallback1.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
+            verify(addedCallback1, times(4)).run();
+            verifyZeroInteractions(removedCallback);
         } finally {
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
@@ -113,9 +128,10 @@
         }
     }
 
+    @Test
     public void testPostCallbackWithDelayEventuallyRunsCallbacksAfterDelay() {
-        MockRunnable addedCallback = new MockRunnable();
-        MockRunnable removedCallback = new MockRunnable();
+        final Runnable addedCallback = mock(Runnable.class);
+        final Runnable removedCallback = mock(Runnable.class);
         try {
             // Add and remove a few callbacks.
             mChoreographer.postCallbackDelayed(
@@ -126,18 +142,18 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
 
             // Sleep for a couple of frames.
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
             // The callbacks should not have been invoked yet because of the delay.
-            assertEquals(0, addedCallback.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            verifyZeroInteractions(addedCallback);
+            verifyZeroInteractions(removedCallback);
 
             // Sleep for the rest of the delay time.
-            sleep(DELAY_PERIOD);
+            SystemClock.sleep(DELAY_PERIOD);
 
             // We expect the remaining callbacks to have been invoked.
-            assertEquals(1, addedCallback.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            verify(addedCallback, times(1)).run();
+            verifyZeroInteractions(removedCallback);
 
             // If the token matches, the the callback should be removed.
             mChoreographer.postCallbackDelayed(
@@ -146,9 +162,9 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN, DELAY_PERIOD);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
-            sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
-            assertEquals(2, addedCallback.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
+            verify(addedCallback, times(2)).run();
+            verifyZeroInteractions(removedCallback);
 
             // If the action and token matches, then the callback should be removed.
             // If only the token matches, then the callback should not be removed.
@@ -158,9 +174,9 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN, DELAY_PERIOD);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
-            sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
-            assertEquals(3, addedCallback.invocationCount);
-            assertEquals(0, removedCallback.invocationCount);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD);
+            verify(addedCallback, times(3)).run();
+            verifyZeroInteractions(removedCallback);
         } finally {
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, addedCallback, null);
@@ -169,30 +185,25 @@
         }
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testPostCallbackThrowsIfRunnableIsNull() {
-        try {
-            mChoreographer.postCallback(
-                    Choreographer.CALLBACK_ANIMATION, null, TOKEN);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException ex) {
-            // expected
-        }
+        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, null, TOKEN);
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testPostCallbackDelayedThrowsIfRunnableIsNull() {
-        try {
-            mChoreographer.postCallbackDelayed(
-                    Choreographer.CALLBACK_ANIMATION, null, TOKEN, DELAY_PERIOD);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException ex) {
-            // expected
-        }
+        mChoreographer.postCallbackDelayed( Choreographer.CALLBACK_ANIMATION, null, TOKEN,
+                DELAY_PERIOD);
     }
 
+    @Test
     public void testPostFrameCallbackWithoutDelayEventuallyRunsFrameCallbacks() {
-        MockFrameCallback addedFrameCallback1 = new MockFrameCallback();
-        MockFrameCallback addedFrameCallback2 = new MockFrameCallback();
-        MockFrameCallback removedFrameCallback = new MockFrameCallback();
+        final Choreographer.FrameCallback addedFrameCallback1 =
+                mock(Choreographer.FrameCallback.class);
+        final Choreographer.FrameCallback addedFrameCallback2 =
+                mock(Choreographer.FrameCallback.class);
+        final Choreographer.FrameCallback removedFrameCallback =
+                mock(Choreographer.FrameCallback.class);
         try {
             // Add and remove a few callbacks.
             long postTimeNanos = System.nanoTime();
@@ -202,28 +213,32 @@
             mChoreographer.removeFrameCallback(removedFrameCallback);
 
             // Sleep for a couple of frames.
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
             // We expect the remaining callbacks to have been invoked once.
-            assertEquals(1, addedFrameCallback1.invocationCount);
-            assertEquals(1, addedFrameCallback2.invocationCount);
-            assertEquals(0, removedFrameCallback.invocationCount);
-            assertTimeDeltaLessThan(addedFrameCallback1.frameTimeNanos - postTimeNanos,
+            ArgumentCaptor<Long> frameTimeNanosCaptor1 = ArgumentCaptor.forClass(Long.class);
+            ArgumentCaptor<Long> frameTimeNanosCaptor2 = ArgumentCaptor.forClass(Long.class);
+            verify(addedFrameCallback1, times(1)).doFrame(frameTimeNanosCaptor1.capture());
+            verify(addedFrameCallback2, times(1)).doFrame(frameTimeNanosCaptor2.capture());
+            verifyZeroInteractions(removedFrameCallback);
+
+            assertTimeDeltaLessThan(frameTimeNanosCaptor1.getValue() - postTimeNanos,
                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
-            assertTimeDeltaLessThan(addedFrameCallback2.frameTimeNanos - postTimeNanos,
+            assertTimeDeltaLessThan(frameTimeNanosCaptor2.getValue() - postTimeNanos,
                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
-            assertTimeDeltaLessThan(Math.abs(addedFrameCallback2.frameTimeNanos
-                    - addedFrameCallback1.frameTimeNanos), NOMINAL_VSYNC_PERIOD * NANOS_PER_MS);
+            assertTimeDeltaLessThan(
+                    Math.abs(frameTimeNanosCaptor2.getValue() - frameTimeNanosCaptor1.getValue()),
+                    NOMINAL_VSYNC_PERIOD * NANOS_PER_MS);
 
             // If we post a callback again, then it should be invoked again.
             postTimeNanos = System.nanoTime();
             mChoreographer.postFrameCallback(addedFrameCallback1);
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
-            assertEquals(2, addedFrameCallback1.invocationCount);
-            assertEquals(1, addedFrameCallback2.invocationCount);
-            assertEquals(0, removedFrameCallback.invocationCount);
-            assertTimeDeltaLessThan(addedFrameCallback1.frameTimeNanos - postTimeNanos,
+            verify(addedFrameCallback1, times(2)).doFrame(frameTimeNanosCaptor1.capture());
+            verify(addedFrameCallback2, times(1)).doFrame(frameTimeNanosCaptor2.capture());
+            verifyZeroInteractions(removedFrameCallback);
+            assertTimeDeltaLessThan(frameTimeNanosCaptor1.getAllValues().get(1) - postTimeNanos,
                     NOMINAL_VSYNC_PERIOD * 3 * NANOS_PER_MS);
         } finally {
             mChoreographer.removeFrameCallback(addedFrameCallback1);
@@ -232,9 +247,12 @@
         }
     }
 
+    @Test
     public void testPostFrameCallbackWithDelayEventuallyRunsFrameCallbacksAfterDelay() {
-        MockFrameCallback addedFrameCallback = new MockFrameCallback();
-        MockFrameCallback removedFrameCallback = new MockFrameCallback();
+        final Choreographer.FrameCallback addedFrameCallback =
+                mock(Choreographer.FrameCallback.class);
+        final Choreographer.FrameCallback removedFrameCallback =
+                mock(Choreographer.FrameCallback.class);
         try {
             // Add and remove a few callbacks.
             long postTimeNanos = System.nanoTime();
@@ -243,19 +261,20 @@
             mChoreographer.removeFrameCallback(removedFrameCallback);
 
             // Sleep for a couple of frames.
-            sleep(NOMINAL_VSYNC_PERIOD * 3);
+            SystemClock.sleep(NOMINAL_VSYNC_PERIOD * 3);
 
             // The callbacks should not have been invoked yet because of the delay.
-            assertEquals(0, addedFrameCallback.invocationCount);
-            assertEquals(0, removedFrameCallback.invocationCount);
+            verifyZeroInteractions(addedFrameCallback);
+            verifyZeroInteractions(removedFrameCallback);
 
             // Sleep for the rest of the delay time.
-            sleep(DELAY_PERIOD);
+            SystemClock.sleep(DELAY_PERIOD);
 
             // We expect the remaining callbacks to have been invoked.
-            assertEquals(1, addedFrameCallback.invocationCount);
-            assertEquals(0, removedFrameCallback.invocationCount);
-            assertTimeDeltaLessThan(addedFrameCallback.frameTimeNanos - postTimeNanos,
+            ArgumentCaptor<Long> frameTimeNanosCaptor = ArgumentCaptor.forClass(Long.class);
+            verify(addedFrameCallback, times(1)).doFrame(frameTimeNanosCaptor.capture());
+            verifyZeroInteractions(removedFrameCallback);
+            assertTimeDeltaLessThan(frameTimeNanosCaptor.getValue() - postTimeNanos,
                     (NOMINAL_VSYNC_PERIOD * 3 + DELAY_PERIOD) * NANOS_PER_MS);
         } finally {
             mChoreographer.removeFrameCallback(addedFrameCallback);
@@ -270,58 +289,18 @@
         }
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testPostFrameCallbackThrowsIfCallbackIsNull() {
-        try {
-            mChoreographer.postFrameCallback(null);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException ex) {
-            // expected
-        }
+        mChoreographer.postFrameCallback(null);
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testPostFrameCallbackDelayedThrowsIfCallbackIsNull() {
-        try {
-            mChoreographer.postFrameCallbackDelayed(null, DELAY_PERIOD);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException ex) {
-            // expected
-        }
+        mChoreographer.postFrameCallbackDelayed(null, DELAY_PERIOD);
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testRemoveFrameCallbackThrowsIfCallbackIsNull() {
-        try {
-            mChoreographer.removeFrameCallback(null);
-            fail("Expected IllegalArgumentException");
-        } catch (IllegalArgumentException ex) {
-            // expected
-        }
-    }
-
-    private void sleep(long time) {
-        try {
-            Thread.sleep(time);
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
-    }
-
-    private static final class MockRunnable implements Runnable {
-        public int invocationCount;
-
-        @Override
-        public void run() {
-            invocationCount += 1;
-        }
-    }
-
-    private static final class MockFrameCallback implements Choreographer.FrameCallback {
-        public long frameTimeNanos;
-        public int invocationCount;
-
-        @Override
-        public void doFrame(long frameTimeNanos) {
-            this.frameTimeNanos = frameTimeNanos;
-            invocationCount += 1;
-        }
+        mChoreographer.removeFrameCallback(null);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
index eaaea74..ade68e3 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
@@ -16,46 +16,63 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.app.ActionBar;
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
+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.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 
-public class ContentPaneFocusTest
-        extends ActivityInstrumentationTestCase2<ContentPaneCtsActivity> {
-    public ContentPaneFocusTest() {
-        super("android.view.cts", ContentPaneCtsActivity.class);
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ContentPaneFocusTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<ContentPaneCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ContentPaneCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
+    @Test
     public void testAccessActionBar() throws Throwable {
-        final Activity activity = getActivity();
+        final View v1 = mActivity.findViewById(R.id.view1);
+        mActivityRule.runOnUiThread(v1::requestFocus);
 
-        final View v1 = activity.findViewById(R.id.view1);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                v1.requestFocus();
-            }
-        });
-
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         sendControlChar('<');
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
-        ActionBar action = activity.getActionBar();
+        ActionBar action = mActivity.getActionBar();
         if (action == null || !action.isShowing()) {
             // No action bar, so we only needed to make sure that the shortcut didn't cause
             // the framework to crash.
             return;
         }
 
-        final View content = activity.findViewById(android.R.id.content);
+        final View content = mActivity.findViewById(android.R.id.content);
         assertNotNull(content);
         final ViewParent viewParent = content.getParent();
         assertNotNull(viewParent);
@@ -72,37 +89,24 @@
         assertNotNull(actionBarView);
         final View actionBar = actionBarView;
         // Should jump to the action bar after control-<
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertFalse(v1.hasFocus());
-                assertTrue(actionBar.hasFocus());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertFalse(v1.hasFocus());
+            assertTrue(actionBar.hasFocus());
         });
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        mInstrumentation.waitForIdleSync();
 
         // Should jump to the first view again.
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(v1.hasFocus());
-            }
-        });
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> assertTrue(v1.hasFocus()));
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
+        mInstrumentation.waitForIdleSync();
 
-        boolean isTouchScreen = activity.getPackageManager().
+        boolean isTouchScreen = mActivity.getPackageManager().
                 hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
         if (isTouchScreen) {
             // Now it shouldn't go up to action bar -- it doesn't allow taking focus once left
             // but only for touch screens.
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    assertTrue(v1.hasFocus());
-                }
-            });
+            mActivityRule.runOnUiThread(() -> assertTrue(v1.hasFocus()));
         }
     }
 
@@ -117,7 +121,7 @@
             KeyEvent event = events[i];
             KeyEvent controlKey = new KeyEvent(time, time, event.getAction(), event.getKeyCode(),
                     event.getRepeatCount(), event.getMetaState() | controlOn);
-            getInstrumentation().sendKeySync(controlKey);
+            mInstrumentation.sendKeySync(controlKey);
             Thread.sleep(2);
         }
         sendControlKey(KeyEvent.ACTION_UP);
@@ -127,7 +131,7 @@
         long time = SystemClock.uptimeMillis();
         KeyEvent keyEvent = new KeyEvent(time, time, action, KeyEvent.KEYCODE_CTRL_LEFT, 0,
                 KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON);
-        getInstrumentation().sendKeySync(keyEvent);
+        mInstrumentation.sendKeySync(keyEvent);
         Thread.sleep(2);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
index ccf37949..2e1b929 100644
--- a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
+++ b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
@@ -16,22 +16,35 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
-import android.test.AndroidTestCase;
+import android.content.res.TypedArray;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ContextThemeWrapper;
 
-import android.view.cts.R;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class ContextThemeWrapperTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ContextThemeWrapperTest {
     private static final int SYSTEM_DEFAULT_THEME = 0;
 
-    private static class MocContextThemeWrapper extends ContextThemeWrapper {
+    private Context mContext;
+
+    private static class MockContextThemeWrapper extends ContextThemeWrapper {
         public boolean isOnApplyThemeResourceCalled;
-        public MocContextThemeWrapper(Context base, int themeres) {
+        public MockContextThemeWrapper(Context base, int themeres) {
             super(base, themeres);
         }
 
@@ -42,42 +55,51 @@
         }
     }
 
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() {
         new ContextThemeWrapper();
 
-        new ContextThemeWrapper(getContext(), R.style.TextAppearance);
+        new ContextThemeWrapper(mContext, R.style.TextAppearance);
 
-        new ContextThemeWrapper(getContext(), getContext().getTheme());
+        new ContextThemeWrapper(mContext, mContext.getTheme());
     }
 
+    @Test
     public void testAccessTheme() {
-        Context context = getContext();
         ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
-                context, SYSTEM_DEFAULT_THEME);
+                mContext, SYSTEM_DEFAULT_THEME);
         // set Theme to TextAppearance
         contextThemeWrapper.setTheme(R.style.TextAppearance);
         TypedArray ta =
             contextThemeWrapper.getTheme().obtainStyledAttributes(R.styleable.TextAppearance);
 
         // assert theme style of TextAppearance
-        assertEqualsTextAppearanceStyle(ta);
+        verifyIdenticalTextAppearanceStyle(ta);
     }
 
+    @Test
     public void testGetSystemService() {
-        // new the ContextThemeWrapper instance
-        Context context = getContext();
-        int themeres = R.style.TextAppearance;
-        MocContextThemeWrapper contextThemeWrapper = new MocContextThemeWrapper(context, themeres);
+        // Note that we can't use Mockito since ContextThemeWrapper.onApplyThemeResource is
+        // protected
+        final MockContextThemeWrapper contextThemeWrapper =
+                new MockContextThemeWrapper(mContext, R.style.TextAppearance);
         contextThemeWrapper.getTheme();
         assertTrue(contextThemeWrapper.isOnApplyThemeResourceCalled);
+
         // All service get from contextThemeWrapper just the same as this context get,
         // except Context.LAYOUT_INFLATER_SERVICE.
-        assertEquals(context.getSystemService(Context.ACTIVITY_SERVICE),
+        assertEquals(mContext.getSystemService(Context.ACTIVITY_SERVICE),
                 contextThemeWrapper.getSystemService(Context.ACTIVITY_SERVICE));
-        assertNotSame(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE),
+        assertNotSame(mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE),
                 contextThemeWrapper.getSystemService(Context.LAYOUT_INFLATER_SERVICE));
     }
 
+    @Test
     public void testAttachBaseContext() {
         assertTrue((new ContextThemeWrapper() {
             public boolean test() {
@@ -86,7 +108,7 @@
                 // As ContextThemeWrapper is a context, we will attachBaseContext to
                 // two different ContextThemeWrapper instances.
                 try {
-                    attachBaseContext(new ContextThemeWrapper(getContext(),
+                    attachBaseContext(new ContextThemeWrapper(mContext,
                             R.style.TextAppearance));
                 } catch(IllegalStateException e) {
                     fail("test attachBaseContext fail");
@@ -103,13 +125,13 @@
         }).test());
     }
 
+    @Test
     public void testApplyOverrideConfiguration() {
-        Context context = getContext();
-        final int realDensity = context.getResources().getConfiguration().densityDpi;
+        final int realDensity = mContext.getResources().getConfiguration().densityDpi;
         final int expectedDensity = realDensity + 1;
 
         ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
-                context, SYSTEM_DEFAULT_THEME);
+                mContext, SYSTEM_DEFAULT_THEME);
 
         Configuration overrideConfig = new Configuration();
         overrideConfig.densityDpi = expectedDensity;
@@ -119,11 +141,11 @@
         assertEquals(expectedDensity, actualConfiguration.densityDpi);
     }
 
-    private void assertEqualsTextAppearanceStyle(TypedArray ta) {
+    private void verifyIdenticalTextAppearanceStyle(TypedArray ta) {
         final int defValue = -1;
         // get Theme and assert
-        Resources.Theme expected = getContext().getResources().newTheme();
-        expected.setTo(getContext().getTheme());
+        Resources.Theme expected = mContext.getResources().newTheme();
+        expected.setTo(mContext.getTheme());
         expected.applyStyle(R.style.TextAppearance, true);
         TypedArray expectedTa = expected.obtainStyledAttributes(R.styleable.TextAppearance);
         assertEquals(expectedTa.getIndexCount(), ta.getIndexCount());
@@ -136,7 +158,7 @@
         assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHighlight, defValue),
                 ta.getColor(R.styleable.TextAppearance_textColorHighlight, defValue));
         assertEquals(expectedTa.getDimension(R.styleable.TextAppearance_textSize, defValue),
-                ta.getDimension(R.styleable.TextAppearance_textSize, defValue));
+                ta.getDimension(R.styleable.TextAppearance_textSize, defValue), 0.0f);
         assertEquals(expectedTa.getInt(R.styleable.TextAppearance_textStyle, defValue),
                 ta.getInt(R.styleable.TextAppearance_textStyle, defValue));
     }
diff --git a/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java b/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java
new file mode 100644
index 0000000..957ee10
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/DisplayRefreshRateCtsActivity.java
@@ -0,0 +1,144 @@
+/*
+ * 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.opengl.GLSurfaceView;
+import android.util.Log;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class DisplayRefreshRateCtsActivity extends GLSurfaceViewCtsActivity {
+    private static final String TAG = "DisplayRefreshRateAct";
+
+    public class FpsResult {
+        private float mFps;
+        private boolean mValid = false;
+        private boolean mRestartRequested = false;
+
+        public final synchronized void notifyResult(float fps) {
+            if (!mValid) {
+                mFps = fps;
+                mValid = true;
+                notifyAll();
+            }
+        }
+
+        public final synchronized float waitResult() {
+            while (!mValid) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {/* ignore and retry */}
+            }
+            return mFps;
+        }
+
+        public synchronized void restart() {
+            mRestartRequested = true;
+            mValid = false;
+        }
+        public synchronized boolean restartNecessary() {
+            return mRestartRequested;
+        }
+        public synchronized void ackRestart() {
+            mRestartRequested = false;
+        }
+    }
+
+    private class Renderer implements GLSurfaceView.Renderer {
+        // Measurement knobs.
+        // NB: Some devices need a surprisingly long warmup period before the
+        // framerate becomes stable.
+        private static final float WARMUP_SECONDS = 2.0f;
+        private static final float TEST_SECONDS   = 8.0f;
+
+        // Test states
+        private static final int STATE_START  = 0;
+        private static final int STATE_WARMUP = 1;
+        private static final int STATE_TEST   = 2;
+        private static final int STATE_DONE   = 3;
+
+        private FpsResult mResult;
+        private int       mState     = STATE_START;
+        private float     mStartTime = 0.0f;
+        private int       mNumFrames = 0;
+
+        public Renderer(FpsResult result) {
+            mResult = result;
+        }
+
+        public void onDrawFrame(GL10 gl) {
+            float t = (float)System.nanoTime() * 1.0e-9f;
+            switch (mState) {
+                case STATE_START:
+                    mStartTime = t;
+                    mState = STATE_WARMUP;
+                    break;
+
+                case STATE_WARMUP:
+                    if ((t - mStartTime) >= WARMUP_SECONDS) {
+                        mStartTime = t;
+                        mNumFrames = 0;
+                        mState = STATE_TEST;
+                    }
+                    break;
+
+                case STATE_TEST:
+                    mNumFrames++;
+                    float elapsed = t - mStartTime;
+                    if (elapsed >= TEST_SECONDS) {
+                        mResult.notifyResult((float)mNumFrames / elapsed);
+                        mState = STATE_DONE;
+                    }
+                    break;
+
+                case STATE_DONE:
+                    if (mResult.restartNecessary()) {
+                        mResult.ackRestart();
+                        mState = STATE_START;
+                        Log.d(TAG, "restarting");
+                    }
+                    break;
+            }
+
+            // prevent unwanted optimizations or hidden costs (e.g. reading
+            // previous frame on tilers).
+            gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+            gl.glClear(gl.GL_COLOR_BUFFER_BIT);
+        }
+
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            // Do nothing.
+        }
+
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+            // Do nothing.
+        }
+    }
+
+    private FpsResult mResult = new FpsResult();
+
+    @Override
+    protected void configureGLSurfaceView() {
+        mView.setRenderer(new Renderer(mResult));
+        mView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+    }
+
+    public FpsResult getFpsResult() {
+        return mResult;
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java b/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
index 5120604..51ec7f2 100644
--- a/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
+++ b/tests/tests/view/src/android/view/cts/DisplayRefreshRateTest.java
@@ -16,19 +16,21 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
-import android.opengl.GLSurfaceView;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.os.SystemClock;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
 import android.view.Display;
 import android.view.WindowManager;
-import android.util.Log;
 
-import java.lang.InterruptedException;
-import java.lang.Thread;
-import java.util.ArrayList;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test that the screen refresh rate claimed by
@@ -37,9 +39,9 @@
  * Display.getRefreshRate() -- using GL is just an easy and hopefully reliable
  * way of measuring the actual refresh rate.
  */
-public class DisplayRefreshRateTest extends
-        ActivityInstrumentationTestCase2<GLSurfaceViewCtsActivity> {
-
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayRefreshRateTest {
     // The test passes if
     //   abs(measured_fps - Display.getRefreshRate()) <= FPS_TOLERANCE.
     // A smaller tolerance requires a more accurate measured_fps in order
@@ -48,131 +50,24 @@
 
     private static final String TAG = "DisplayRefreshRateTest";
 
-    private class FpsResult {
-        private float mFps;
-        private boolean mValid = false;
-        private boolean mRestartRequested = false;
+    @Rule
+    public ActivityTestRule<DisplayRefreshRateCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DisplayRefreshRateCtsActivity.class);
 
-        public final synchronized void notifyResult(float fps) {
-            if (!mValid) {
-                mFps = fps;
-                mValid = true;
-                notifyAll();
-            }
-        }
+    private DisplayRefreshRateCtsActivity mActivity;
+    private DisplayRefreshRateCtsActivity.FpsResult mFpsResult;
 
-        public final synchronized float waitResult() {
-            while (!mValid) {
-                try {
-                    wait();
-                } catch (InterruptedException e) {/* ignore and retry */}
-            }
-            return mFps;
-        }
-
-        public synchronized void restart() {
-            mRestartRequested = true;
-            mValid = false;
-        }
-        public synchronized boolean restartNecessary() {
-            return mRestartRequested;
-        }
-        public synchronized void ackRestart() {
-            mRestartRequested = false;
-        }
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mFpsResult = mActivity.getFpsResult();
     }
 
-    private class Renderer implements GLSurfaceView.Renderer {
-        // Measurement knobs.
-        // NB: Some devices need a surprisingly long warmup period before the
-        // framerate becomes stable.
-        private static final float WARMUP_SECONDS = 2.0f;
-        private static final float TEST_SECONDS   = 8.0f;
-
-        // Test states
-        private static final int STATE_START  = 0;
-        private static final int STATE_WARMUP = 1;
-        private static final int STATE_TEST   = 2;
-        private static final int STATE_DONE   = 3;
-
-        private FpsResult mResult;
-        private int       mState     = STATE_START;
-        private float     mStartTime = 0.0f;
-        private int       mNumFrames = 0;
-
-        public Renderer(FpsResult result) {
-            mResult = result;
-        }
-
-        public void onDrawFrame(GL10 gl) {
-            float t = (float)System.nanoTime() * 1.0e-9f;
-            switch (mState) {
-                case STATE_START:
-                    mStartTime = t;
-                    mState = STATE_WARMUP;
-                    break;
-
-                case STATE_WARMUP:
-                    if ((t - mStartTime) >= WARMUP_SECONDS) {
-                        mStartTime = t;
-                        mNumFrames = 0;
-                        mState = STATE_TEST;
-                    }
-                    break;
-
-                case STATE_TEST:
-                    mNumFrames++;
-                    float elapsed = t - mStartTime;
-                    if (elapsed >= TEST_SECONDS) {
-                        mResult.notifyResult((float)mNumFrames / elapsed);
-                        mState = STATE_DONE;
-                    }
-                    break;
-
-                case STATE_DONE:
-                    if (mResult.restartNecessary()) {
-                        mResult.ackRestart();
-                        mState = STATE_START;
-                        Log.d(TAG, "restarting");
-                    }
-                    break;
-            }
-
-            // prevent unwanted optimizations or hidden costs (e.g. reading
-            // previous frame on tilers).
-            gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-            gl.glClear(gl.GL_COLOR_BUFFER_BIT);
-        }
-
-        public void onSurfaceChanged(GL10 gl, int width, int height) {
-            // Do nothing.
-        }
-
-        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-            // Do nothing.
-        }
-    }
-
-    private FpsResult mResult;
-
-    public DisplayRefreshRateTest() {
-        super(GLSurfaceViewCtsActivity.class);
-        mResult = new FpsResult();
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        GLSurfaceViewCtsActivity.setRenderer(new Renderer(mResult));
-        GLSurfaceViewCtsActivity.setRenderMode(
-                GLSurfaceView.RENDERMODE_CONTINUOUSLY);
-    }
-
-    public void testRefreshRate() throws java.lang.InterruptedException {
+    @Test
+    public void testRefreshRate() {
         boolean fpsOk = false;
-        GLSurfaceViewCtsActivity activity = getActivity();
 
-        WindowManager wm = (WindowManager)activity
+        WindowManager wm = (WindowManager) mActivity
                 .getView()
                 .getContext()
                 .getSystemService(Context.WINDOW_SERVICE);
@@ -180,21 +75,20 @@
         float claimedFps = dpy.getRefreshRate();
 
         for (int i = 0; i < 3; i++) {
-            float achievedFps = mResult.waitResult();
+            float achievedFps = mFpsResult.waitResult();
             Log.d(TAG, "claimed " + claimedFps + " fps, " +
                        "achieved " + achievedFps + " fps");
             fpsOk = Math.abs(claimedFps - achievedFps) <= FPS_TOLERANCE;
             if (fpsOk) {
                 break;
             } else {
-                // it could be other sctivity like bug report capturing for other failures
+                // it could be other activity like bug report capturing for other failures
                 // sleep for a while and re-try
-                Thread.sleep(10000);
-                mResult.restart();
+                SystemClock.sleep(10000);
+                mFpsResult.restart();
             }
         }
-        activity.finish();
+        mActivity.finish();
         assertTrue(fpsOk);
     }
-
 }
diff --git a/tests/tests/view/src/android/view/cts/DragDropActivity.java b/tests/tests/view/src/android/view/cts/DragDropActivity.java
index b4324e3..e4e4fdc 100644
--- a/tests/tests/view/src/android/view/cts/DragDropActivity.java
+++ b/tests/tests/view/src/android/view/cts/DragDropActivity.java
@@ -16,8 +16,6 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
diff --git a/tests/tests/view/src/android/view/cts/DragDropTest.java b/tests/tests/view/src/android/view/cts/DragDropTest.java
index 968dc7b..64c170c 100644
--- a/tests/tests/view/src/android/view/cts/DragDropTest.java
+++ b/tests/tests/view/src/android/view/cts/DragDropTest.java
@@ -16,10 +16,14 @@
 
 package android.view.cts;
 
-import com.android.internal.util.ArrayUtils;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
 
 import android.app.Instrumentation;
 import android.app.UiAutomation;
+import android.content.ClipData;
+import android.content.ClipDescription;
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
@@ -31,21 +35,18 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.internal.util.ArrayUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.InterruptedException;
-import java.lang.StringBuilder;
-import java.lang.Thread;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.Objects;
-
-import static junit.framework.TestCase.*;
 
 @RunWith(AndroidJUnit4.class)
 public class DragDropTest {
@@ -62,12 +63,44 @@
 
     private CountDownLatch mEndReceived;
 
-    static boolean equal(DragEvent ev1, DragEvent ev2) {
+    private static boolean equal(ClipDescription d1, ClipDescription d2) {
+        if ((d1 == null) != (d2 == null)) {
+            return false;
+        }
+        if (d1 == null) {
+            return true;
+        }
+        return d1.getLabel().equals(d2.getLabel()) &&
+                d1.getMimeTypeCount() == 1 && d2.getMimeTypeCount() == 1 &&
+                d1.getMimeType(0).equals(d2.getMimeType(0));
+    }
+
+    private static boolean equal(ClipData.Item i1, ClipData.Item i2) {
+        return Objects.equals(i1.getIntent(), i2.getIntent()) &&
+                Objects.equals(i1.getHtmlText(), i2.getHtmlText()) &&
+                Objects.equals(i1.getText(), i2.getText()) &&
+                Objects.equals(i1.getUri(), i2.getUri());
+    }
+
+    private static boolean equal(ClipData d1, ClipData d2) {
+        if ((d1 == null) != (d2 == null)) {
+            return false;
+        }
+        if (d1 == null) {
+            return true;
+        }
+        return equal(d1.getDescription(), d2.getDescription()) &&
+                Objects.equals(d1.getIcon(), d2.getIcon()) &&
+                d1.getItemCount() == 1 && d2.getItemCount() == 1 &&
+                equal(d1.getItemAt(0), d2.getItemAt(0));
+    }
+
+    private static boolean equal(DragEvent ev1, DragEvent ev2) {
         return ev1.getAction() == ev2.getAction() &&
                 ev1.getX() == ev2.getX() &&
                 ev1.getY() == ev2.getY() &&
-                Objects.equals(ev1.getClipData(), ev2.getClipData()) &&
-                Objects.equals(ev1.getClipDescription(), ev2.getClipDescription()) &&
+                equal(ev1.getClipData(), ev2.getClipData()) &&
+                equal(ev1.getClipDescription(), ev2.getClipDescription()) &&
                 Objects.equals(ev1.getDragAndDropPermissions(), ev2.getDragAndDropPermissions()) &&
                 Objects.equals(ev1.getLocalState(), ev2.getLocalState()) &&
                 ev1.getResult() == ev2.getResult();
@@ -92,8 +125,19 @@
     final private ArrayList<LogEntry> mActual = new ArrayList<LogEntry> ();
     final private ArrayList<LogEntry> mExpected = new ArrayList<LogEntry> ();
 
+    private static ClipDescription createClipDescription() {
+        return new ClipDescription("TestLabel", new String[]{"text/plain"});
+    }
+
+    private static ClipData createClipData() {
+        return new ClipData(createClipDescription(), new ClipData.Item("TestText"));
+    }
+
     static private DragEvent obtainDragEvent(int action, int x, int y, boolean result) {
-        return DragEvent.obtain(action, x, y, null, null, null, null, result);
+        final ClipDescription description =
+                action != DragEvent.ACTION_DRAG_ENDED ? createClipDescription() : null;
+        final ClipData data = action == DragEvent.ACTION_DROP ? createClipData() : null;
+        return DragEvent.obtain(action, x, y, null, description, data, null, result);
     }
 
     private void logEvent(View v, DragEvent ev) {
@@ -269,7 +313,7 @@
             // Start drag.
             View v = mActivity.findViewById(R.id.draggable);
             assertTrue("Couldn't start drag",
-                    v.startDragAndDrop(null, new View.DragShadowBuilder(v), null, 0));
+                    v.startDragAndDrop(createClipData(), new View.DragShadowBuilder(v), null, 0));
         });
     }
 
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
index d2fa729..ae0b4bf 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderCtsActivity.java
@@ -16,12 +16,8 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
-import android.content.Context;
 import android.os.Bundle;
-import android.util.AttributeSet;
 import android.view.ViewGroup;
 import android.widget.Button;
 
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 6b3b784..db2ee10 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -16,16 +16,27 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.FocusFinder;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 
-public class FocusFinderTest extends ActivityInstrumentationTestCase2<FocusFinderCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FocusFinderTest {
     private FocusFinder mFocusFinder;
     private ViewGroup mLayout;
     private Button mTopLeft;
@@ -33,31 +44,32 @@
     private Button mBottomLeft;
     private Button mBottomRight;
 
-    public FocusFinderTest() {
-        super("android.view.cts", FocusFinderCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<FocusFinderCtsActivity> mActivityRule =
+            new ActivityTestRule<>(FocusFinderCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        FocusFinderCtsActivity activity = mActivityRule.getActivity();
+
         mFocusFinder = FocusFinder.getInstance();
-        mLayout = getActivity().layout;
-        mTopLeft = getActivity().topLeftButton;
-        mTopRight = getActivity().topRightButton;
-        mBottomLeft = getActivity().bottomLeftButton;
-        mBottomRight = getActivity().bottomRightButton;
+        mLayout = activity.layout;
+        mTopLeft = activity.topLeftButton;
+        mTopRight = activity.topRightButton;
+        mBottomLeft = activity.bottomLeftButton;
+        mBottomRight = activity.bottomRightButton;
         mTopLeft.setNextFocusLeftId(View.NO_ID);
         mTopRight.setNextFocusLeftId(View.NO_ID);
         mBottomLeft.setNextFocusLeftId(View.NO_ID);
         mBottomRight.setNextFocusLeftId(View.NO_ID);
     }
 
+    @Test
     public void testGetInstance() {
-        mFocusFinder = null;
-        mFocusFinder = FocusFinder.getInstance();
         assertNotNull(mFocusFinder);
     }
 
+    @Test
     public void testFindNextFocus() {
         /*
          * Go clockwise around the buttons from the top left searching for focus.
@@ -68,22 +80,23 @@
          * | 3 | 4 |
          * +---+---+
          */
-        assertNextFocus(mTopLeft, View.FOCUS_RIGHT, mTopRight);
-        assertNextFocus(mTopRight, View.FOCUS_DOWN, mBottomRight);
-        assertNextFocus(mBottomRight, View.FOCUS_LEFT, mBottomLeft);
-        assertNextFocus(mBottomLeft, View.FOCUS_UP, mTopLeft);
+        verifyNextFocus(mTopLeft, View.FOCUS_RIGHT, mTopRight);
+        verifyNextFocus(mTopRight, View.FOCUS_DOWN, mBottomRight);
+        verifyNextFocus(mBottomRight, View.FOCUS_LEFT, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_UP, mTopLeft);
 
-        assertNextFocus(null, View.FOCUS_RIGHT, mTopLeft);
-        assertNextFocus(null, View.FOCUS_DOWN, mTopLeft);
-        assertNextFocus(null, View.FOCUS_LEFT, mBottomRight);
-        assertNextFocus(null, View.FOCUS_UP, mBottomRight);
+        verifyNextFocus(null, View.FOCUS_RIGHT, mTopLeft);
+        verifyNextFocus(null, View.FOCUS_DOWN, mTopLeft);
+        verifyNextFocus(null, View.FOCUS_LEFT, mBottomRight);
+        verifyNextFocus(null, View.FOCUS_UP, mBottomRight);
     }
 
-    private void assertNextFocus(View currentFocus, int direction, View expectedNextFocus) {
+    private void verifyNextFocus(View currentFocus, int direction, View expectedNextFocus) {
         View actualNextFocus = mFocusFinder.findNextFocus(mLayout, currentFocus, direction);
         assertEquals(expectedNextFocus, actualNextFocus);
     }
 
+    @Test
     public void testFindNextFocusFromRect() {
         /*
          * Create a small rectangle on the border between the top left and top right buttons.
@@ -99,8 +112,8 @@
         rect.offset(mTopLeft.getWidth() / 2, 0);
         rect.inset(mTopLeft.getWidth() / 4, mTopLeft.getHeight() / 4);
 
-        assertNextFocusFromRect(rect, View.FOCUS_LEFT, mTopLeft);
-        assertNextFocusFromRect(rect, View.FOCUS_RIGHT, mTopRight);
+        verifytNextFocusFromRect(rect, View.FOCUS_LEFT, mTopLeft);
+        verifytNextFocusFromRect(rect, View.FOCUS_RIGHT, mTopRight);
 
         /*
          * Create a small rectangle on the border between the top left and bottom left buttons.
@@ -115,15 +128,16 @@
         rect.offset(0, mTopRight.getHeight() / 2);
         rect.inset(mTopLeft.getWidth() / 4, mTopLeft.getHeight() / 4);
 
-        assertNextFocusFromRect(rect, View.FOCUS_UP, mTopLeft);
-        assertNextFocusFromRect(rect, View.FOCUS_DOWN, mBottomLeft);
+        verifytNextFocusFromRect(rect, View.FOCUS_UP, mTopLeft);
+        verifytNextFocusFromRect(rect, View.FOCUS_DOWN, mBottomLeft);
     }
 
-    private void assertNextFocusFromRect(Rect rect, int direction, View expectedNextFocus) {
+    private void verifytNextFocusFromRect(Rect rect, int direction, View expectedNextFocus) {
         View actualNextFocus = mFocusFinder.findNextFocusFromRect(mLayout, rect, direction);
         assertEquals(expectedNextFocus, actualNextFocus);
     }
 
+    @Test
     public void testFindNearestTouchable() {
         /*
          * Table layout with two rows and coordinates are relative to those parent rows.
@@ -174,36 +188,37 @@
         assertEquals(-1, deltas[1]);
     }
 
+    @Test
     public void testFindNextAndPrevFocusAvoidingChain() {
         mBottomRight.setNextFocusForwardId(mBottomLeft.getId());
         mBottomLeft.setNextFocusForwardId(mTopRight.getId());
         // Follow the chain
-        assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mBottomLeft);
-        assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
-        assertNextFocus(mTopRight, View.FOCUS_BACKWARD, mBottomLeft);
-        assertNextFocus(mBottomLeft, View.FOCUS_BACKWARD, mBottomRight);
+        verifyNextFocus(mBottomRight, View.FOCUS_FORWARD, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mTopRight, View.FOCUS_BACKWARD, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_BACKWARD, mBottomRight);
 
         // Now go to the one not in the chain
-        assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
-        assertNextFocus(mBottomRight, View.FOCUS_BACKWARD, mTopLeft);
+        verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+        verifyNextFocus(mBottomRight, View.FOCUS_BACKWARD, mTopLeft);
 
         // Now go back to the top of the chain
-        assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mBottomRight);
-        assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mTopRight);
+        verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mBottomRight);
+        verifyNextFocus(mTopLeft, View.FOCUS_BACKWARD, mTopRight);
 
         // Now make the chain a circle -- this is the pathological case
         mTopRight.setNextFocusForwardId(mBottomRight.getId());
         // Fall back to the next one in a chain.
-        assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
-        assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mBottomRight);
+        verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mTopLeft, View.FOCUS_BACKWARD, mBottomRight);
 
         //Now do branching focus changes
         mTopRight.setNextFocusForwardId(View.NO_ID);
         mBottomRight.setNextFocusForwardId(mTopRight.getId());
-        assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mTopRight);
-        assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mBottomRight, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
         // From the tail, it jumps out of the chain
-        assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+        verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
 
         // Back from the head of a tree goes out of the tree
         // We don't know which is the head of the focus chain since it is branching.
diff --git a/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java b/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
index 86a1c9e..56fd97b 100644
--- a/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/FocusHandlingCtsActivity.java
@@ -16,8 +16,6 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
diff --git a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
index dac3a1922..25c7861 100644
--- a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
@@ -16,56 +16,56 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.os.Looper;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-import android.view.cts.util.ViewTestUtils;
+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.FrameMetrics;
-import android.view.View;
 import android.view.Window;
 import android.widget.ScrollView;
 
-import java.lang.Thread;
-import java.lang.Exception;
-import java.lang.System;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class FrameMetricsListenerTest extends ActivityInstrumentationTestCase2<MockActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FrameMetricsListenerTest {
     private Instrumentation mInstrumentation;
-    private Window.OnFrameMetricsAvailableListener mFrameMetricsListener;
     private Activity mActivity;
 
-    public FrameMetricsListenerTest() {
-        super(MockActivity.class);
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule =
+            new ActivityTestRule<>(MockActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-    }
-
-    private void layout(final int layoutId) {
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(layoutId);
-            }
-        });
+    private void layout(final int layoutId) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layoutId));
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testReceiveData() throws Throwable {
         layout(R.layout.scrollview_layout);
         final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
@@ -73,48 +73,33 @@
         final Handler handler = new Handler(Looper.getMainLooper());
         final Window myWindow = mActivity.getWindow();
         final Window.OnFrameMetricsAvailableListener listener =
-            new Window.OnFrameMetricsAvailableListener() {
-               @Override
-               public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
-                       int dropCount) {
-                   assertEquals(myWindow, window);
-                   assertEquals(0, dropCount);
-                   data.add(new FrameMetrics(frameMetrics));
-               }
+            (Window window, FrameMetrics frameMetrics, int dropCount) -> {
+                assertEquals(myWindow, window);
+                assertEquals(0, dropCount);
+                callGetMetric(frameMetrics);
+                data.add(new FrameMetrics(frameMetrics));
             };
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().addOnFrameMetricsAvailableListener(listener, handler);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.getWindow().
+                addOnFrameMetricsAvailableListener(listener, handler));
 
         scrollView.postInvalidate();
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return data.size() != 0;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> data.size() != 0);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().removeOnFrameMetricsAvailableListener(listener);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.getWindow().removeOnFrameMetricsAvailableListener(listener);
         });
 
         data.clear();
 
         // Produce 5 frames and assert no metric listeners were invoked
         for (int i = 0; i < 5; i++) {
-            ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mActivity,
-                                               () -> { scrollView.invalidate(); });
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, scrollView, null);
         }
         assertEquals(0, data.size());
     }
 
+    @Test
     public void testMultipleListeners() throws Throwable {
         layout(R.layout.scrollview_layout);
         final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
@@ -123,114 +108,87 @@
         final Window myWindow = mActivity.getWindow();
 
         final Window.OnFrameMetricsAvailableListener frameMetricsListener1 =
-            new Window.OnFrameMetricsAvailableListener() {
-               @Override
-               public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
-                       int dropCount) {
-                   assertEquals(myWindow, window);
-                   assertEquals(0, dropCount);
-                   data1.add(new FrameMetrics(frameMetrics));
-               }
-            };
+                (Window window, FrameMetrics frameMetrics, int dropCount) -> {
+                    assertEquals(myWindow, window);
+                    assertEquals(0, dropCount);
+                    callGetMetric(frameMetrics);
+                    data1.add(new FrameMetrics(frameMetrics));
+                };
         final ArrayList<FrameMetrics> data2 = new ArrayList<>();
         final Window.OnFrameMetricsAvailableListener frameMetricsListener2 =
-            new Window.OnFrameMetricsAvailableListener() {
-               @Override
-               public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
-                       int dropCount) {
-                   assertEquals(myWindow, window);
-                   assertEquals(0, dropCount);
-                   data2.add(new FrameMetrics(frameMetrics));
-               }
-            };
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().addOnFrameMetricsAvailableListener(
-                        frameMetricsListener1, handler);
-                mActivity.getWindow().addOnFrameMetricsAvailableListener(
-                        frameMetricsListener2, handler);
-            }
+                (Window window, FrameMetrics frameMetrics, int dropCount) -> {
+                    assertEquals(myWindow, window);
+                    assertEquals(0, dropCount);
+                    callGetMetric(frameMetrics);
+                    data2.add(new FrameMetrics(frameMetrics));
+                };
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.getWindow().addOnFrameMetricsAvailableListener(
+                    frameMetricsListener1, handler);
+            mActivity.getWindow().addOnFrameMetricsAvailableListener(
+                    frameMetricsListener2, handler);
         });
 
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fling(-100);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> scrollView.fling(-100));
 
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return data1.size() != 0 && data1.size() == data2.size();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> data1.size() != 0 && data1.size() == data2.size());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().removeOnFrameMetricsAvailableListener(frameMetricsListener1);
-                mActivity.getWindow().removeOnFrameMetricsAvailableListener(frameMetricsListener2);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.getWindow().removeOnFrameMetricsAvailableListener(frameMetricsListener1);
+            mActivity.getWindow().removeOnFrameMetricsAvailableListener(frameMetricsListener2);
         });
     }
 
+    @Test
     public void testDropCount() throws Throwable {
         layout(R.layout.scrollview_layout);
         final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
 
-        final Window window = mActivity.getWindow();
         final AtomicInteger framesDropped = new AtomicInteger();
-        final AtomicInteger frameCount = new AtomicInteger();
 
         final HandlerThread thread = new HandlerThread("Listener");
         thread.start();
-        final Handler handler = new Handler(thread.getLooper());
         final Window.OnFrameMetricsAvailableListener frameMetricsListener =
-            new Window.OnFrameMetricsAvailableListener() {
-               @Override
-               public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
-                       int dropCount) {
-                    try {
-                        Thread.sleep(100);
-                        framesDropped.addAndGet(dropCount);
-                    } catch (Exception e) { }
-               }
-            };
+                (Window window, FrameMetrics frameMetrics, int dropCount) -> {
+                    SystemClock.sleep(100);
+                    callGetMetric(frameMetrics);
+                    framesDropped.addAndGet(dropCount);
+                };
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().addOnFrameMetricsAvailableListener(frameMetricsListener, handler);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.getWindow().
+                addOnFrameMetricsAvailableListener(frameMetricsListener,
+                        new Handler(thread.getLooper())));
 
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fling(-100);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> scrollView.fling(-100));
 
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return framesDropped.get() > 0;
-            }
-        }.run();
+        PollingCheck.waitFor(() -> framesDropped.get() > 0);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getWindow().removeOnFrameMetricsAvailableListener(frameMetricsListener);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.getWindow().
+                removeOnFrameMetricsAvailableListener(frameMetricsListener));
+    }
+
+    private void callGetMetric(FrameMetrics frameMetrics) {
+        // The return values for non-boolean metrics do not have expected values. Here we
+        // are verifying that calling getMetrics does not crash
+        frameMetrics.getMetric(FrameMetrics.UNKNOWN_DELAY_DURATION);
+        frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION);
+        frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION);
+        frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);
+        frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);
+        frameMetrics.getMetric(FrameMetrics.SYNC_DURATION);
+        frameMetrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION);
+        frameMetrics.getMetric(FrameMetrics.SWAP_BUFFERS_DURATION);
+        frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
+
+        // This is the only boolean metric so far
+        final long firstDrawFrameMetric = frameMetrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+        assertTrue("First draw frame metric should be boolean but is " + firstDrawFrameMetric,
+                (firstDrawFrameMetric == 0) || (firstDrawFrameMetric == 1));
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
index bff6511..bb4dce7 100644
--- a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
@@ -21,104 +21,25 @@
 import android.os.Bundle;
 import android.view.Window;
 
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
 /**
  * A minimal activity for testing {@link android.opengl.GLSurfaceView}.
  * Also accepts non-blank renderers to allow its use for more complex tests.
  */
-public class GLSurfaceViewCtsActivity extends Activity {
-
-    private static class Renderer implements GLSurfaceView.Renderer {
-
-        public void onDrawFrame(GL10 gl) {
-            // Do nothing.
-        }
-
-        public void onSurfaceChanged(GL10 gl, int width, int height) {
-            // Do nothing.
-        }
-
-        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-            // Do nothing.
-        }
-    }
-
-    private GLSurfaceView mView;
-
-    /** To override the blank renderer, or other settings, these
-     * static set* methods must be called before onCreate() is called.
-     * If using ActivityInstrumentationTestCase2, that means the set
-     * methods need to be called before calling getActivity in the
-     * test setUp().
-     */
-    private static GLSurfaceView.Renderer mRenderer = null;
-    public static void setRenderer(GLSurfaceView.Renderer renderer) {
-        mRenderer = renderer;
-    }
-    public static void resetRenderer() {
-        mRenderer = null;
-    }
-
-    private static int mRenderMode = 0;
-    private static boolean mRenderModeSet = false;
-    public static void setRenderMode(int renderMode) {
-        mRenderModeSet = true;
-        mRenderMode = renderMode;
-    }
-    public static void resetRenderMode() {
-        mRenderModeSet = false;
-        mRenderMode = 0;
-    }
-
-    private static int mGlVersion = 0;
-    private static boolean mGlVersionSet = false;
-    public static void setGlVersion(int glVersion) {
-        mGlVersionSet = true;
-        mGlVersion = glVersion;
-    }
-    public static void resetGlVersion() {
-        mGlVersionSet = false;
-        mGlVersion = 0;
-    }
-
-    private static boolean mFixedSizeSet = false;
-    private static int mFixedWidth, mFixedHeight;
-    public static void setFixedSize(int width, int height) {
-        mFixedSizeSet = true;
-        mFixedWidth = width;
-        mFixedHeight = height;
-    }
-    public static void resetFixedSize() {
-        mFixedSizeSet = false;
-    }
+public abstract class GLSurfaceViewCtsActivity extends Activity {
+    protected GLSurfaceView mView;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mView = new GLSurfaceView(this);
-        // Only set this if explicitly asked for
-        if (mGlVersionSet) {
-            mView.setEGLContextClientVersion(mGlVersion);
-        }
-        // Use no-op renderer by default
-        if (mRenderer == null) {
-            mView.setRenderer(new Renderer());
-        } else {
-            mView.setRenderer(mRenderer);
-        }
-        // Only set this if explicitly asked for
-        if (mRenderModeSet) {
-            mView.setRenderMode(mRenderMode);
-        }
-        if (mFixedSizeSet) {
-            mView.getHolder().setFixedSize(mFixedWidth, mFixedHeight);
-        }
-        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        configureGLSurfaceView();
+
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
         setContentView(mView);
     }
 
+    protected abstract void configureGLSurfaceView();
+
     public GLSurfaceView getView() {
         return mView;
     }
diff --git a/tests/tests/view/src/android/view/cts/GestureDetectorCtsActivity.java b/tests/tests/view/src/android/view/cts/GestureDetectorCtsActivity.java
index 1c02a89..5e3a2af 100644
--- a/tests/tests/view/src/android/view/cts/GestureDetectorCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/GestureDetectorCtsActivity.java
@@ -16,33 +16,25 @@
 
 package android.view.cts;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.View.OnTouchListener;
 import android.view.View.OnGenericMotionListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
 import android.widget.Button;
 
 public class GestureDetectorCtsActivity extends Activity {
-
-    public boolean isDown;
-    public boolean isScroll;
-    public boolean isFling;
-    public boolean isSingleTapUp;
-    public boolean onShowPress;
-    public boolean onLongPress;
-    public boolean onDoubleTap;
-    public boolean onDoubleTapEvent;
-    public boolean onSingleTapConfirmed;
-    public boolean onContextClick;
-
     private GestureDetector mGestureDetector;
-    private MockOnGestureListener mOnGestureListener;
+    private GestureDetector.SimpleOnGestureListener mOnGestureListener;
     private Handler mHandler;
     private View mView;
     private Button mTop;
@@ -53,7 +45,14 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mOnGestureListener = new MockOnGestureListener();
+        mOnGestureListener = mock(GestureDetector.SimpleOnGestureListener.class);
+        doReturn(true).when(mOnGestureListener).onDown(any(MotionEvent.class));
+        doReturn(true).when(mOnGestureListener).onFling(any(MotionEvent.class),
+                any(MotionEvent.class), anyFloat(), anyFloat());
+        doReturn(true).when(mOnGestureListener).onScroll(any(MotionEvent.class),
+                any(MotionEvent.class), anyFloat(), anyFloat());
+        doReturn(true).when(mOnGestureListener).onSingleTapUp(any(MotionEvent.class));
+
         mHandler = new Handler();
 
         mGestureDetector = new GestureDetector(this, mOnGestureListener, mHandler);
@@ -81,75 +80,14 @@
         return mView;
     }
 
-    public ViewGroup getViewGroup() {
-        return mViewGroup;
-    }
-
     public GestureDetector getGestureDetector() {
         return mGestureDetector;
     }
 
-    public MockOnGestureListener getListener() {
+    public GestureDetector.SimpleOnGestureListener getListener() {
         return mOnGestureListener;
     }
 
-    public class MockOnGestureListener extends SimpleOnGestureListener {
-        private MotionEvent mPreviousContextClickEvent;
-
-        public boolean onDown(MotionEvent e) {
-            isDown = true;
-            return true;
-        }
-
-        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-            isFling = true;
-            return true;
-        }
-
-        public void onLongPress(MotionEvent e) {
-            onLongPress = true;
-        }
-
-        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-            isScroll = true;
-            return true;
-        }
-
-        public void onShowPress(MotionEvent e) {
-            onShowPress = true;
-        }
-
-        public boolean onSingleTapUp(MotionEvent e) {
-            isSingleTapUp = true;
-            return true;
-        }
-
-        public boolean onDoubleTap(MotionEvent e) {
-            onDoubleTap = true;
-            return false;
-        }
-
-        public boolean onDoubleTapEvent(MotionEvent e) {
-            onDoubleTapEvent = true;
-            return false;
-        }
-
-        public boolean onSingleTapConfirmed(MotionEvent e) {
-            onSingleTapConfirmed = true;
-            return false;
-        }
-
-        public boolean onContextClick(MotionEvent e) {
-            onContextClick = true;
-            mPreviousContextClickEvent = e;
-            return false;
-        }
-
-        public MotionEvent getPreviousContextClickEvent() {
-            return mPreviousContextClickEvent;
-        }
-    }
-
     class MockOnTouchListener implements OnTouchListener, OnGenericMotionListener {
 
         public boolean onTouch(View v, MotionEvent event) {
diff --git a/tests/tests/view/src/android/view/cts/GestureDetectorTest.java b/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
index 0493088..a9eb7b4 100644
--- a/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
+++ b/tests/tests/view/src/android/view/cts/GestureDetectorTest.java
@@ -16,55 +16,54 @@
 
 package android.view.cts;
 
-import android.content.Context;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.cts.GestureDetectorCtsActivity.MockOnGestureListener;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
 
-public class GestureDetectorTest extends
-        ActivityInstrumentationTestCase2<GestureDetectorCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class GestureDetectorTest {
 
     private static final float X_3F = 3.0f;
     private static final float Y_4F = 4.0f;
 
-    private GestureDetector mGestureDetector;
     private GestureDetectorCtsActivity mActivity;
-    private MockOnGestureListener mListener;
-    private Context mContext;
+    private GestureDetector mGestureDetector;
+    private GestureDetector.SimpleOnGestureListener mListener;
 
     private long mDownTime;
     private long mEventTime;
     private MotionEvent mButtonPressPrimaryMotionEvent;
     private MotionEvent mButtonPressSecondaryMotionEvent;
 
-    public GestureDetectorTest() {
-        super("android.view.cts", GestureDetectorCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<GestureDetectorCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GestureDetectorCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mGestureDetector = mActivity.getGestureDetector();
         mListener = mActivity.getListener();
-        mContext = getInstrumentation().getTargetContext();
-        mActivity.isDown = false;
-        mActivity.isScroll = false;
-        mActivity.isFling = false;
-        mActivity.isSingleTapUp = false;
-        mActivity.onShowPress = false;
-        mActivity.onLongPress = false;
-        mActivity.onDoubleTap = false;
-        mActivity.onDoubleTapEvent = false;
-        mActivity.onSingleTapConfirmed = false;
-        mActivity.onContextClick = false;
 
         mDownTime = SystemClock.uptimeMillis();
         mEventTime = SystemClock.uptimeMillis();
@@ -78,22 +77,22 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-
         new GestureDetector(
-                mContext, new SimpleOnGestureListener(), new Handler(Looper.getMainLooper()));
-        new GestureDetector(mContext, new SimpleOnGestureListener());
+                mActivity, new SimpleOnGestureListener(), new Handler(Looper.getMainLooper()));
+        new GestureDetector(mActivity, new SimpleOnGestureListener());
         new GestureDetector(new SimpleOnGestureListener(), new Handler(Looper.getMainLooper()));
         new GestureDetector(new SimpleOnGestureListener());
-
-        try {
-            mGestureDetector = new GestureDetector(null);
-            fail("should throw null exception");
-        } catch (RuntimeException e) {
-            // expected
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullListener() {
+        new GestureDetector(null);
+    }
+
+    @Test
     public void testLongpressEnabled() {
         mGestureDetector.setIsLongpressEnabled(true);
         assertTrue(mGestureDetector.isLongpressEnabled());
@@ -101,34 +100,29 @@
         assertFalse(mGestureDetector.isLongpressEnabled());
     }
 
+    @Test
     public void testOnSetContextClickListener() {
-        mActivity.onContextClick = false;
         mGestureDetector.setContextClickListener(null);
         mGestureDetector.onGenericMotionEvent(mButtonPressPrimaryMotionEvent);
-        assertFalse(mActivity.onContextClick);
+        verify(mListener, never()).onContextClick(any(MotionEvent.class));
 
         mGestureDetector.setContextClickListener(mListener);
         mGestureDetector.onGenericMotionEvent(mButtonPressPrimaryMotionEvent);
-        assertTrue(mActivity.onContextClick);
-        assertSame(mButtonPressPrimaryMotionEvent, mListener.getPreviousContextClickEvent());
+        verify(mListener, times(1)).onContextClick(mButtonPressPrimaryMotionEvent);
     }
 
+    @Test
     public void testOnContextClick() {
-        mActivity.onContextClick = false;
         mListener.onContextClick(mButtonPressPrimaryMotionEvent);
-        assertTrue(mActivity.onContextClick);
-        assertSame(mButtonPressPrimaryMotionEvent, mListener.getPreviousContextClickEvent());
+        verify(mListener, times(1)).onContextClick(mButtonPressPrimaryMotionEvent);
 
-        mActivity.onContextClick = false;
         mGestureDetector.onGenericMotionEvent(mButtonPressSecondaryMotionEvent);
-        assertTrue(mActivity.onContextClick);
-        assertSame(mButtonPressSecondaryMotionEvent, mListener.getPreviousContextClickEvent());
+        verify(mListener, times(1)).onContextClick(mButtonPressSecondaryMotionEvent);
     }
 
+    @Test
     public void testOnGenericMotionEvent() {
-        mActivity.onContextClick = false;
         mGestureDetector.onGenericMotionEvent(mButtonPressPrimaryMotionEvent);
-        assertTrue(mActivity.onContextClick);
-        assertSame(mButtonPressPrimaryMotionEvent, mListener.getPreviousContextClickEvent());
+        verify(mListener, times(1)).onContextClick(mButtonPressPrimaryMotionEvent);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/GravityTest.java b/tests/tests/view/src/android/view/cts/GravityTest.java
index 86b1283..ccd3921 100644
--- a/tests/tests/view/src/android/view/cts/GravityTest.java
+++ b/tests/tests/view/src/android/view/cts/GravityTest.java
@@ -16,36 +16,46 @@
 
 package android.view.cts;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Gravity;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Gravity}.
  */
-public class GravityTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GravityTest {
     private Rect mInRect;
     private Rect mOutRect;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mInRect = new Rect(1, 2, 3, 4);
         mOutRect = new Rect();
     }
 
+    @Test
     public void testConstructor() {
         new Gravity();
     }
 
-    private void applyGravity(int gravity, int w, int h, Rect container, Rect outRect, boolean bRtl) {
+    private void applyGravity(int gravity, int w, int h, boolean bRtl) {
         final int layoutDirection = bRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
         Gravity.apply(gravity, w, h, mInRect, mOutRect, layoutDirection);
     }
 
+    @Test
     public void testApply() {
         mInRect = new Rect(10, 20, 30, 40);
         Gravity.apply(Gravity.TOP, 2, 3, mInRect, mOutRect);
@@ -58,12 +68,12 @@
         assertEquals(26, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(28, mOutRect.bottom);
-        applyGravity(Gravity.TOP, 2, 3, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.TOP, 2, 3, false /* LTR direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(20, mOutRect.top);
         assertEquals(23, mOutRect.bottom);
-        applyGravity(Gravity.TOP, 2, 3, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.TOP, 2, 3, true /* RTL direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(20, mOutRect.top);
@@ -79,12 +89,12 @@
         assertEquals(26, mOutRect.right);
         assertEquals(32, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.BOTTOM, 2, 3, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.BOTTOM, 2, 3, false /* LTR direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(37, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.BOTTOM, 2, 3, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.BOTTOM, 2, 3, true /* RTL direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(37, mOutRect.top);
@@ -100,12 +110,12 @@
         assertEquals(17, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.LEFT, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.LEFT, 2, 10, false /* LTR direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(12, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.LEFT, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.LEFT, 2, 10, true /* RTL direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(12, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -121,12 +131,12 @@
         assertEquals(17, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.START, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.START, 2, 10, false /* LTR direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(12, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.START, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.START, 2, 10, true /* RTL direction */);
         assertEquals(28, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -142,12 +152,12 @@
         assertEquals(25, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.RIGHT, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.RIGHT, 2, 10, false /* LTR direction */);
         assertEquals(28, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.RIGHT, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.RIGHT, 2, 10, true /* RTL direction */);
         assertEquals(28, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -163,12 +173,12 @@
         assertEquals(25, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.END, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.END, 2, 10, false /* LTR direction */);
         assertEquals(28, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.END, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.END, 2, 10, true /* RTL direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(12, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -184,12 +194,12 @@
         assertEquals(26, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.CENTER_VERTICAL, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.CENTER_VERTICAL, 2, 10, false /* LTR direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.CENTER_VERTICAL, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.CENTER_VERTICAL, 2, 10, true /* RTL direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -205,12 +215,12 @@
         assertEquals(26, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(45, mOutRect.bottom);
-        applyGravity(Gravity.FILL_VERTICAL, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.FILL_VERTICAL, 2, 10, false /* LTR direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(20, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.FILL_VERTICAL, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.FILL_VERTICAL, 2, 10, true /* RTL direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(20, mOutRect.top);
@@ -226,12 +236,12 @@
         assertEquals(26, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.CENTER_HORIZONTAL, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.CENTER_HORIZONTAL, 2, 10, false /* LTR direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.CENTER_HORIZONTAL, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.CENTER_HORIZONTAL, 2, 10, true /* RTL direction */);
         assertEquals(19, mOutRect.left);
         assertEquals(21, mOutRect.right);
         assertEquals(25, mOutRect.top);
@@ -247,24 +257,26 @@
         assertEquals(35, mOutRect.right);
         assertEquals(30, mOutRect.top);
         assertEquals(40, mOutRect.bottom);
-        applyGravity(Gravity.FILL_HORIZONTAL, 2, 10, mInRect, mOutRect, false /* LTR direction */);
+        applyGravity(Gravity.FILL_HORIZONTAL, 2, 10, false /* LTR direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
-        applyGravity(Gravity.FILL_HORIZONTAL, 2, 10, mInRect, mOutRect, true /* RTL direction */);
+        applyGravity(Gravity.FILL_HORIZONTAL, 2, 10, true /* RTL direction */);
         assertEquals(10, mOutRect.left);
         assertEquals(30, mOutRect.right);
         assertEquals(25, mOutRect.top);
         assertEquals(35, mOutRect.bottom);
     }
 
+    @Test
     public void testIsVertical() {
         assertFalse(Gravity.isVertical(-1));
         assertTrue(Gravity.isVertical(Gravity.VERTICAL_GRAVITY_MASK));
         assertFalse(Gravity.isVertical(Gravity.NO_GRAVITY));
     }
 
+    @Test
     public void testIsHorizontal() {
         assertFalse(Gravity.isHorizontal(-1));
         assertTrue(Gravity.isHorizontal(Gravity.HORIZONTAL_GRAVITY_MASK));
@@ -272,6 +284,7 @@
         assertFalse(Gravity.isHorizontal(Gravity.NO_GRAVITY));
     }
 
+    @Test
     public void testApplyDisplay() {
         Rect display = new Rect(20, 30, 40, 50);
         Rect inoutRect = new Rect(10, 10, 30, 60);
@@ -290,52 +303,52 @@
         assertEquals(50, inoutRect.bottom);
     }
 
-    @SmallTest
-    public void testGetAbsoluteGravity() throws Exception {
-        assertOneGravity(Gravity.LEFT, Gravity.LEFT, false);
-        assertOneGravity(Gravity.LEFT, Gravity.LEFT, true);
+    @Test
+    public void testGetAbsoluteGravity() {
+        verifyOneGravity(Gravity.LEFT, Gravity.LEFT, false);
+        verifyOneGravity(Gravity.LEFT, Gravity.LEFT, true);
 
-        assertOneGravity(Gravity.RIGHT, Gravity.RIGHT, false);
-        assertOneGravity(Gravity.RIGHT, Gravity.RIGHT, true);
+        verifyOneGravity(Gravity.RIGHT, Gravity.RIGHT, false);
+        verifyOneGravity(Gravity.RIGHT, Gravity.RIGHT, true);
 
-        assertOneGravity(Gravity.TOP, Gravity.TOP, false);
-        assertOneGravity(Gravity.TOP, Gravity.TOP, true);
+        verifyOneGravity(Gravity.TOP, Gravity.TOP, false);
+        verifyOneGravity(Gravity.TOP, Gravity.TOP, true);
 
-        assertOneGravity(Gravity.BOTTOM, Gravity.BOTTOM, false);
-        assertOneGravity(Gravity.BOTTOM, Gravity.BOTTOM, true);
+        verifyOneGravity(Gravity.BOTTOM, Gravity.BOTTOM, false);
+        verifyOneGravity(Gravity.BOTTOM, Gravity.BOTTOM, true);
 
-        assertOneGravity(Gravity.CENTER_VERTICAL, Gravity.CENTER_VERTICAL, false);
-        assertOneGravity(Gravity.CENTER_VERTICAL, Gravity.CENTER_VERTICAL, true);
+        verifyOneGravity(Gravity.CENTER_VERTICAL, Gravity.CENTER_VERTICAL, false);
+        verifyOneGravity(Gravity.CENTER_VERTICAL, Gravity.CENTER_VERTICAL, true);
 
-        assertOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, false);
-        assertOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, true);
+        verifyOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, false);
+        verifyOneGravity(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_HORIZONTAL, true);
 
-        assertOneGravity(Gravity.CENTER, Gravity.CENTER, false);
-        assertOneGravity(Gravity.CENTER, Gravity.CENTER, true);
+        verifyOneGravity(Gravity.CENTER, Gravity.CENTER, false);
+        verifyOneGravity(Gravity.CENTER, Gravity.CENTER, true);
 
-        assertOneGravity(Gravity.FILL_VERTICAL, Gravity.FILL_VERTICAL, false);
-        assertOneGravity(Gravity.FILL_VERTICAL, Gravity.FILL_VERTICAL, true);
+        verifyOneGravity(Gravity.FILL_VERTICAL, Gravity.FILL_VERTICAL, false);
+        verifyOneGravity(Gravity.FILL_VERTICAL, Gravity.FILL_VERTICAL, true);
 
-        assertOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, false);
-        assertOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, true);
+        verifyOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, false);
+        verifyOneGravity(Gravity.FILL_HORIZONTAL, Gravity.FILL_HORIZONTAL, true);
 
-        assertOneGravity(Gravity.FILL, Gravity.FILL, false);
-        assertOneGravity(Gravity.FILL, Gravity.FILL, true);
+        verifyOneGravity(Gravity.FILL, Gravity.FILL, false);
+        verifyOneGravity(Gravity.FILL, Gravity.FILL, true);
 
-        assertOneGravity(Gravity.CLIP_HORIZONTAL, Gravity.CLIP_HORIZONTAL, false);
-        assertOneGravity(Gravity.CLIP_HORIZONTAL, Gravity.CLIP_HORIZONTAL, true);
+        verifyOneGravity(Gravity.CLIP_HORIZONTAL, Gravity.CLIP_HORIZONTAL, false);
+        verifyOneGravity(Gravity.CLIP_HORIZONTAL, Gravity.CLIP_HORIZONTAL, true);
 
-        assertOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, false);
-        assertOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, true);
+        verifyOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, false);
+        verifyOneGravity(Gravity.CLIP_VERTICAL, Gravity.CLIP_VERTICAL, true);
 
-        assertOneGravity(Gravity.LEFT, Gravity.START, false);
-        assertOneGravity(Gravity.RIGHT, Gravity.START, true);
+        verifyOneGravity(Gravity.LEFT, Gravity.START, false);
+        verifyOneGravity(Gravity.RIGHT, Gravity.START, true);
 
-        assertOneGravity(Gravity.RIGHT, Gravity.END, false);
-        assertOneGravity(Gravity.LEFT, Gravity.END, true);
+        verifyOneGravity(Gravity.RIGHT, Gravity.END, false);
+        verifyOneGravity(Gravity.LEFT, Gravity.END, true);
     }
 
-    private void assertOneGravity(int expected, int initial, boolean isRtl) {
+    private void verifyOneGravity(int expected, int initial, boolean isRtl) {
         final int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
 
         assertEquals(expected, Gravity.getAbsoluteGravity(initial, layoutDirection));
diff --git a/tests/tests/view/src/android/view/cts/HoverCtsActivity.java b/tests/tests/view/src/android/view/cts/HoverCtsActivity.java
new file mode 100644
index 0000000..907e3b8
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/HoverCtsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class HoverCtsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.hover_layout);
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/HoverTest.java b/tests/tests/view/src/android/view/cts/HoverTest.java
new file mode 100644
index 0000000..24e3020
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/HoverTest.java
@@ -0,0 +1,381 @@
+/*
+ * 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 static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.hamcrest.Description;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InOrder;
+
+/**
+ * Test hover events.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HoverTest {
+    private static final String LOG_TAG = "HoverTest";
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    private View mOuter;
+    private View mMiddle1;
+    private View mMiddle2;
+    private View mInner11;
+    private View mInner12;
+    private View mInner21;
+    private View mInner22;
+
+    private View mOverlapping;
+    private View mLayer1;
+    private View mLayer2;
+    private View mLayer3;
+    private View mLayer4Left;
+    private View mLayer4Right;
+
+    @Rule
+    public ActivityTestRule<HoverCtsActivity> mActivityRule =
+            new ActivityTestRule<>(HoverCtsActivity.class);
+
+    static class ActionMatcher extends ArgumentMatcher<MotionEvent> {
+        private final int mAction;
+
+        ActionMatcher(int action) {
+            mAction = action;
+        }
+
+        public boolean matches(Object actual) {
+            return (actual instanceof MotionEvent) && ((MotionEvent) actual).getAction() == mAction;
+        }
+
+        public void describeTo(Description description) {
+            description.appendText("action=" + MotionEvent.actionToString(mAction));
+        }
+    }
+
+    static class MoveMatcher extends ActionMatcher {
+        private final int mX;
+        private final int mY;
+
+        MoveMatcher(int x, int y) {
+            super(MotionEvent.ACTION_HOVER_MOVE);
+            mX = x;
+            mY = y;
+        }
+
+        public boolean matches(Object actual) {
+            return super.matches(actual)
+                    && ((int)((MotionEvent)actual).getX()) == mX
+                    && ((int)((MotionEvent)actual).getY()) == mY;
+        }
+
+        public void describeTo(Description description) {
+            super.describeTo(description);
+            description.appendText("@(" + mX + "," + mY + ")");
+        }
+    }
+
+    private final ActionMatcher mEnterMatcher = new ActionMatcher(MotionEvent.ACTION_HOVER_ENTER);
+    private final ActionMatcher mMoveMatcher = new ActionMatcher(MotionEvent.ACTION_HOVER_MOVE);
+    private final ActionMatcher mExitMatcher = new ActionMatcher(MotionEvent.ACTION_HOVER_EXIT);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+
+        mOuter = mActivity.findViewById(R.id.outer);
+        mMiddle1 = mActivity.findViewById(R.id.middle1);
+        mMiddle2 = mActivity.findViewById(R.id.middle2);
+        mInner11 = mActivity.findViewById(R.id.inner11);
+        mInner12 = mActivity.findViewById(R.id.inner12);
+        mInner21 = mActivity.findViewById(R.id.inner21);
+        mInner22 = mActivity.findViewById(R.id.inner22);
+
+        mOverlapping = mActivity.findViewById(R.id.overlapping);
+        mLayer1 = mActivity.findViewById(R.id.layer1);
+        mLayer2 = mActivity.findViewById(R.id.layer2);
+        mLayer3 = mActivity.findViewById(R.id.layer3);
+        mLayer4Left = mActivity.findViewById(R.id.layer4_left);
+        mLayer4Right = mActivity.findViewById(R.id.layer4_right);
+    }
+
+    private void verifyHoverSequence(
+            View.OnHoverListener listener, View view, int moveCount, boolean exit) {
+        InOrder inOrder = inOrder(listener);
+        inOrder.verify(listener, times(1)).onHover(eq(view), argThat(mEnterMatcher));
+        inOrder.verify(listener, times(moveCount)).onHover(eq(view), argThat(mMoveMatcher));
+        if (exit) {
+            inOrder.verify(listener, times(1)).onHover(eq(view), argThat(mExitMatcher));
+        }
+        verifyNoMoreInteractions(listener);
+    }
+
+    private void verifyEnterMove(View.OnHoverListener listener, View view, int moveCount) {
+        verifyHoverSequence(listener, view, moveCount, false);
+    }
+
+    private void verifyEnterMoveExit(View.OnHoverListener listener, View view, int moveCount) {
+        verifyHoverSequence(listener, view, moveCount, true);
+    }
+
+    private void injectHoverMove(View view) {
+        injectHoverMove(view, 0, 0);
+    }
+
+    private void injectHoverMove(View view, int offsetX, int offsetY) {
+        mActivity.getWindow().injectInputEvent(
+                obtainMotionEvent(view, MotionEvent.ACTION_HOVER_MOVE, offsetX, offsetY));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private MotionEvent obtainMotionEvent(View anchor, int action, int offsetX, int offsetY) {
+        final long eventTime = SystemClock.uptimeMillis();
+        final int[] screenPos = new int[2];
+        anchor.getLocationOnScreen(screenPos);
+        final int x = screenPos[0] + offsetX;
+        final int y = screenPos[1] + offsetY;
+        MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action, x, y, 0);
+        event.setSource(InputDevice.SOURCE_MOUSE);
+        return event;
+    }
+
+    private View.OnHoverListener installHoverListener(View view) {
+        return installHoverListener(view, true);
+    }
+
+    private View.OnHoverListener installHoverListener(View view, boolean result) {
+        final View.OnHoverListener mockListener = mock(View.OnHoverListener.class);
+        view.setOnHoverListener((v, event) -> {
+            // Clone the event to work around event instance reuse in the framework.
+            mockListener.onHover(v, MotionEvent.obtain(event));
+            return result;
+        });
+        return mockListener;
+    }
+
+    private void clearHoverListener(View view) {
+        view.setOnHoverListener(null);
+    }
+
+    private void remove(View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> ((ViewGroup)view.getParent()).removeView(view));
+    }
+
+    @Test
+    public void testHoverMove() throws Throwable {
+        View.OnHoverListener listener = installHoverListener(mInner11);
+
+        injectHoverMove(mInner11);
+
+        clearHoverListener(mInner11);
+
+        verifyEnterMove(listener, mInner11, 1);
+    }
+
+    @Test
+    public void testHoverMoveMultiple() throws Throwable {
+        View.OnHoverListener listener = installHoverListener(mInner11);
+
+        injectHoverMove(mInner11, 1, 2);
+        injectHoverMove(mInner11, 3, 4);
+        injectHoverMove(mInner11, 5, 6);
+
+        clearHoverListener(mInner11);
+
+        InOrder inOrder = inOrder(listener);
+
+        inOrder.verify(listener, times(1)).onHover(eq(mInner11), argThat(mEnterMatcher));
+        inOrder.verify(listener, times(1)).onHover(eq(mInner11), argThat(new MoveMatcher(1, 2)));
+        inOrder.verify(listener, times(1)).onHover(eq(mInner11), argThat(new MoveMatcher(3, 4)));
+        inOrder.verify(listener, times(1)).onHover(eq(mInner11), argThat(new MoveMatcher(5, 6)));
+
+        verifyNoMoreInteractions(listener);
+    }
+
+    @Test
+    public void testHoverMoveAndExit() throws Throwable {
+        View.OnHoverListener inner11Listener = installHoverListener(mInner11);
+        View.OnHoverListener inner12Listener = installHoverListener(mInner12);
+
+        injectHoverMove(mInner11);
+        injectHoverMove(mInner12);
+
+        clearHoverListener(mInner11);
+        clearHoverListener(mInner12);
+
+        verifyEnterMoveExit(inner11Listener, mInner11, 2);
+        verifyEnterMove(inner12Listener, mInner12, 1);
+    }
+
+    @Test
+    public void testRemoveBeforeExit() throws Throwable {
+        View.OnHoverListener middle1Listener = installHoverListener(mMiddle1);
+        View.OnHoverListener inner11Listener = installHoverListener(mInner11);
+
+        injectHoverMove(mInner11);
+        remove(mInner11);
+
+        clearHoverListener(mMiddle1);
+        clearHoverListener(mInner11);
+
+        verifyNoMoreInteractions(middle1Listener);
+        verifyEnterMoveExit(inner11Listener, mInner11, 1);
+    }
+
+    @Test
+    public void testRemoveParentBeforeExit() throws Throwable {
+        View.OnHoverListener outerListener = installHoverListener(mOuter);
+        View.OnHoverListener middle1Listener = installHoverListener(mMiddle1);
+        View.OnHoverListener inner11Listener = installHoverListener(mInner11);
+
+        injectHoverMove(mInner11);
+        remove(mMiddle1);
+
+        clearHoverListener(mOuter);
+        clearHoverListener(mMiddle1);
+        clearHoverListener(mInner11);
+
+        verifyNoMoreInteractions(outerListener);
+        verifyNoMoreInteractions(middle1Listener);
+        verifyEnterMoveExit(inner11Listener, mInner11, 1);
+    }
+
+    @Test
+    public void testRemoveAfterExit() throws Throwable {
+        View.OnHoverListener listener = installHoverListener(mInner11);
+
+        injectHoverMove(mInner11);
+        injectHoverMove(mInner12);
+        remove(mInner11);
+
+        clearHoverListener(mInner11);
+
+        verifyEnterMoveExit(listener, mInner11, 2);
+    }
+
+    @Test
+    public void testNoParentInteraction() throws Throwable {
+        View.OnHoverListener outerListener = installHoverListener(mOuter);
+        View.OnHoverListener middle1Listener = installHoverListener(mMiddle1);
+        View.OnHoverListener middle2Listener = installHoverListener(mMiddle2);
+        View.OnHoverListener inner11Listener = installHoverListener(mInner11);
+        View.OnHoverListener inner12Listener = installHoverListener(mInner12);
+        View.OnHoverListener inner21Listener = installHoverListener(mInner21);
+        View.OnHoverListener inner22Listener = installHoverListener(mInner22);
+
+        injectHoverMove(mInner11);
+        injectHoverMove(mInner12);
+        injectHoverMove(mInner21);
+        injectHoverMove(mInner22);
+
+        clearHoverListener(mOuter);
+        clearHoverListener(mMiddle1);
+        clearHoverListener(mMiddle2);
+        clearHoverListener(mInner11);
+        clearHoverListener(mInner21);
+
+        verifyNoMoreInteractions(outerListener);
+        verifyNoMoreInteractions(middle1Listener);
+        verifyNoMoreInteractions(middle2Listener);
+        verifyEnterMoveExit(inner11Listener, mInner11, 2);
+        verifyEnterMoveExit(inner12Listener, mInner12, 2);
+        verifyEnterMoveExit(inner21Listener, mInner21, 2);
+        verifyEnterMove(inner22Listener, mInner22, 1);
+    }
+
+    @Test
+    public void testParentInteraction() throws Throwable {
+        View.OnHoverListener outerListener = installHoverListener(mOuter);
+        View.OnHoverListener middle1Listener = installHoverListener(mMiddle1);
+        View.OnHoverListener middle2Listener = installHoverListener(mMiddle2);
+        View.OnHoverListener inner11Listener = installHoverListener(mInner11, false);
+        View.OnHoverListener inner12Listener = installHoverListener(mInner12, false);
+        View.OnHoverListener inner21Listener = installHoverListener(mInner21);
+        View.OnHoverListener inner22Listener = installHoverListener(mInner22);
+
+        injectHoverMove(mInner11);
+        injectHoverMove(mInner12);
+        injectHoverMove(mInner21);
+        injectHoverMove(mInner22);
+
+        clearHoverListener(mOuter);
+        clearHoverListener(mMiddle1);
+        clearHoverListener(mMiddle2);
+        clearHoverListener(mInner11);
+        clearHoverListener(mInner12);
+        clearHoverListener(mInner21);
+
+        verifyNoMoreInteractions(outerListener);
+        verifyEnterMoveExit(middle1Listener, mMiddle1, 3);
+        verifyNoMoreInteractions(middle2Listener);
+        verifyEnterMoveExit(inner11Listener, mInner11, 2);
+        verifyEnterMoveExit(inner12Listener, mInner12, 2);
+        verifyEnterMoveExit(inner21Listener, mInner21, 2);
+        verifyEnterMove(inner22Listener, mInner22, 1);
+    }
+
+    @Test
+    public void testOverlappingHoverTargets() throws Throwable {
+        View.OnHoverListener overlapping = installHoverListener(mOverlapping);
+        View.OnHoverListener listener1 = installHoverListener(mLayer1);
+        View.OnHoverListener listener2 = installHoverListener(mLayer2);
+        View.OnHoverListener listener3 = installHoverListener(mLayer3, false);
+        View.OnHoverListener listener4_left = installHoverListener(mLayer4Left, false);
+        View.OnHoverListener listener4_right = installHoverListener(mLayer4Right, false);
+
+        injectHoverMove(mLayer4Left);
+        injectHoverMove(mLayer4Left, 1, 1);
+        injectHoverMove(mLayer4Right);
+        injectHoverMove(mMiddle1);
+
+        clearHoverListener(mLayer1);
+        clearHoverListener(mLayer2);
+        clearHoverListener(mLayer3);
+        clearHoverListener(mLayer4Left);
+        clearHoverListener(mLayer4Right);
+
+        verifyNoMoreInteractions(overlapping);
+        verifyNoMoreInteractions(listener1);
+        verifyEnterMoveExit(listener2, mLayer2, 4);
+        verifyEnterMoveExit(listener3, mLayer3, 4);
+        verifyEnterMoveExit(listener4_left, mLayer4Left, 3);
+        verifyEnterMoveExit(listener4_right, mLayer4Right, 2);
+   }
+}
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/InflateExceptionTest.java b/tests/tests/view/src/android/view/cts/InflateExceptionTest.java
index 665eb07..2251210 100644
--- a/tests/tests/view/src/android/view/cts/InflateExceptionTest.java
+++ b/tests/tests/view/src/android/view/cts/InflateExceptionTest.java
@@ -15,69 +15,79 @@
  */
 package android.view.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.InflateException;
 
-public class InflateExceptionTest extends TestCase {
-   public void testInflateException(){
-       InflateException ne = null;
-       boolean isThrowed = false;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-       try {
-           ne = new InflateException();
-           throw ne;
-       } catch (InflateException e) {
-           assertSame(ne, e);
-           isThrowed = true;
-       } finally {
-           if (!isThrowed) {
-               fail("should throw out InflateException");
-           }
-       }
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InflateExceptionTest {
+    @Test
+    public void testInflateException() {
+        InflateException ne = null;
+        boolean isThrown = false;
 
-       String detailMessage = "testInflateException";
-       Throwable throwable = new Exception();
+        try {
+            ne = new InflateException();
+            throw ne;
+        } catch (InflateException e) {
+            assertSame(ne, e);
+            isThrown = true;
+        } finally {
+            if (!isThrown) {
+                fail("should throw out InflateException");
+            }
+        }
 
-       isThrowed = false;
+        String detailMessage = "testInflateException";
+        Throwable throwable = new Exception();
 
-       try {
-           ne = new InflateException(detailMessage, throwable);
-           throw ne;
-       } catch (InflateException e) {
-           assertSame(ne, e);
-           isThrowed = true;
-       } finally {
-           if (!isThrowed) {
-               fail("should throw out InflateException");
-           }
-       }
+        isThrown = false;
 
-       isThrowed = false;
+        try {
+            ne = new InflateException(detailMessage, throwable);
+            throw ne;
+        } catch (InflateException e) {
+            assertSame(ne, e);
+            isThrown = true;
+        } finally {
+            if (!isThrown) {
+                fail("should throw out InflateException");
+            }
+        }
 
-       try {
-           ne = new InflateException(detailMessage);
-           throw ne;
-       } catch (InflateException e) {
-           assertSame(ne, e);
-           isThrowed = true;
-       } finally {
-           if (!isThrowed) {
-               fail("should throw out InflateException");
-           }
-       }
+        isThrown = false;
 
-       isThrowed = false;
+        try {
+            ne = new InflateException(detailMessage);
+            throw ne;
+        } catch (InflateException e) {
+            assertSame(ne, e);
+            isThrown = true;
+        } finally {
+            if (!isThrown) {
+                fail("should throw out InflateException");
+            }
+        }
 
-       try {
-           ne = new InflateException(throwable);
-           throw ne;
-       } catch (InflateException e) {
-           assertSame(ne, e);
-           isThrowed = true;
-       } finally {
-           if (!isThrowed) {
-               fail("should throw out InflateException");
-           }
-       }
-   }
+        isThrown = false;
+
+        try {
+            ne = new InflateException(throwable);
+            throw ne;
+        } catch (InflateException e) {
+            assertSame(ne, e);
+            isThrown = true;
+        } finally {
+            if (!isThrown) {
+                fail("should throw out InflateException");
+            }
+        }
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/KeyCharacterMapTest.java b/tests/tests/view/src/android/view/cts/KeyCharacterMapTest.java
index 85f91ca..6207b9b 100644
--- a/tests/tests/view/src/android/view/cts/KeyCharacterMapTest.java
+++ b/tests/tests/view/src/android/view/cts/KeyCharacterMapTest.java
@@ -16,25 +16,37 @@
 
 package android.view.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.junit.Assert.fail;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
 import android.view.KeyCharacterMap.KeyData;
+import android.view.KeyEvent;
 
-public class KeyCharacterMapTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyCharacterMapTest {
 
     private KeyCharacterMap mKeyCharacterMap;
     private final char[] chars = {'A', 'B', 'C'};
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
     }
 
-    public void testIsPrintingKey() throws Exception {
+    @Test
+    public void testIsPrintingKey() {
 
         assertFalse(mKeyCharacterMap.isPrintingKey(KeyEvent.KEYCODE_UNKNOWN));
         assertFalse(mKeyCharacterMap.isPrintingKey(KeyEvent.KEYCODE_SOFT_LEFT));
@@ -251,13 +263,15 @@
         assertFalse(mKeyCharacterMap.isPrintingKey(KeyEvent.KEYCODE_PROG_BLUE));
     }
 
-    public void testLoad() throws Exception {
+    @Test
+    public void testLoad() {
         mKeyCharacterMap = null;
         mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
         assertNotNull(mKeyCharacterMap);
     }
 
-    public void testGetNumber() throws Exception {
+    @Test
+    public void testGetNumber() {
         assertEquals('0', mKeyCharacterMap.getNumber(KeyEvent.KEYCODE_0));
         assertEquals('1', mKeyCharacterMap.getNumber(KeyEvent.KEYCODE_1));
         assertEquals('2', mKeyCharacterMap.getNumber(KeyEvent.KEYCODE_2));
@@ -272,13 +286,13 @@
         assertEquals('#', mKeyCharacterMap.getNumber(KeyEvent.KEYCODE_POUND));
     }
 
-    public void testGetMatch1() throws Exception {
-        try {
-            mKeyCharacterMap.getMatch(KeyEvent.KEYCODE_0, null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetMatchNull() {
+        mKeyCharacterMap.getMatch(KeyEvent.KEYCODE_0, null);
+    }
 
+    @Test
+    public void testGetMatch() {
         assertEquals('\0', mKeyCharacterMap.getMatch(getCharacterKeyCode('E'), chars));
         assertEquals('A', mKeyCharacterMap.getMatch(getCharacterKeyCode('A'), chars));
         assertEquals('B', mKeyCharacterMap.getMatch(getCharacterKeyCode('B'), chars));
@@ -291,12 +305,13 @@
         return events[0].getKeyCode();
     }
 
-    public void testGetMatch2() throws Exception {
-        try {
-            mKeyCharacterMap.getMatch(KeyEvent.KEYCODE_0, null, 1);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetMatchMetaStateNull() {
+        mKeyCharacterMap.getMatch(KeyEvent.KEYCODE_0, null, 1);
+    }
+
+    @Test
+    public void testGetMatchMetaState() {
         assertEquals('\0', mKeyCharacterMap.getMatch(1000, chars, 2));
         assertEquals('\0', mKeyCharacterMap.getMatch(10000, chars, 2));
         assertEquals('\0', mKeyCharacterMap.getMatch(getCharacterKeyCode('E'), chars));
@@ -304,16 +319,18 @@
         assertEquals('B', mKeyCharacterMap.getMatch(getCharacterKeyCode('B'), chars));
     }
 
-    public void testGetKeyboardType() throws Exception {
+    @Test
+    public void testGetKeyboardType() {
         mKeyCharacterMap.getKeyboardType();
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetEventsNull() {
+        mKeyCharacterMap.getEvents(null);
+    }
+
+    @Test
     public void testGetEvents() {
-        try {
-            mKeyCharacterMap.getEvents(null);
-            fail("should throw exception");
-        } catch (Exception e) {
-        }
         CharSequence mCharSequence = "TestMessage123";
         int len = mCharSequence.length();
         char[] charsArray = new char[len];
@@ -321,7 +338,8 @@
         mKeyCharacterMap.getEvents(charsArray);
     }
 
-    public void testGetKeyData() throws Exception {
+    @Test
+    public void testGetKeyData() {
         KeyData result = new KeyData();
         result.meta = new char[2];
         try {
diff --git a/tests/tests/view/src/android/view/cts/KeyEventTest.java b/tests/tests/view/src/android/view/cts/KeyEventTest.java
index 61d7d92..fde3f81 100644
--- a/tests/tests/view/src/android/view/cts/KeyEventTest.java
+++ b/tests/tests/view/src/android/view/cts/KeyEventTest.java
@@ -16,35 +16,57 @@
 
 package android.view.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.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+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.verifyNoMoreInteractions;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.method.MetaKeyKeyListener;
-import android.view.KeyEvent;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
 import android.view.KeyCharacterMap.KeyData;
-import android.view.KeyEvent.Callback;
+import android.view.KeyEvent;
 
 import junit.framework.Assert;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+
 /**
  * Test {@link KeyEvent}.
  */
-public class KeyEventTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyEventTest {
     private KeyEvent mKeyEvent;
     private long mDownTime;
     private long mEventTime;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
 
         mDownTime = SystemClock.uptimeMillis();
         mEventTime = SystemClock.uptimeMillis();
     }
 
+    @Test
     public void testConstructor() {
         new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
 
@@ -66,6 +88,7 @@
         new KeyEvent(mDownTime, "test", 0, KeyEvent.FLAG_SOFT_KEYBOARD);
     }
 
+    @Test
     public void testGetCharacters() {
         String characters = "android_test";
         mKeyEvent = new KeyEvent(mDownTime, characters, 0, KeyEvent.FLAG_SOFT_KEYBOARD);
@@ -77,29 +100,79 @@
         assertNull(mKeyEvent.getCharacters());
     }
 
+    @Test
     public void testGetMaxKeyCode() {
         assertTrue(KeyEvent.getMaxKeyCode() > 0);
     }
 
-    public void testIsShiftPressed() {
-        assertFalse(mKeyEvent.isShiftPressed());
-        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
-                KeyEvent.META_SHIFT_ON);
-        assertTrue(mKeyEvent.isShiftPressed());
+    @Test
+    public void testMetaKeyStates() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
                 KeyEvent.META_ALT_ON);
+        assertTrue(mKeyEvent.isAltPressed());
+        assertFalse(mKeyEvent.isCtrlPressed());
+        assertFalse(mKeyEvent.isFunctionPressed());
+        assertFalse(mKeyEvent.isMetaPressed());
         assertFalse(mKeyEvent.isShiftPressed());
+        assertFalse(mKeyEvent.isSymPressed());
+
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_1, 4,
+                KeyEvent.META_CTRL_ON);
+        assertFalse(mKeyEvent.isAltPressed());
+        assertTrue(mKeyEvent.isCtrlPressed());
+        assertFalse(mKeyEvent.isFunctionPressed());
+        assertFalse(mKeyEvent.isMetaPressed());
+        assertFalse(mKeyEvent.isShiftPressed());
+        assertFalse(mKeyEvent.isSymPressed());
+
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_2, 3,
+                KeyEvent.META_FUNCTION_ON);
+        assertFalse(mKeyEvent.isAltPressed());
+        assertFalse(mKeyEvent.isCtrlPressed());
+        assertTrue(mKeyEvent.isFunctionPressed());
+        assertFalse(mKeyEvent.isMetaPressed());
+        assertFalse(mKeyEvent.isShiftPressed());
+        assertFalse(mKeyEvent.isSymPressed());
+
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_3, 2,
+                KeyEvent.META_META_ON);
+        assertFalse(mKeyEvent.isAltPressed());
+        assertFalse(mKeyEvent.isCtrlPressed());
+        assertFalse(mKeyEvent.isFunctionPressed());
+        assertTrue(mKeyEvent.isMetaPressed());
+        assertFalse(mKeyEvent.isShiftPressed());
+        assertFalse(mKeyEvent.isSymPressed());
+
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_4, 1,
+                KeyEvent.META_SHIFT_ON);
+        assertFalse(mKeyEvent.isAltPressed());
+        assertFalse(mKeyEvent.isCtrlPressed());
+        assertFalse(mKeyEvent.isFunctionPressed());
+        assertFalse(mKeyEvent.isMetaPressed());
+        assertTrue(mKeyEvent.isShiftPressed());
+        assertFalse(mKeyEvent.isSymPressed());
+
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_5, 0,
+                KeyEvent.META_SYM_ON);
+        assertFalse(mKeyEvent.isAltPressed());
+        assertFalse(mKeyEvent.isCtrlPressed());
+        assertFalse(mKeyEvent.isFunctionPressed());
+        assertFalse(mKeyEvent.isMetaPressed());
+        assertFalse(mKeyEvent.isShiftPressed());
+        assertTrue(mKeyEvent.isSymPressed());
     }
 
+    @Test
     public void testGetDeadChar() {
         // decimal number of &egrave; is 232.
         assertEquals(232, KeyEvent.getDeadChar('`', 'e'));
     }
 
+    @Test
     public void testGetKeyData() {
-        KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z);
+        mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z);
         KeyData keyData = new KeyData();
-        assertTrue(keyEvent.getKeyData(keyData));
+        assertTrue(mKeyEvent.getKeyData(keyData));
 
         assertEquals('Z', keyData.displayLabel);
         assertEquals(0, keyData.number);
@@ -108,47 +181,51 @@
         assertEquals(0, keyData.meta[3]);
     }
 
+    @Test
     public void testDispatch() {
-        MockCallback callback = new MockCallback();
+        final KeyEvent.Callback callback = mock(KeyEvent.Callback.class);
+        doReturn(true).when(callback).onKeyDown(anyInt(), any(KeyEvent.class));
+        doReturn(true).when(callback).onKeyUp(anyInt(), any(KeyEvent.class));
+        doAnswer((InvocationOnMock invocation) -> {
+            final int count = (Integer) invocation.getArguments()[1];
+            return (count < 1) ? false : true;
+        }).when(callback).onKeyMultiple(anyInt(), anyInt(), any(KeyEvent.class));
+
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        callback.reset();
-        assertFalse(callback.isKeyDown());
+        verify(callback, never()).onKeyDown(anyInt(), any(KeyEvent.class));
         assertTrue(mKeyEvent.dispatch(callback));
-        assertTrue(callback.isKeyDown());
-        assertEquals(KeyEvent.KEYCODE_0, callback.getKeyCode());
-        assertSame(mKeyEvent, callback.getKeyEvent());
+        verify(callback, times(1)).onKeyDown(KeyEvent.KEYCODE_0, mKeyEvent);
+        verifyNoMoreInteractions(callback);
 
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
-        callback.reset();
-        assertFalse(callback.isKeyUp());
+        verify(callback, never()).onKeyUp(anyInt(), any(KeyEvent.class));
         assertTrue(mKeyEvent.dispatch(callback));
-        assertTrue(callback.isKeyUp());
-        assertEquals(KeyEvent.KEYCODE_0, callback.getKeyCode());
-        assertSame(mKeyEvent, callback.getKeyEvent());
+        verify(callback, times(1)).onKeyUp(KeyEvent.KEYCODE_0, mKeyEvent);
+        verifyNoMoreInteractions(callback);
 
-        callback.reset();
         int count = 2;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_MULTIPLE,
                 KeyEvent.KEYCODE_0, count);
-        assertFalse(callback.isKeyMultiple());
+        verify(callback, never()).onKeyMultiple(anyInt(), anyInt(), any(KeyEvent.class));
         assertTrue(mKeyEvent.dispatch(callback));
-        assertTrue(callback.isKeyMultiple());
-        assertEquals(KeyEvent.KEYCODE_0, callback.getKeyCode());
-        assertSame(mKeyEvent, callback.getKeyEvent());
-        assertEquals(count, callback.getCount());
+        verify(callback, times(1)).onKeyMultiple(KeyEvent.KEYCODE_0, count, mKeyEvent);
+        verifyNoMoreInteractions(callback);
 
-        callback.reset();
         count = 0;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_MULTIPLE,
                 KeyEvent.KEYCODE_0, count);
         assertTrue(mKeyEvent.dispatch(callback));
-        assertTrue(callback.isKeyMultiple());
-        assertTrue(callback.isKeyDown());
-        assertTrue(callback.isKeyUp());
-        assertEquals(count, callback.getCount());
-        assertEquals(KeyEvent.KEYCODE_0, callback.getKeyCode());
+        // Note that even though we didn't reset our mock callback, we have a brand new
+        // instance of KeyEvent in mKeyEvent. This is why we're expecting the relevant
+        // onKeyXXX() methods on the mock callback to be called once with that new KeyEvent
+        // instance.
+        verify(callback, times(1)).onKeyDown(KeyEvent.KEYCODE_0, mKeyEvent);
+        verify(callback, times(1)).onKeyMultiple(KeyEvent.KEYCODE_0, count, mKeyEvent);
+        verify(callback, times(1)).onKeyUp(KeyEvent.KEYCODE_0, mKeyEvent);
+        verifyNoMoreInteractions(callback);
     }
 
+    @Test
     public void testGetMetaState() {
         int metaState = KeyEvent.META_ALT_ON;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_MULTIPLE,
@@ -156,18 +233,21 @@
         assertEquals(metaState, mKeyEvent.getMetaState());
     }
 
+    @Test
     public void testGetEventTime() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5);
         assertEquals(mEventTime, mKeyEvent.getEventTime());
     }
 
+    @Test
     public void testGetDownTime() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5);
         assertEquals(mDownTime, mKeyEvent.getDownTime());
     }
 
+    @Test
     public void testGetUnicodeChar1() {
         // 48 is Unicode character of '0'
         assertEquals(48, mKeyEvent.getUnicodeChar());
@@ -183,6 +263,7 @@
         assertEquals(0, mKeyEvent.getUnicodeChar());
     }
 
+    @Test
     public void testGetUnicodeChar2() {
         // 48 is Unicode character of '0'
         assertEquals(48, mKeyEvent.getUnicodeChar(MetaKeyKeyListener.META_CAP_LOCKED));
@@ -198,6 +279,7 @@
         assertEquals(0, mKeyEvent.getUnicodeChar(0));
     }
 
+    @Test
     public void testGetNumber() {
         // 48 is associated with key '0'
         assertEquals(48, mKeyEvent.getNumber());
@@ -207,16 +289,7 @@
         assertEquals(51, mKeyEvent.getNumber());
     }
 
-    public void testIsSymPressed() {
-        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
-                KeyEvent.META_SYM_ON);
-        assertTrue(mKeyEvent.isSymPressed());
-
-        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
-                KeyEvent.META_SHIFT_ON);
-        assertFalse(mKeyEvent.isSymPressed());
-    }
-
+    @Test
     public void testGetDeviceId() {
         int deviceId = 1;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
@@ -224,21 +297,13 @@
         assertEquals(deviceId, mKeyEvent.getDeviceId());
     }
 
+    @Test
     public void testToString() {
         // make sure it does not throw any exception.
         mKeyEvent.toString();
     }
 
-    public void testIsAltPressed() {
-        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
-                KeyEvent.META_ALT_ON);
-        assertTrue(mKeyEvent.isAltPressed());
-
-        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, 5,
-                KeyEvent.META_SHIFT_ON);
-        assertFalse(mKeyEvent.isAltPressed());
-    }
-
+    @Test
     public void testGetModifierMetaStateMask() {
         int mask = KeyEvent.getModifierMetaStateMask();
         assertTrue((mask & KeyEvent.META_SHIFT_ON) != 0);
@@ -261,6 +326,7 @@
         assertFalse((mask & KeyEvent.META_SCROLL_LOCK_ON) != 0);
     }
 
+    @Test
     public void testIsModifierKey() {
         assertTrue(KeyEvent.isModifierKey(KeyEvent.KEYCODE_SHIFT_LEFT));
         assertTrue(KeyEvent.isModifierKey(KeyEvent.KEYCODE_SHIFT_RIGHT));
@@ -279,6 +345,7 @@
 
     private static final int UNDEFINED_META_STATE = 0x80000000;
 
+    @Test
     public void testNormalizeMetaState() {
         // Already normalized values.
         assertEquals(0, KeyEvent.normalizeMetaState(0));
@@ -312,6 +379,7 @@
                 KeyEvent.normalizeMetaState(KeyEvent.META_SHIFT_ON | UNDEFINED_META_STATE));
     }
 
+    @Test
     public void testMetaStateHasNoModifiers() {
         assertTrue(KeyEvent.metaStateHasNoModifiers(0));
         assertTrue(KeyEvent.metaStateHasNoModifiers(KeyEvent.META_CAPS_LOCK_ON));
@@ -334,6 +402,7 @@
         assertFalse(KeyEvent.metaStateHasNoModifiers(KeyEvent.META_FUNCTION_ON));
     }
 
+    @Test
     public void testMetaStateHasModifiers() {
         assertTrue(KeyEvent.metaStateHasModifiers(0, 0));
         assertTrue(KeyEvent.metaStateHasModifiers(
@@ -413,35 +482,39 @@
         assertFalse(KeyEvent.metaStateHasModifiers(0, UNDEFINED_META_STATE));
     }
 
+    @Test
     public void testHasNoModifiers() {
-        KeyEvent ev = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_A, 0, KeyEvent.META_CAPS_LOCK_ON);
-        assertTrue(ev.hasNoModifiers());
+        assertTrue(mKeyEvent.hasNoModifiers());
 
-        ev = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_A, 0, KeyEvent.META_CAPS_LOCK_ON | KeyEvent.META_SHIFT_ON);
-        assertFalse(ev.hasNoModifiers());
+        assertFalse(mKeyEvent.hasNoModifiers());
     }
 
+    @Test
     public void testHasModifiers() {
-        KeyEvent ev = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_A, 0, KeyEvent.META_CAPS_LOCK_ON);
-        assertTrue(ev.hasModifiers(0));
+        assertTrue(mKeyEvent.hasModifiers(0));
 
-        ev = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_A, 0, KeyEvent.META_CAPS_LOCK_ON | KeyEvent.META_SHIFT_ON);
-        assertTrue(ev.hasModifiers(KeyEvent.META_SHIFT_ON));
+        assertTrue(mKeyEvent.hasModifiers(KeyEvent.META_SHIFT_ON));
 
-        ev = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_A, 0,
                 KeyEvent.META_CAPS_LOCK_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_RIGHT_ON);
-        assertFalse(ev.hasModifiers(KeyEvent.META_SHIFT_LEFT_ON));
+        assertFalse(mKeyEvent.hasModifiers(KeyEvent.META_SHIFT_LEFT_ON));
     }
 
+    @Test
     public void testGetDisplayLabel() {
         assertTrue(mKeyEvent.getDisplayLabel() > 0);
     }
 
+    @Test
     public void testIsSystem() {
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
         assertTrue(mKeyEvent.isSystem());
@@ -486,6 +559,7 @@
         assertFalse(mKeyEvent.isSystem());
     }
 
+    @Test
     public void testIsPrintingKey() {
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, Character.SPACE_SEPARATOR);
         assertTrue(mKeyEvent.isPrintingKey());
@@ -506,22 +580,35 @@
         assertTrue(mKeyEvent.isPrintingKey());
     }
 
-    public void testGetMatch1() {
-        char[] codes1 = new char[] { '0', '1', '2' };
-        assertEquals('0', mKeyEvent.getMatch(codes1));
+    @Test
+    public void testGetMatch() {
+        // Our default key event is down + 0, so we expect getMatch to return our '0' character
+        assertEquals('0', mKeyEvent.getMatch(new char[] { '0', '1', '2' }));
 
-        char[] codes2 = new char[] { 'A', 'B', 'C' };
-        assertEquals('\0', mKeyEvent.getMatch(codes2));
+        // Our default key event is down + 0, so we expect getMatch to return the default 0
+        assertEquals('\0', mKeyEvent.getMatch(new char[] { 'A', 'B', 'C' }));
 
-        char[] codes3 = { '2', 'S' };
         mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_S);
-        assertEquals('S', mKeyEvent.getMatch(codes3));
+        assertEquals('S', mKeyEvent.getMatch(new char[] { '2', 'S' }));
     }
 
+    @Test
+    public void testGetMatchWithMeta() {
+        mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
+        // With no meta state, we're expecting our key event to match the lowercase 'a' since
+        // it's the first good match in the passed array
+        assertEquals('a', mKeyEvent.getMatch(new char[] { 'a', 'A' }, 0));
+        // With SHIFT_ON meta state, we're expecting the same key event to match the uppercase
+        // 'a' since it's a better match now
+        assertEquals('A', mKeyEvent.getMatch(new char[] { 'a', 'A' }, KeyEvent.META_SHIFT_ON));
+    }
+
+    @Test
     public void testGetAction() {
         assertEquals(KeyEvent.ACTION_DOWN, mKeyEvent.getAction());
     }
 
+    @Test
     public void testGetRepeatCount() {
         int repeatCount = 1;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_MULTIPLE,
@@ -529,6 +616,7 @@
         assertEquals(repeatCount, mKeyEvent.getRepeatCount());
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel parcel = Parcel.obtain();
         mKeyEvent.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
@@ -548,15 +636,18 @@
         assertEquals(mKeyEvent.getEventTime(), keyEvent.getEventTime());
     }
 
+    @Test
     public void testDescribeContents() {
         // make sure it never shrow any exception.
         mKeyEvent.describeContents();
     }
 
+    @Test
     public void testGetKeyCode() {
         assertEquals(KeyEvent.KEYCODE_0, mKeyEvent.getKeyCode());
     }
 
+    @Test
     public void testGetFlags() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5, KeyEvent.META_SHIFT_ON, 1, 1, KeyEvent.FLAG_WOKE_HERE);
@@ -567,6 +658,7 @@
         assertEquals(KeyEvent.FLAG_SOFT_KEYBOARD, mKeyEvent.getFlags());
     }
 
+    @Test
     public void testGetScanCode() {
         int scanCode = 1;
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
@@ -574,6 +666,7 @@
         assertEquals(scanCode, mKeyEvent.getScanCode());
     }
 
+    @Test
     public void testChangeAction() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5, KeyEvent.META_SHIFT_ON, 1, 1, KeyEvent.FLAG_WOKE_HERE);
@@ -590,6 +683,7 @@
         assertEquals(mKeyEvent.getRepeatCount(), newEvent.getRepeatCount());
     }
 
+    @Test
     public void testChangeFlags() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5, KeyEvent.META_SHIFT_ON, 1, 1, KeyEvent.FLAG_WOKE_HERE);
@@ -606,6 +700,7 @@
         assertEquals(mKeyEvent.getRepeatCount(), newEvent.getRepeatCount());
     }
 
+    @Test
     public void testChangeTimeRepeat() {
         mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
                 KeyEvent.KEYCODE_0, 5, KeyEvent.META_SHIFT_ON, 1, 1, KeyEvent.FLAG_WOKE_HERE);
@@ -624,71 +719,45 @@
         assertEquals(mKeyEvent.getKeyCode(), newEvent.getKeyCode());
     }
 
-    private class MockCallback implements Callback {
-        private boolean mIsKeyDown;
-        private boolean mIsKeyUp;
-        private boolean mIsMultiple;
-        private int mKeyCode;
-        private KeyEvent mKeyEvent;
-        private int mCount;
+    @Test
+    public void testAccessSource() {
+        mKeyEvent.setSource(InputDevice.SOURCE_KEYBOARD);
+        assertEquals(InputDevice.SOURCE_KEYBOARD, mKeyEvent.getSource());
 
-        public boolean isKeyDown() {
-            return mIsKeyDown;
-        }
+        mKeyEvent.setSource(InputDevice.SOURCE_HDMI);
+        assertEquals(InputDevice.SOURCE_HDMI, mKeyEvent.getSource());
+    }
 
-        public boolean isKeyUp() {
-            return mIsKeyUp;
-        }
+    @Test
+    public void testMetaOn() {
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_A, 0, KeyEvent.META_CAPS_LOCK_ON | KeyEvent.META_SHIFT_ON);
+        assertTrue(mKeyEvent.isCapsLockOn());
+        assertFalse(mKeyEvent.isNumLockOn());
+        assertFalse(mKeyEvent.isScrollLockOn());
 
-        public boolean isKeyMultiple() {
-            return mIsMultiple;
-        }
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_B, 1, KeyEvent.META_NUM_LOCK_ON | KeyEvent.META_SHIFT_ON);
+        assertFalse(mKeyEvent.isCapsLockOn());
+        assertTrue(mKeyEvent.isNumLockOn());
+        assertFalse(mKeyEvent.isScrollLockOn());
 
-        public int getKeyCode() {
-            return mKeyCode;
-        }
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_C, 2, KeyEvent.META_SCROLL_LOCK_ON | KeyEvent.META_SHIFT_ON);
+        assertFalse(mKeyEvent.isCapsLockOn());
+        assertFalse(mKeyEvent.isNumLockOn());
+        assertTrue(mKeyEvent.isScrollLockOn());
+    }
 
-        public KeyEvent getKeyEvent() {
-            return mKeyEvent;
-        }
+    @Test
+    public void testIsLongPress() {
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A,
+                1, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
+                InputDevice.SOURCE_TOUCHSCREEN);
+        assertTrue(mKeyEvent.isLongPress());
 
-        public int getCount() {
-            return mCount;
-        }
-
-        public void reset() {
-            mIsKeyDown = false;
-            mIsKeyUp = false;
-            mIsMultiple = false;
-        }
-
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            mIsKeyDown = true;
-            mKeyCode = keyCode;
-            mKeyEvent = event;
-            return true;
-        }
-
-        public boolean onKeyLongPress(int keyCode, KeyEvent event) {
-            return false;
-        }
-
-        public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
-            mIsMultiple = true;
-            mKeyCode = keyCode;
-            mKeyEvent = event;
-            mCount = count;
-            if (count < 1) {
-                return false; // this key event never repeat.
-            }
-            return true;
-        }
-
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            mIsKeyUp = true;
-            mKeyCode = keyCode;
-            mKeyEvent = event;
-            return true;
-        }
+        mKeyEvent = new KeyEvent(mDownTime, mEventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A,
+                1, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_TOUCHSCREEN);
+        assertFalse(mKeyEvent.isLongPress());
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
index 067f0bb..cae49c7 100644
--- a/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
@@ -1,25 +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 android.view.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 android.os.Parcel;
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
 
 import com.google.android.collect.Lists;
 
-import java.util.ArrayList;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.List;
 
 /**
  * Tests for {@link android.view.KeyboardShortcutGroup}.
  */
-public class KeyboardShortcutGroupTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutGroupTest {
     private static final CharSequence TEST_LABEL = "Test Group Label";
     private final List<KeyboardShortcutInfo> TEST_ITEMS = Lists.newArrayList(
             new KeyboardShortcutInfo("Item 1", KeyEvent.KEYCODE_U, KeyEvent.META_CTRL_ON),
             new KeyboardShortcutInfo("Item 2", KeyEvent.KEYCODE_F, KeyEvent.META_CTRL_ON));
 
+    @Test
     public void testConstructor() {
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
 
@@ -29,6 +55,7 @@
         assertEquals(0, group.describeContents());
     }
 
+    @Test
     public void testShortConstructor() {
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL);
 
@@ -38,6 +65,7 @@
         assertEquals(0, group.describeContents());
     }
 
+    @Test
     public void testSystemConstructor() {
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
 
@@ -47,6 +75,7 @@
         assertEquals(0, group.describeContents());
     }
 
+    @Test
     public void testSystemShortConstructor() {
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, true);
 
@@ -56,15 +85,12 @@
         assertEquals(0, group.describeContents());
     }
 
+    @Test(expected=NullPointerException.class)
     public void testConstructorChecksList() {
-        try {
-            KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, null);
-        } catch (NullPointerException expected) {
-            return;
-        }
-        fail();
+        new KeyboardShortcutGroup(TEST_LABEL, null);
     }
 
+    @Test
     public void testAddItem() {
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
 
@@ -76,6 +102,7 @@
         assertEquals("Additional item", group.getItems().get(newSize - 1).getLabel());
     }
 
+    @Test
     public void testWriteToParcelAndRead() {
         Parcel dest = Parcel.obtain();
         KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
diff --git a/tests/tests/view/src/android/view/cts/KeyboardShortcutInfoTest.java b/tests/tests/view/src/android/view/cts/KeyboardShortcutInfoTest.java
index 76dc43f..b2e809d 100644
--- a/tests/tests/view/src/android/view/cts/KeyboardShortcutInfoTest.java
+++ b/tests/tests/view/src/android/view/cts/KeyboardShortcutInfoTest.java
@@ -1,20 +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.view.cts;
 
-import android.graphics.drawable.Icon;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 import android.os.Parcel;
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutInfo;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Tests for {@link android.view.KeyboardShortcutInfo}.
  */
-public class KeyboardShortcutInfoTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutInfoTest {
     private static final CharSequence TEST_LABEL = "Test Label";
     private static final char TEST_BASE_CHARACTER = 't';
     private static final int TEST_KEYCODE = KeyEvent.KEYCODE_T;
     private static final int TEST_MODIFIERS = KeyEvent.META_ALT_ON | KeyEvent.META_CTRL_ON;
 
+    @Test
     public void testCharacterConstructor() {
         KeyboardShortcutInfo info = new KeyboardShortcutInfo(
                 TEST_LABEL, TEST_BASE_CHARACTER, TEST_MODIFIERS);
@@ -26,6 +50,7 @@
         assertEquals(0, info.describeContents());
     }
 
+    @Test
     public void testKeycodeConstructor() {
         KeyboardShortcutInfo info = new KeyboardShortcutInfo(
                 TEST_LABEL, TEST_KEYCODE, TEST_MODIFIERS);
@@ -37,26 +62,17 @@
         assertEquals(0, info.describeContents());
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testConstructorChecksBaseCharacter() {
-        try {
-            KeyboardShortcutInfo info = new KeyboardShortcutInfo(
-                    TEST_LABEL, Character.MIN_VALUE, TEST_MODIFIERS);
-        } catch (IllegalArgumentException expected) {
-            return;
-        }
-        fail();
+        new KeyboardShortcutInfo(TEST_LABEL, Character.MIN_VALUE, TEST_MODIFIERS);
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testConstructorChecksKeycode() {
-        try {
-            KeyboardShortcutInfo info = new KeyboardShortcutInfo(
-                    TEST_LABEL, KeyEvent.KEYCODE_UNKNOWN - 1, TEST_MODIFIERS);
-        } catch (IllegalArgumentException expected) {
-            return;
-        }
-        fail();
+        new KeyboardShortcutInfo(TEST_LABEL, KeyEvent.KEYCODE_UNKNOWN - 1, TEST_MODIFIERS);
     }
 
+    @Test
     public void testWriteToParcelAndReadCharacter() {
         Parcel dest = Parcel.obtain();
         KeyboardShortcutInfo info = new KeyboardShortcutInfo(
@@ -72,6 +88,7 @@
         assertEquals(TEST_MODIFIERS, result.getModifiers());
     }
 
+    @Test
     public void testWriteToParcelAndReadKeycode() {
         Parcel dest = Parcel.obtain();
         KeyboardShortcutInfo info = new KeyboardShortcutInfo(
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index 9208b13..b445165 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -16,10 +16,13 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-import android.view.cts.util.XmlUtils;
-
-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.junit.Assert.fail;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,50 +31,51 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.Gravity;
 import android.view.InflateException;
 import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
 import android.view.LayoutInflater.Factory;
 import android.view.LayoutInflater.Filter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.cts.util.XmlUtils;
 import android.widget.LinearLayout;
 
-public class LayoutInflaterTest 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 LayoutInflaterTest {
     private LayoutInflater mLayoutInflater;
 
-    @SuppressWarnings("hiding")
     private Context mContext;
 
-    private final Factory mFactory = new Factory() {
-        @Override
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
-            return null;
-        }
-    };
+    private final Factory mFactory = (String name, Context context, AttributeSet attrs) -> null;
+
     private boolean isOnLoadClass;
-    private final Filter mFilter = new Filter() {
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        @Override
-        public boolean onLoadClass(Class clazz) {
-            isOnLoadClass = true;
-            return true;
-        }
 
+    private final Filter mFilter = (Class clazz) -> {
+        isOnLoadClass = true;
+        return true;
     };
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
-        mLayoutInflater = (LayoutInflater) mContext
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mLayoutInflater = (LayoutInflater) mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
     }
 
+    @Test
     public void testFrom() {
         mLayoutInflater = null;
         mLayoutInflater = LayoutInflater.from(mContext);
@@ -85,12 +89,13 @@
         assertNotNull(layoutInflater);
     }
 
+    @Test
     public void testAccessLayoutInflaterProperties() {
         mLayoutInflater.setFilter(mFilter);
         assertSame(mFilter, mLayoutInflater.getFilter());
         mLayoutInflater.setFactory(mFactory);
         assertSame(mFactory, mLayoutInflater.getFactory());
-        mLayoutInflater=new MockLayoutInflater(mContext);
+        mLayoutInflater = new MockLayoutInflater(mContext);
         assertSame(mContext, mLayoutInflater.getContext());
     }
 
@@ -131,14 +136,13 @@
         return attrs;
     }
 
+    @Test
     public void testCreateView() {
-
         AttributeSet attrs = getAttrs();
         isOnLoadClass = false;
         View view = null;
         try {
-            view = mLayoutInflater
-                    .createView("testthrow", "com.android", attrs);
+            view = mLayoutInflater.createView("testthrow", "com.android", attrs);
             fail("should throw exception");
         } catch (InflateException e) {
         } catch (ClassNotFoundException e) {
@@ -148,13 +152,9 @@
         mLayoutInflater = null;
         mLayoutInflater = LayoutInflater.from(mContext);
         isOnLoadClass = false;
-        mLayoutInflater.setFilter(new Filter() {
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            @Override
-            public boolean onLoadClass(Class clazz) {
-                isOnLoadClass = true;
-                return false;
-            }
+        mLayoutInflater.setFilter((Class clazz) -> {
+            isOnLoadClass = true;
+            return false;
         });
         try {
             view = mLayoutInflater.createView("MockActivity",
@@ -208,162 +208,151 @@
         }
     }
 
+    @Test(expected=Resources.NotFoundException.class)
+    public void testInflateInvalidId() {
+        mLayoutInflater.inflate(-1, null);
+    }
+
+    @Test
     public void testInflate() {
         View view = mLayoutInflater.inflate(
                 android.view.cts.R.layout.inflater_layout, null);
         assertNotNull(view);
-        view = null;
-        try {
-            view = mLayoutInflater.inflate(-1, null);
-            fail("should throw exception");
-        } catch (Resources.NotFoundException e) {
-        }
-        LinearLayout mLayout;
-        mLayout = new LinearLayout(mContext);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setHorizontalGravity(Gravity.LEFT);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+
+        LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        linearLayout.setHorizontalGravity(Gravity.LEFT);
+        linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        assertEquals(0, mLayout.getChildCount());
+        assertEquals(0, linearLayout.getChildCount());
         view = mLayoutInflater.inflate(R.layout.inflater_layout,
-                mLayout);
+                linearLayout);
         assertNotNull(view);
-        assertEquals(1, mLayout.getChildCount());
+        assertEquals(1, linearLayout.getChildCount());
     }
 
-    public void testInflate2() {
+    @Test(expected=Resources.NotFoundException.class)
+    public void testInflateAttachToRootInvalidId() {
+        mLayoutInflater.inflate(-1, null, false);
+    }
+
+    @Test
+    public void testInflateAttachToRoot() {
         View view = mLayoutInflater.inflate(
                 R.layout.inflater_layout, null, false);
         assertNotNull(view);
-        view = null;
-        try {
-            view = mLayoutInflater.inflate(-1, null, false);
-            fail("should throw exception");
-        } catch (Resources.NotFoundException e) {
 
-        }
-        LinearLayout mLayout;
-        mLayout = new LinearLayout(mContext);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setHorizontalGravity(Gravity.LEFT);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+        LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        linearLayout.setHorizontalGravity(Gravity.LEFT);
+        linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        assertEquals(0, mLayout.getChildCount());
+        assertEquals(0, linearLayout.getChildCount());
         view = mLayoutInflater.inflate(R.layout.inflater_layout,
-                mLayout, false);
+                linearLayout, false);
         assertNotNull(view);
-        assertEquals(0, mLayout.getChildCount());
+        assertEquals(0, linearLayout.getChildCount());
 
-        view = null;
         view = mLayoutInflater.inflate(R.layout.inflater_layout,
-                mLayout, true);
+                linearLayout, true);
         assertNotNull(view);
-        assertEquals(1, mLayout.getChildCount());
+        assertEquals(1, linearLayout.getChildCount());
     }
 
-    public void testInflate3() {
-        XmlResourceParser parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
+    @Test(expected=NullPointerException.class)
+    public void testInflateParserNullParser() {
+        mLayoutInflater.inflate(null, null);
+    }
+
+    @Test
+    public void testInflateParser() {
+        XmlResourceParser parser = mContext.getResources().getLayout(R.layout.inflater_layout);
         View view = mLayoutInflater.inflate(parser, null);
         assertNotNull(view);
-        view = null;
-        try {
-            view = mLayoutInflater.inflate(null, null);
-            fail("should throw exception");
-        } catch (NullPointerException e) {
-        }
-        LinearLayout mLayout;
-        mLayout = new LinearLayout(mContext);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setHorizontalGravity(Gravity.LEFT);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+
+        LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        linearLayout.setHorizontalGravity(Gravity.LEFT);
+        linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        assertEquals(0, mLayout.getChildCount());
+        assertEquals(0, linearLayout.getChildCount());
 
         try {
-            view = mLayoutInflater.inflate(parser, mLayout);
+            mLayoutInflater.inflate(parser, linearLayout);
             fail("should throw exception");
         } catch (NullPointerException e) {
         }
-        parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
-        view = mLayoutInflater.inflate(parser, mLayout);
-        assertNotNull(view);
-        assertEquals(1, mLayout.getChildCount());
-        parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
-        view = mLayoutInflater.inflate(parser, mLayout);
-        assertNotNull(view);
-        assertEquals(2, mLayout.getChildCount());
 
-        parser = null;
-        view = null;
+        parser = mContext.getResources().getLayout(R.layout.inflater_layout);
+        view = mLayoutInflater.inflate(parser, linearLayout);
+        assertNotNull(view);
+        assertEquals(1, linearLayout.getChildCount());
+        parser = mContext.getResources().getLayout(R.layout.inflater_layout);
+        view = mLayoutInflater.inflate(parser, linearLayout);
+        assertNotNull(view);
+        assertEquals(2, linearLayout.getChildCount());
+
         parser = getParser();
-
-        view = mLayoutInflater.inflate(parser, mLayout);
+        view = mLayoutInflater.inflate(parser, linearLayout);
         assertNotNull(view);
-        assertEquals(3, mLayout.getChildCount());
+        assertEquals(3, linearLayout.getChildCount());
     }
 
-    public void testInflate4() {
-        XmlResourceParser parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
+    @Test(expected=NullPointerException.class)
+    public void testInflateParserAttachToRootNullParser() {
+        mLayoutInflater.inflate(null, null, false);
+    }
+
+    @Test
+    public void testInflateParserAttachToRoot() {
+        XmlResourceParser parser = mContext.getResources().getLayout(R.layout.inflater_layout);
         View view = mLayoutInflater.inflate(parser, null, false);
         assertNotNull(view);
-        view = null;
-        try {
-            view = mLayoutInflater.inflate(null, null, false);
-            fail("should throw exception");
-        } catch (NullPointerException e) {
-        }
-        LinearLayout mLayout;
-        mLayout = new LinearLayout(mContext);
-        mLayout.setOrientation(LinearLayout.VERTICAL);
-        mLayout.setHorizontalGravity(Gravity.LEFT);
-        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+
+        LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        linearLayout.setHorizontalGravity(Gravity.LEFT);
+        linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        assertEquals(0, mLayout.getChildCount());
+        assertEquals(0, linearLayout.getChildCount());
 
         try {
-            view = mLayoutInflater.inflate(parser, mLayout, false);
+            mLayoutInflater.inflate(parser, linearLayout, false);
             fail("should throw exception");
         } catch (NullPointerException e) {
         }
-        parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
-        view = mLayoutInflater.inflate(parser, mLayout, false);
-        assertNull(view.getParent());
-        assertNotNull(view);
-        assertEquals(0, mLayout.getChildCount());
-        parser = getContext().getResources().getLayout(
-                R.layout.inflater_layout);
-        assertEquals(0, mLayout.getChildCount());
-        view = mLayoutInflater.inflate(parser, mLayout, true);
-        assertNotNull(view);
-        assertNull(view.getParent());
-        assertEquals(1, mLayout.getChildCount());
 
-        parser = null;
+        parser = mContext.getResources().getLayout(R.layout.inflater_layout);
+        view = mLayoutInflater.inflate(parser, linearLayout, false);
+        assertNull(view.getParent());
+        assertNotNull(view);
+        assertEquals(0, linearLayout.getChildCount());
+        parser = mContext.getResources().getLayout(R.layout.inflater_layout);
+        assertEquals(0, linearLayout.getChildCount());
+        view = mLayoutInflater.inflate(parser, linearLayout, true);
+        assertNotNull(view);
+        assertNull(view.getParent());
+        assertEquals(1, linearLayout.getChildCount());
+
         parser = getParser();
         try {
-            view = mLayoutInflater.inflate(parser, mLayout, false);
+            mLayoutInflater.inflate(parser, linearLayout, false);
             fail("should throw exception");
         } catch (InflateException e) {
         }
 
-        parser = null;
-        view = null;
         parser = getParser();
 
-        view = mLayoutInflater.inflate(parser, mLayout, true);
+        view = mLayoutInflater.inflate(parser, linearLayout, true);
         assertNotNull(view);
-        assertEquals(2, mLayout.getChildCount());
+        assertEquals(2, linearLayout.getChildCount());
     }
 
+    @Test
     public void testOverrideTheme() {
         View container = mLayoutInflater.inflate(R.layout.inflater_override_theme_layout, null);
         verifyThemeType(container, "view_outer", R.id.view_outer, 1);
@@ -383,6 +372,7 @@
         assertEquals(tag + " has themeType " + type, type, outValue.data);
     }
 
+    @Test
     public void testInflateTags() {
         final View view = mLayoutInflater.inflate(
                 android.view.cts.R.layout.inflater_layout_tags, null);
diff --git a/tests/tests/view/src/android/view/cts/LongPressBackActivity.java b/tests/tests/view/src/android/view/cts/LongPressBackActivity.java
index 55bcdd5..6df956d 100644
--- a/tests/tests/view/src/android/view/cts/LongPressBackActivity.java
+++ b/tests/tests/view/src/android/view/cts/LongPressBackActivity.java
@@ -16,9 +16,6 @@
 
 package android.view.cts;
 
-import android.view.MotionEvent;
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.KeyEvent;
diff --git a/tests/tests/view/src/android/view/cts/LongPressBackTest.java b/tests/tests/view/src/android/view/cts/LongPressBackTest.java
index ade44c9..5ee9753 100644
--- a/tests/tests/view/src/android/view/cts/LongPressBackTest.java
+++ b/tests/tests/view/src/android/view/cts/LongPressBackTest.java
@@ -16,32 +16,33 @@
 
 package android.view.cts;
 
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
 import android.app.UiAutomation;
 import android.content.pm.PackageManager;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.ViewConfiguration;
-
 import android.view.KeyEvent;
+import android.view.ViewConfiguration;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static junit.framework.TestCase.*;
-
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class LongPressBackTest {
-    static final String TAG = "LongPressBackTest";
+    private LongPressBackActivity mActivity;
 
     @Rule
     public ActivityTestRule<LongPressBackActivity> mActivityRule =
             new ActivityTestRule<>(LongPressBackActivity.class);
 
-    private LongPressBackActivity mActivity;
-
     @Before
     public void setUp() {
         mActivity = mActivityRule.getActivity();
@@ -52,7 +53,7 @@
      * non-watch devices
      */
     @Test
-    public void testAppIsNotDismissed() throws Exception {
+    public void testAppIsNotDismissed() {
         // Only run for non-watch devices
         if (mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
             return;
@@ -68,7 +69,7 @@
 
         // Wait long press time plus a few ms to ensure events get triggered
         long timeout = ViewConfiguration.get(mActivity).getDeviceGlobalActionKeyTimeout();
-        try { Thread.sleep(timeout + 500); } catch (InterruptedException ignored) {}
+        SystemClock.sleep(timeout + 500);
 
         // Activity should not have been stopped and back key down should have been registered
         assertFalse(mActivity.wasPaused());
diff --git a/tests/tests/view/src/android/view/cts/MenuInflaterCtsActivity.java b/tests/tests/view/src/android/view/cts/MenuInflaterCtsActivity.java
deleted file mode 100644
index 75adede..0000000
--- a/tests/tests/view/src/android/view/cts/MenuInflaterCtsActivity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.
- */
-
-package android.view.cts;
-
-import android.app.Activity;
-import android.view.MenuInflater;
-
-/**
- * Stub activity for testing {@link MenuInflater}.
- *
- * @see MenuInflaterTest
- */
-public class MenuInflaterCtsActivity extends Activity {
-}
diff --git a/tests/tests/view/src/android/view/cts/MenuInflaterTest.java b/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
index 9ced9c7..9da739e 100644
--- a/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/MenuInflaterTest.java
@@ -16,194 +16,223 @@
 
 package android.view.cts;
 
-import android.view.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.content.res.Resources;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.SubMenu;
 import android.widget.PopupMenu;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link MenuInflater}.
  */
-public class MenuInflaterTest extends ActivityInstrumentationTestCase2<MenuInflaterCtsActivity> {
-    private MenuInflater mMenuInflater;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class MenuInflaterTest {
     private Activity mActivity;
+    private MenuInflater mMenuInflater;
+    private Menu mMenu;
 
-    public MenuInflaterTest() {
-        super("android.view.cts", MenuInflaterCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule =
+            new ActivityTestRule<>(MockActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    private Menu createMenu(Activity context) {
-        return new PopupMenu(context, null).getMenu();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mMenuInflater = mActivity.getMenuInflater();
+        mMenu = new PopupMenu(mActivity, null).getMenu();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new MenuInflater(mActivity);
     }
 
     @UiThreadTest
+    @Test
     public void testInflate() {
-        Menu menu = createMenu(mActivity);
-        assertEquals(0, menu.size());
+        assertEquals(0, mMenu.size());
 
-        if (mMenuInflater == null) {
-            mMenuInflater = mActivity.getMenuInflater();
-        }
-
-        mMenuInflater.inflate(android.view.cts.R.menu.browser, menu);
-        assertNotNull(menu);
-        assertEquals(1, menu.size());
-
-        try {
-            mMenuInflater.inflate(0, menu);
-            fail("should throw Resources.NotFoundException");
-        } catch (Resources.NotFoundException e) {
-        }
-
-        try {
-            mMenuInflater.inflate(android.view.cts.R.menu.browser, null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        mMenuInflater.inflate(R.menu.browser, mMenu);
+        assertEquals(1, mMenu.size());
     }
 
-    // Check wheher the objects are created correctly from xml files
     @UiThreadTest
-    public void testInflateFromXml(){
-        if (mMenuInflater == null) {
-            mMenuInflater = mActivity.getMenuInflater();
-        }
+    @Test(expected=Resources.NotFoundException.class)
+    public void testInflateInvalidId() {
+        mMenuInflater.inflate(0, mMenu);
+    }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testInflateNullMenu() {
+        mMenuInflater.inflate(R.menu.browser, null);
+    }
+
+    // Check whether the objects are created correctly from xml files
+    @UiThreadTest
+    @Test
+    public void testInflateAlphabeticShortcutFromXml() {
         // the visibility and shortcut
-        Menu menu = createMenu(mActivity);
-        mMenuInflater.inflate(R.menu.visible_shortcut, menu);
+        mMenuInflater.inflate(R.menu.visible_shortcut, mMenu);
 
-        assertTrue(menu.findItem(R.id.visible_item).isVisible());
-        assertEquals('a', menu.findItem(R.id.visible_item).getAlphabeticShortcut());
+        assertTrue(mMenu.findItem(R.id.visible_item).isVisible());
+        assertEquals('a', mMenu.findItem(R.id.visible_item).getAlphabeticShortcut());
 
-        assertFalse(menu.findItem(R.id.hidden_item).isVisible());
-        assertEquals('b', menu.findItem(R.id.hidden_item).getAlphabeticShortcut());
+        assertFalse(mMenu.findItem(R.id.hidden_item).isVisible());
+        assertEquals('b', mMenu.findItem(R.id.hidden_item).getAlphabeticShortcut());
 
-        assertEquals(R.id.hidden_group, menu.findItem(R.id.hidden_by_group).getGroupId());
-        assertFalse(menu.findItem(R.id.hidden_by_group).isVisible());
-        assertEquals('c', menu.findItem(R.id.hidden_by_group).getAlphabeticShortcut());
+        assertEquals(R.id.hidden_group, mMenu.findItem(R.id.hidden_by_group).getGroupId());
+        assertFalse(mMenu.findItem(R.id.hidden_by_group).isVisible());
+        assertEquals('c', mMenu.findItem(R.id.hidden_by_group).getAlphabeticShortcut());
+    }
 
+    @UiThreadTest
+    @Test
+    public void testInflateDrawableFromXml() {
         // the titles and icons
-        menu = createMenu(mActivity);
-        mMenuInflater.inflate(android.view.cts.R.menu.title_icon, menu);
+        mMenuInflater.inflate(R.menu.title_icon, mMenu);
 
-        assertEquals("Start", menu.findItem(R.id.start).getTitle());
-        assertIconUsingDrawableRes((BitmapDrawable) menu.findItem(R.id.start).getIcon(),
+        assertEquals("Start", mMenu.findItem(R.id.start).getTitle());
+        verifyDrawableContent((BitmapDrawable) mMenu.findItem(R.id.start).getIcon(),
                 R.drawable.start);
 
-        assertEquals("Pass", menu.findItem(R.id.pass).getTitle());
-        assertIconUsingDrawableRes((BitmapDrawable) menu.findItem(R.id.pass).getIcon(),
+        assertEquals("Pass", mMenu.findItem(R.id.pass).getTitle());
+        verifyDrawableContent((BitmapDrawable) mMenu.findItem(R.id.pass).getIcon(),
                 R.drawable.pass);
 
-        assertEquals("Failed", menu.findItem(R.id.failed).getTitle());
-        assertIconUsingDrawableRes((BitmapDrawable) menu.findItem(R.id.failed).getIcon(),
+        assertEquals("Failed", mMenu.findItem(R.id.failed).getTitle());
+        verifyDrawableContent((BitmapDrawable) mMenu.findItem(R.id.failed).getIcon(),
                 R.drawable.failed);
+    }
 
+    @UiThreadTest
+    @Test
+    public void testInflateOrderFromXml() {
         // the orders and categories
-        menu = createMenu(mActivity);
-        mMenuInflater.inflate(android.view.cts.R.menu.category_order, menu);
+        mMenuInflater.inflate(R.menu.category_order, mMenu);
         // default category
-        assertEquals(R.id.most_used_items, menu.findItem(R.id.first_most_item).getGroupId());
-        assertEquals(1, menu.findItem(R.id.first_most_item).getOrder());
+        assertEquals(R.id.most_used_items, mMenu.findItem(R.id.first_most_item).getGroupId());
+        assertEquals(1, mMenu.findItem(R.id.first_most_item).getOrder());
 
-        assertEquals(R.id.most_used_items, menu.findItem(R.id.middle_most_item).getGroupId());
-        assertEquals(3, menu.findItem(R.id.middle_most_item).getOrder());
+        assertEquals(R.id.most_used_items, mMenu.findItem(R.id.middle_most_item).getGroupId());
+        assertEquals(3, mMenu.findItem(R.id.middle_most_item).getOrder());
 
-        assertEquals(R.id.most_used_items, menu.findItem(R.id.last_most_item).getGroupId());
-        assertEquals(5, menu.findItem(R.id.last_most_item).getOrder());
+        assertEquals(R.id.most_used_items, mMenu.findItem(R.id.last_most_item).getGroupId());
+        assertEquals(5, mMenu.findItem(R.id.last_most_item).getOrder());
 
         // specific category (CATEGORY_SECONDARY)
-        assertEquals(R.id.least_used_items, menu.findItem(R.id.first_least_item).getGroupId());
-        assertEquals(Menu.CATEGORY_SECONDARY + 0, menu.findItem(R.id.first_least_item).getOrder());
+        assertEquals(R.id.least_used_items, mMenu.findItem(R.id.first_least_item).getGroupId());
+        assertEquals(Menu.CATEGORY_SECONDARY + 0, mMenu.findItem(R.id.first_least_item).getOrder());
 
-        assertEquals(R.id.least_used_items, menu.findItem(R.id.middle_least_item).getGroupId());
+        assertEquals(R.id.least_used_items, mMenu.findItem(R.id.middle_least_item).getGroupId());
         assertEquals(Menu.CATEGORY_SECONDARY + 2,
-                menu.findItem(R.id.middle_least_item).getOrder());
+                mMenu.findItem(R.id.middle_least_item).getOrder());
 
-        assertEquals(R.id.least_used_items, menu.findItem(R.id.last_least_item).getGroupId());
-        assertEquals(Menu.CATEGORY_SECONDARY + 4, menu.findItem(R.id.last_least_item).getOrder());
+        assertEquals(R.id.least_used_items, mMenu.findItem(R.id.last_least_item).getGroupId());
+        assertEquals(Menu.CATEGORY_SECONDARY + 4, mMenu.findItem(R.id.last_least_item).getOrder());
+    }
 
-        // the checkables
-        menu = createMenu(mActivity);
-        mMenuInflater.inflate(android.view.cts.R.menu.checkable, menu);
+    @UiThreadTest
+    @Test
+    public void testInflateCheckableFromXmlNone() {
+        mMenuInflater.inflate(R.menu.checkable, mMenu);
+
         // noncheckables
         assertEquals(R.id.noncheckable_group,
-                menu.findItem(R.id.noncheckable_item_1).getGroupId());
-        assertFalse(menu.findItem(R.id.noncheckable_item_1).isCheckable());
+                mMenu.findItem(R.id.noncheckable_item_1).getGroupId());
+        assertFalse(mMenu.findItem(R.id.noncheckable_item_1).isCheckable());
 
         assertEquals(R.id.noncheckable_group,
-                menu.findItem(R.id.noncheckable_item_2).getGroupId());
-        assertFalse(menu.findItem(R.id.noncheckable_item_2).isCheckable());
+                mMenu.findItem(R.id.noncheckable_item_2).getGroupId());
+        assertFalse(mMenu.findItem(R.id.noncheckable_item_2).isCheckable());
 
         assertEquals(R.id.noncheckable_group,
-                menu.findItem(R.id.noncheckable_item_3).getGroupId());
-        assertFalse(menu.findItem(R.id.noncheckable_item_3).isCheckable());
+                mMenu.findItem(R.id.noncheckable_item_3).getGroupId());
+        assertFalse(mMenu.findItem(R.id.noncheckable_item_3).isCheckable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testInflateCheckableFromXmlMultiples() {
+        mMenuInflater.inflate(R.menu.checkable, mMenu);
 
         // multiple checkables (item 2 and item 3 are both checked)
-        assertEquals(R.id.checkable_group, menu.findItem(R.id.checkable_item_1).getGroupId());
-        assertTrue(menu.findItem(R.id.checkable_item_1).isCheckable());
-        assertFalse(menu.findItem(R.id.checkable_item_1).isChecked());
+        assertEquals(R.id.checkable_group, mMenu.findItem(R.id.checkable_item_1).getGroupId());
+        assertTrue(mMenu.findItem(R.id.checkable_item_1).isCheckable());
+        assertFalse(mMenu.findItem(R.id.checkable_item_1).isChecked());
 
-        assertEquals(R.id.checkable_group, menu.findItem(R.id.checkable_item_3).getGroupId());
-        assertTrue(menu.findItem(R.id.checkable_item_2).isCheckable());
-        assertTrue(menu.findItem(R.id.checkable_item_2).isChecked());
+        assertEquals(R.id.checkable_group, mMenu.findItem(R.id.checkable_item_3).getGroupId());
+        assertTrue(mMenu.findItem(R.id.checkable_item_2).isCheckable());
+        assertTrue(mMenu.findItem(R.id.checkable_item_2).isChecked());
 
-        assertEquals(R.id.checkable_group, menu.findItem(R.id.checkable_item_2).getGroupId());
-        assertTrue(menu.findItem(R.id.checkable_item_3).isCheckable());
-        assertTrue(menu.findItem(R.id.checkable_item_3).isChecked());
+        assertEquals(R.id.checkable_group, mMenu.findItem(R.id.checkable_item_2).getGroupId());
+        assertTrue(mMenu.findItem(R.id.checkable_item_3).isCheckable());
+        assertTrue(mMenu.findItem(R.id.checkable_item_3).isChecked());
 
         // make item 1 checked and item 2 and item 3 will remain checked
-        menu.findItem(R.id.checkable_item_1).setChecked(true);
-        assertTrue(menu.findItem(R.id.checkable_item_1).isChecked());
-        assertTrue(menu.findItem(R.id.checkable_item_2).isChecked());
-        assertTrue(menu.findItem(R.id.checkable_item_3).isChecked());
+        mMenu.findItem(R.id.checkable_item_1).setChecked(true);
+        assertTrue(mMenu.findItem(R.id.checkable_item_1).isChecked());
+        assertTrue(mMenu.findItem(R.id.checkable_item_2).isChecked());
+        assertTrue(mMenu.findItem(R.id.checkable_item_3).isChecked());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testInflateCheckableFromXmlExclusive() {
+        mMenuInflater.inflate(R.menu.checkable, mMenu);
 
         // exclusive checkables (only item 3 is checked)
         assertEquals(R.id.exclusive_checkable_group,
-                menu.findItem(R.id.exclusive_checkable_item_1).getGroupId());
-        assertTrue(menu.findItem(R.id.exclusive_checkable_item_1).isCheckable());
-        assertFalse(menu.findItem(R.id.exclusive_checkable_item_1).isChecked());
+                mMenu.findItem(R.id.exclusive_checkable_item_1).getGroupId());
+        assertTrue(mMenu.findItem(R.id.exclusive_checkable_item_1).isCheckable());
+        assertFalse(mMenu.findItem(R.id.exclusive_checkable_item_1).isChecked());
 
         assertEquals(R.id.exclusive_checkable_group,
-                menu.findItem(R.id.exclusive_checkable_item_3).getGroupId());
-        assertTrue(menu.findItem(R.id.exclusive_checkable_item_2).isCheckable());
-        assertFalse(menu.findItem(R.id.exclusive_checkable_item_2).isChecked());
+                mMenu.findItem(R.id.exclusive_checkable_item_3).getGroupId());
+        assertTrue(mMenu.findItem(R.id.exclusive_checkable_item_2).isCheckable());
+        assertFalse(mMenu.findItem(R.id.exclusive_checkable_item_2).isChecked());
 
         assertEquals(R.id.exclusive_checkable_group,
-                menu.findItem(R.id.exclusive_checkable_item_2).getGroupId());
-        assertTrue(menu.findItem(R.id.exclusive_checkable_item_3).isCheckable());
-        assertTrue(menu.findItem(R.id.exclusive_checkable_item_3).isChecked());
+                mMenu.findItem(R.id.exclusive_checkable_item_2).getGroupId());
+        assertTrue(mMenu.findItem(R.id.exclusive_checkable_item_3).isCheckable());
+        assertTrue(mMenu.findItem(R.id.exclusive_checkable_item_3).isChecked());
 
         // make item 1 checked and item 3 will be unchecked
-        menu.findItem(R.id.exclusive_checkable_item_1).setChecked(true);
-        assertTrue(menu.findItem(R.id.exclusive_checkable_item_1).isChecked());
-        assertFalse(menu.findItem(R.id.exclusive_checkable_item_2).isChecked());
-        assertFalse(menu.findItem(R.id.exclusive_checkable_item_3).isChecked());
+        mMenu.findItem(R.id.exclusive_checkable_item_1).setChecked(true);
+        assertTrue(mMenu.findItem(R.id.exclusive_checkable_item_1).isChecked());
+        assertFalse(mMenu.findItem(R.id.exclusive_checkable_item_2).isChecked());
+        assertFalse(mMenu.findItem(R.id.exclusive_checkable_item_3).isChecked());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testInflateCheckableFromXmlSubmenu() {
+        mMenuInflater.inflate(R.menu.checkable, mMenu);
 
         // checkables without group (all in a sub menu)
-        SubMenu subMenu = menu.findItem(R.id.submenu).getSubMenu();
+        SubMenu subMenu = mMenu.findItem(R.id.submenu).getSubMenu();
         assertNotNull(subMenu);
 
         assertTrue(subMenu.findItem(R.id.nongroup_checkable_item_1).isCheckable());
@@ -217,12 +246,12 @@
 
         // make item 1 checked and item 2 and item 3 will remain checked
         subMenu.findItem(R.id.nongroup_checkable_item_1).setChecked(true);
-        assertTrue(menu.findItem(R.id.nongroup_checkable_item_1).isChecked());
-        assertTrue(menu.findItem(R.id.nongroup_checkable_item_2).isChecked());
-        assertTrue(menu.findItem(R.id.nongroup_checkable_item_3).isChecked());
+        assertTrue(mMenu.findItem(R.id.nongroup_checkable_item_1).isChecked());
+        assertTrue(mMenu.findItem(R.id.nongroup_checkable_item_2).isChecked());
+        assertTrue(mMenu.findItem(R.id.nongroup_checkable_item_3).isChecked());
     }
 
-    public void assertIconUsingDrawableRes(BitmapDrawable b, int resId) {
+    private void verifyDrawableContent(BitmapDrawable b, int resId) {
         Bitmap expected = BitmapFactory.decodeResource(mActivity.getResources(), resId);
         WidgetTestUtils.assertEquals(expected, b.getBitmap());
     }
diff --git a/tests/tests/view/src/android/view/cts/MockApplication.java b/tests/tests/view/src/android/view/cts/MockApplication.java
deleted file mode 100644
index e99e6b8..0000000
--- a/tests/tests/view/src/android/view/cts/MockApplication.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-package android.view.cts;
-
-import android.app.Application;
-import android.content.res.Configuration;
-
-
-public class MockApplication extends Application {
-
-    public boolean isOnCreateCalled;
-    public boolean isConstructorCalled;
-    public boolean isOnConfigurationChangedCalled;
-    public boolean isOnLowMemoryCalled;
-
-    public MockApplication() {
-        super();
-        isConstructorCalled = true;
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        isOnCreateCalled = true;
-    }
-
-    @Override
-    public void onTerminate() {
-        super.onTerminate();
-        // The documentation states that one cannot rely on this method being called. No need to
-        // test it here.
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        isOnConfigurationChangedCalled = true;
-    }
-
-    @Override
-    public void onLowMemory() {
-        super.onLowMemory();
-        isOnLowMemoryCalled = true;
-    }
-}
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/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index 6b2cc18..7938d64 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -25,12 +25,12 @@
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
 
 public class MockView extends View {
     private boolean mCalledOnCreateContextMenu = false;
diff --git a/tests/tests/view/src/android/view/cts/MotionEventTest.java b/tests/tests/view/src/android/view/cts/MotionEventTest.java
index 10ea33a..f9b2e4f 100644
--- a/tests/tests/view/src/android/view/cts/MotionEventTest.java
+++ b/tests/tests/view/src/android/view/cts/MotionEventTest.java
@@ -16,24 +16,44 @@
 
 package android.view.cts;
 
+import static android.view.cts.MotionEventUtils.withCoords;
+import static android.view.cts.MotionEventUtils.withProperties;
+
+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.junit.Assert.fail;
 
 import android.graphics.Matrix;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
+import android.view.cts.MotionEventUtils.PointerCoordsBuilder;
+import android.view.cts.MotionEventUtils.PointerPropertiesBuilder;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link MotionEvent}.
  */
-public class MotionEventTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MotionEventTest {
     private MotionEvent mMotionEvent1;
     private MotionEvent mMotionEvent2;
+    private MotionEvent mMotionEventDynamic;
     private long mDownTime;
     private long mEventTime;
     private static final float X_3F           = 3.0f;
@@ -47,10 +67,8 @@
     private static final int EDGE_FLAGS       = MotionEvent.EDGE_TOP;
     private static final float DELTA          = 0.01f;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setup() {
         mDownTime = SystemClock.uptimeMillis();
         mEventTime = SystemClock.uptimeMillis();
         mMotionEvent1 = MotionEvent.obtain(mDownTime, mEventTime,
@@ -60,18 +78,21 @@
                 X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         if (null != mMotionEvent1) {
             mMotionEvent1.recycle();
         }
         if (null != mMotionEvent2) {
             mMotionEvent2.recycle();
         }
-        super.tearDown();
+        if (null != mMotionEventDynamic) {
+            mMotionEventDynamic.recycle();
+        }
     }
 
-    public void testObtain1() {
+    @Test
+    public void testObtainBasic() {
         mMotionEvent1 = MotionEvent.obtain(mDownTime, mEventTime,
                 MotionEvent.ACTION_DOWN, X_3F, Y_4F, META_STATE);
         assertNotNull(mMotionEvent1);
@@ -91,49 +112,110 @@
         assertEquals(1.0f, mMotionEvent1.getYPrecision(), DELTA);
     }
 
-    public void testObtain2() {
-        MotionEvent motionEvent = MotionEvent.obtain(mDownTime, mEventTime,
-                MotionEvent.ACTION_DOWN, X_3F, Y_4F, META_STATE);
-        mMotionEvent1 = MotionEvent.obtain(motionEvent);
-        assertNotNull(mMotionEvent1);
-        assertEquals(motionEvent.getDownTime(), mMotionEvent1.getDownTime());
-        assertEquals(motionEvent.getEventTime(), mMotionEvent1.getEventTime());
-        assertEquals(motionEvent.getAction(), mMotionEvent1.getAction());
-        assertEquals(motionEvent.getX(), mMotionEvent1.getX(), DELTA);
-        assertEquals(motionEvent.getY(), mMotionEvent1.getY(), DELTA);
-        assertEquals(motionEvent.getX(), mMotionEvent1.getRawX(), DELTA);
-        assertEquals(motionEvent.getY(), mMotionEvent1.getRawY(), DELTA);
-        assertEquals(motionEvent.getMetaState(), mMotionEvent1.getMetaState());
-        assertEquals(motionEvent.getDeviceId(), mMotionEvent1.getDeviceId());
-        assertEquals(motionEvent.getEdgeFlags(), mMotionEvent1.getEdgeFlags());
-        assertEquals(motionEvent.getPressure(), mMotionEvent1.getPressure(), DELTA);
-        assertEquals(motionEvent.getSize(), mMotionEvent1.getSize(), DELTA);
-        assertEquals(motionEvent.getXPrecision(), mMotionEvent1.getXPrecision(), DELTA);
-        assertEquals(motionEvent.getYPrecision(), mMotionEvent1.getYPrecision(), DELTA);
+    @Test
+    public void testObtainFromMotionEvent() {
+        mMotionEventDynamic = MotionEvent.obtain(mMotionEvent2);
+        assertNotNull(mMotionEventDynamic);
+        assertEquals(mMotionEvent2.getDownTime(), mMotionEventDynamic.getDownTime());
+        assertEquals(mMotionEvent2.getEventTime(), mMotionEventDynamic.getEventTime());
+        assertEquals(mMotionEvent2.getAction(), mMotionEventDynamic.getAction());
+        assertEquals(mMotionEvent2.getX(), mMotionEventDynamic.getX(), DELTA);
+        assertEquals(mMotionEvent2.getY(), mMotionEventDynamic.getY(), DELTA);
+        assertEquals(mMotionEvent2.getX(), mMotionEventDynamic.getRawX(), DELTA);
+        assertEquals(mMotionEvent2.getY(), mMotionEventDynamic.getRawY(), DELTA);
+        assertEquals(mMotionEvent2.getMetaState(), mMotionEventDynamic.getMetaState());
+        assertEquals(mMotionEvent2.getDeviceId(), mMotionEventDynamic.getDeviceId());
+        assertEquals(mMotionEvent2.getEdgeFlags(), mMotionEventDynamic.getEdgeFlags());
+        assertEquals(mMotionEvent2.getPressure(), mMotionEventDynamic.getPressure(), DELTA);
+        assertEquals(mMotionEvent2.getSize(), mMotionEventDynamic.getSize(), DELTA);
+        assertEquals(mMotionEvent2.getXPrecision(), mMotionEventDynamic.getXPrecision(), DELTA);
+        assertEquals(mMotionEvent2.getYPrecision(), mMotionEventDynamic.getYPrecision(), DELTA);
     }
 
-    public void testObtain3() {
-        mMotionEvent1 = null;
-        mMotionEvent1 = MotionEvent.obtain(mDownTime, mEventTime,
+    @Test
+    public void testObtainAllFields() {
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
                 MotionEvent.ACTION_DOWN, X_3F, Y_4F, PRESSURE_1F, SIZE_1F, META_STATE,
                 X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS);
-        assertNotNull(mMotionEvent1);
-        assertEquals(mDownTime, mMotionEvent1.getDownTime());
-        assertEquals(mEventTime, mMotionEvent1.getEventTime());
-        assertEquals(MotionEvent.ACTION_DOWN, mMotionEvent1.getAction());
-        assertEquals(X_3F, mMotionEvent1.getX(), DELTA);
-        assertEquals(Y_4F, mMotionEvent1.getY(), DELTA);
-        assertEquals(X_3F, mMotionEvent1.getRawX(), DELTA);
-        assertEquals(Y_4F, mMotionEvent1.getRawY(), DELTA);
-        assertEquals(META_STATE, mMotionEvent1.getMetaState());
-        assertEquals(DEVICE_ID_1, mMotionEvent1.getDeviceId());
-        assertEquals(EDGE_FLAGS, mMotionEvent1.getEdgeFlags());
-        assertEquals(PRESSURE_1F, mMotionEvent1.getPressure(), DELTA);
-        assertEquals(SIZE_1F, mMotionEvent1.getSize(), DELTA);
-        assertEquals(X_PRECISION_3F, mMotionEvent1.getXPrecision(), DELTA);
-        assertEquals(Y_PRECISION_4F, mMotionEvent1.getYPrecision(), DELTA);
+        assertNotNull(mMotionEventDynamic);
+        assertEquals(mDownTime, mMotionEventDynamic.getDownTime());
+        assertEquals(mEventTime, mMotionEventDynamic.getEventTime());
+        assertEquals(MotionEvent.ACTION_DOWN, mMotionEventDynamic.getAction());
+        assertEquals(X_3F, mMotionEventDynamic.getX(), DELTA);
+        assertEquals(Y_4F, mMotionEventDynamic.getY(), DELTA);
+        assertEquals(X_3F, mMotionEventDynamic.getRawX(), DELTA);
+        assertEquals(Y_4F, mMotionEventDynamic.getRawY(), DELTA);
+        assertEquals(META_STATE, mMotionEventDynamic.getMetaState());
+        assertEquals(DEVICE_ID_1, mMotionEventDynamic.getDeviceId());
+        assertEquals(EDGE_FLAGS, mMotionEventDynamic.getEdgeFlags());
+        assertEquals(PRESSURE_1F, mMotionEventDynamic.getPressure(), DELTA);
+        assertEquals(SIZE_1F, mMotionEventDynamic.getSize(), DELTA);
+        assertEquals(X_PRECISION_3F, mMotionEventDynamic.getXPrecision(), DELTA);
+        assertEquals(Y_PRECISION_4F, mMotionEventDynamic.getYPrecision(), DELTA);
     }
 
+    @Test
+    public void testObtainFromPropertyArrays() {
+        PointerCoordsBuilder coordsBuilder0 =
+                withCoords(X_3F, Y_4F).withPressure(PRESSURE_1F).withSize(SIZE_1F).
+                        withTool(1.2f, 1.4f);
+        PointerCoordsBuilder coordsBuilder1 =
+                withCoords(X_3F + 1.0f, Y_4F - 2.0f).withPressure(PRESSURE_1F + 0.2f).
+                        withSize(SIZE_1F + 0.5f).withTouch(2.2f, 0.6f);
+
+        PointerPropertiesBuilder propertiesBuilder0 =
+                withProperties(0, MotionEvent.TOOL_TYPE_FINGER);
+        PointerPropertiesBuilder propertiesBuilder1 =
+                withProperties(1, MotionEvent.TOOL_TYPE_FINGER);
+
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_MOVE, 2,
+                new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() },
+                new PointerCoords[] { coordsBuilder0.build(), coordsBuilder1.build() },
+                META_STATE, 0, X_PRECISION_3F, Y_PRECISION_4F, DEVICE_ID_1, EDGE_FLAGS,
+                InputDevice.SOURCE_TOUCHSCREEN, 0);
+
+        // We expect to have data for two pointers
+        assertEquals(2, mMotionEventDynamic.getPointerCount());
+        assertEquals(0, mMotionEventDynamic.getPointerId(0));
+        assertEquals(1, mMotionEventDynamic.getPointerId(1));
+        assertEquals(0, mMotionEventDynamic.getFlags());
+        verifyCurrentPointerData(mMotionEventDynamic,
+                new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 },
+                new PointerCoordsBuilder[] { coordsBuilder0, coordsBuilder1 });
+    }
+
+    @Test
+    public void testObtainNoHistory() {
+        // Add two batch to one of our events
+        mMotionEvent2.addBatch(mEventTime + 10, X_3F + 5.0f, Y_4F + 5.0f, 0.5f, 0.5f, 0);
+        mMotionEvent2.addBatch(mEventTime + 20, X_3F + 10.0f, Y_4F + 15.0f, 2.0f, 3.0f, 0);
+        // The newly added batch should be the "new" values of the event
+        withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f).
+                verifyMatches(mMotionEvent2);
+        assertEquals(mEventTime + 20, mMotionEvent2.getEventTime());
+        // We should have history with 2 entries
+        assertEquals(2, mMotionEvent2.getHistorySize());
+        // The previous data should be history at index 1
+        withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f).
+                verifyMatchesHistorical(mMotionEvent2, 1);
+        assertEquals(mEventTime + 10, mMotionEvent2.getHistoricalEventTime(1));
+        // And the original data should be history at index 0
+        withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f).
+                verifyMatchesHistorical(mMotionEvent2, 0);
+        assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0));
+
+        assertEquals(2, mMotionEvent2.getHistorySize());
+
+        mMotionEventDynamic = MotionEvent.obtainNoHistory(mMotionEvent2);
+        // The newly obtained event should have the matching current content
+        withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f).
+                verifyMatches(mMotionEvent2);
+        // And no history
+        assertEquals(0, mMotionEventDynamic.getHistorySize());
+    }
+
+    @Test
     public void testAccessAction() {
         assertEquals(MotionEvent.ACTION_MOVE, mMotionEvent1.getAction());
 
@@ -150,11 +232,13 @@
         assertEquals(MotionEvent.ACTION_DOWN, mMotionEvent1.getAction());
     }
 
+    @Test
     public void testDescribeContents() {
         // make sure this method never throw any exception.
         mMotionEvent2.describeContents();
     }
 
+    @Test
     public void testAccessEdgeFlags() {
         assertEquals(EDGE_FLAGS, mMotionEvent2.getEdgeFlags());
 
@@ -163,6 +247,7 @@
         assertEquals(edgeFlags, mMotionEvent2.getEdgeFlags());
     }
 
+    @Test
     public void testWriteToParcel() {
         Parcel parcel = Parcel.obtain();
         mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
@@ -180,6 +265,7 @@
         assertEquals(mMotionEvent2.getDeviceId(), motionEvent.getDeviceId());
     }
 
+    @Test
     public void testReadFromParcelWithInvalidPointerCountSize() {
         Parcel parcel = Parcel.obtain();
         mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
@@ -197,6 +283,7 @@
         }
     }
 
+    @Test
     public void testReadFromParcelWithInvalidSampleSize() {
         Parcel parcel = Parcel.obtain();
         mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
@@ -214,11 +301,13 @@
         }
     }
 
+    @Test
     public void testToString() {
         // make sure this method never throw exception.
         mMotionEvent2.toString();
     }
 
+    @Test
     public void testOffsetLocation() {
         assertEquals(X_3F, mMotionEvent2.getX(), DELTA);
         assertEquals(Y_4F, mMotionEvent2.getY(), DELTA);
@@ -226,104 +315,233 @@
         float offsetX = 1.0f;
         float offsetY = 1.0f;
         mMotionEvent2.offsetLocation(offsetX, offsetY);
-        assertEquals(X_3F + offsetX, mMotionEvent2.getX(), DELTA);
-        assertEquals(Y_4F + offsetY, mMotionEvent2.getY(), DELTA);
+        withCoords(X_3F + offsetX, Y_4F + offsetY).withPressure(PRESSURE_1F).withSize(SIZE_1F).
+                verifyMatches(mMotionEvent2);
     }
 
+    @Test
     public void testSetLocation() {
         assertEquals(X_3F, mMotionEvent2.getX(), DELTA);
         assertEquals(Y_4F, mMotionEvent2.getY(), DELTA);
 
-        float newLocationX = 0.0f;
-        float newLocationY = 0.0f;
-        mMotionEvent2.setLocation(newLocationX, newLocationY);
-        assertEquals(newLocationX, mMotionEvent2.getX(), DELTA);
-        assertEquals(newLocationY, mMotionEvent2.getY(), DELTA);
+        mMotionEvent2.setLocation(0.0f, 0.0f);
+        withCoords(0.0f, 0.0f).withPressure(PRESSURE_1F).withSize(SIZE_1F).
+                verifyMatches(mMotionEvent2);
 
-        newLocationX = 2.0f;
-        newLocationY = 2.0f;
-        mMotionEvent2.setLocation(newLocationX, newLocationY);
-        assertEquals(newLocationX, mMotionEvent2.getX(), DELTA);
-        assertEquals(newLocationY, mMotionEvent2.getY(), DELTA);
+        mMotionEvent2.setLocation(2.0f, 2.0f);
+        withCoords(2.0f, 2.0f).withPressure(PRESSURE_1F).withSize(SIZE_1F).
+                verifyMatches(mMotionEvent2);
     }
 
-    public void testGetHistoricalX() {
-        float x = X_3F + 5.0f;
-        mMotionEvent2.addBatch(mEventTime, x, 5.0f, 1.0f, 0.0f, 0);
-        assertEquals(X_3F, mMotionEvent2.getHistoricalX(0), DELTA);
+    @Test
+    public void testGetHistoricalData() {
+        assertEquals(0, mMotionEvent2.getHistorySize());
 
-        mMotionEvent2.addBatch(mEventTime, X_3F + 10.0f, 10.0f, 0.0f, 1.0f, 0);
-        assertEquals(x, mMotionEvent2.getHistoricalX(1), DELTA);
-    }
-
-    public void testGetHistoricalY() {
-        float y = Y_4F + 5.0f;
-        mMotionEvent2.addBatch(mEventTime, 5.0f, y, 1.0f, 0.0f, 0);
-        assertEquals(Y_4F, mMotionEvent2.getHistoricalY(0), DELTA);
-
-        mMotionEvent2.addBatch(mEventTime, 15.0f, Y_4F + 15.0f, 0.0f, 1.0f, 0);
-        assertEquals(y, mMotionEvent2.getHistoricalY(1), DELTA);
-    }
-
-    public void testGetHistoricalSize() {
-        float size = 0.5f;
-        mMotionEvent2.addBatch(mEventTime, 5.0f, 5.0f, 1.0f, size, 0);
-        assertEquals(SIZE_1F, mMotionEvent2.getHistoricalSize(0), DELTA);
-
-        mMotionEvent2.addBatch(mEventTime, 15.0f, 15.0f, 1.0f, 0.0f, 0);
-        assertEquals(size, mMotionEvent2.getHistoricalSize(1), DELTA);
-    }
-
-    public void testGetHistoricalPressure() {
-        float pressure = 0.5f;
-        mMotionEvent2.addBatch(mEventTime, 5.0f, 5.0f, pressure, 0.0f, 0);
-        assertEquals(PRESSURE_1F, mMotionEvent2.getHistoricalPressure(0), DELTA);
-
-        mMotionEvent2.addBatch(mEventTime, 15.0f, 15.0f, 0.0f, 0.0f, 0);
-        assertEquals(pressure, mMotionEvent2.getHistoricalPressure(1), DELTA);
-    }
-
-    public void testGetHistoricalEventTime() {
-        long eventTime = mEventTime + 5l;
-        mMotionEvent2.addBatch(eventTime, 5.0f, 5.0f, 0.0f, 1.0f, 0);
+        mMotionEvent2.addBatch(mEventTime + 10, X_3F + 5.0f, Y_4F + 5.0f, 0.5f, 0.5f, 0);
+        // The newly added batch should be the "new" values of the event
+        withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f).
+                verifyMatches(mMotionEvent2);
+        assertEquals(mEventTime + 10, mMotionEvent2.getEventTime());
+        // We should have history with 1 entry
+        assertEquals(1, mMotionEvent2.getHistorySize());
+        // And the previous / original data should be history at index 0
+        assertEquals(1, mMotionEvent2.getHistorySize());
+        withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f).
+                verifyMatchesHistorical(mMotionEvent2, 0);
         assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0));
 
-        mMotionEvent2.addBatch(mEventTime + 10l, 15.0f, 15.0f, 1.0f, 0.0f, 0);
-        assertEquals(eventTime, mMotionEvent2.getHistoricalEventTime(1));
-    }
-
-    public void testAddBatch() {
-        long eventTime = SystemClock.uptimeMillis();
-        float x = 10.0f;
-        float y = 20.0f;
-        float pressure = 1.0f;
-        float size = 1.0f;
-
-        // get original attribute values.
-        long origEventTime = mMotionEvent2.getEventTime();
-        float origX = mMotionEvent2.getX();
-        float origY = mMotionEvent2.getY();
-        float origPressure = mMotionEvent2.getPressure();
-        float origSize = mMotionEvent2.getSize();
-
-        assertEquals(0, mMotionEvent2.getHistorySize());
-        mMotionEvent2.addBatch(eventTime, x, y, pressure, size, 0);
-        assertEquals(1, mMotionEvent2.getHistorySize());
-        assertEquals(origEventTime, mMotionEvent2.getHistoricalEventTime(0));
-        assertEquals(origX, mMotionEvent2.getHistoricalX(0), DELTA);
-        assertEquals(origY, mMotionEvent2.getHistoricalY(0), DELTA);
-        assertEquals(origPressure, mMotionEvent2.getHistoricalPressure(0), DELTA);
-        assertEquals(origSize, mMotionEvent2.getHistoricalSize(0), DELTA);
-
-        mMotionEvent2.addBatch(mEventTime, 6, 6, 0.1f, 0, 0);
+        // Add another update batch to our event
+        mMotionEvent2.addBatch(mEventTime + 20, X_3F + 10.0f, Y_4F + 15.0f, 2.0f, 3.0f, 0);
+        // The newly added batch should be the "new" values of the event
+        withCoords(X_3F + 10.0f, Y_4F + 15.0f).withPressure(2.0f).withSize(3.0f).
+                verifyMatches(mMotionEvent2);
+        assertEquals(mEventTime + 20, mMotionEvent2.getEventTime());
+        // We should have history with 2 entries
         assertEquals(2, mMotionEvent2.getHistorySize());
-        assertEquals(eventTime, mMotionEvent2.getHistoricalEventTime(1));
-        assertEquals(x, mMotionEvent2.getHistoricalX(1), DELTA);
-        assertEquals(y, mMotionEvent2.getHistoricalY(1), DELTA);
-        assertEquals(pressure, mMotionEvent2.getHistoricalPressure(1), DELTA);
-        assertEquals(size, mMotionEvent2.getHistoricalSize(1), DELTA);
+        // The previous data should be history at index 1
+        withCoords(X_3F + 5.0f, Y_4F + 5.0f).withPressure(0.5f).withSize(0.5f).
+                verifyMatchesHistorical(mMotionEvent2, 1);
+        assertEquals(mEventTime + 10, mMotionEvent2.getHistoricalEventTime(1));
+        // And the original data should be history at index 0
+        withCoords(X_3F, Y_4F).withPressure(1.0f).withSize(1.0f).
+                verifyMatchesHistorical(mMotionEvent2, 0);
+        assertEquals(mEventTime, mMotionEvent2.getHistoricalEventTime(0));
     }
 
+    private static void verifyCurrentPointerData(MotionEvent motionEvent,
+            PointerPropertiesBuilder[] pointerPropertiesBuilders,
+            PointerCoordsBuilder[] pointerCoordsBuilders) {
+        assertNotNull(motionEvent);
+        assertNotNull(pointerPropertiesBuilders);
+        assertNotNull(pointerCoordsBuilders);
+        final int pointerCount = motionEvent.getPointerCount();
+        assertEquals(pointerCount, pointerPropertiesBuilders.length);
+        assertEquals(pointerCount, pointerCoordsBuilders.length);
+
+        // Test that we have the expected data fetched via MotionEvent.getPointerCoords API
+        for (int i = 0; i < pointerCount; i++) {
+            pointerCoordsBuilders[i].verifyMatchesPointerCoords(motionEvent, i);
+        }
+
+        // Test that we have the expected data fetched via per-field MotionEvent getter APIs
+        for (int i = 0; i < pointerCount; i++) {
+            pointerCoordsBuilders[i].verifyMatches(motionEvent, i);
+        }
+
+        // Test that we have the expected data fetched via MotionEvent.getPointerProperties API
+        for (int i = 0; i < pointerCount; i++) {
+            pointerPropertiesBuilders[i].verifyMatchesPointerProperties(motionEvent, i);
+        }
+
+        // Test that we have the expected data fetched via per-field MotionEvent getter APIs
+        for (int i = 0; i < pointerCount; i++) {
+            pointerPropertiesBuilders[i].verifyMatches(motionEvent, i);
+        }
+    }
+
+    private static void verifyHistoricalPointerData(MotionEvent motionEvent,
+            PointerCoordsBuilder[] pointerCoordsBuilders, int pos) {
+        assertNotNull(motionEvent);
+        assertNotNull(pointerCoordsBuilders);
+        final int pointerCount = motionEvent.getPointerCount();
+        assertEquals(pointerCount, pointerCoordsBuilders.length);
+
+        // Test that we have the expected data fetched via MotionEvent.getHistoricalPointerCoords
+        // API
+        for (int i = 0; i < pointerCount; i++) {
+            pointerCoordsBuilders[i].verifyMatchesHistoricalPointerCoords(motionEvent, i, pos);
+        }
+
+        // Test that we have the expected data fetched via per-field MotionEvent getter APIs
+        for (int i = 0; i < pointerCount; i++) {
+            pointerCoordsBuilders[i].verifyMatchesHistorical(motionEvent, i, pos);
+        }
+    }
+
+    @Test
+    public void testGetCurrentDataWithTwoPointers() {
+        PointerCoordsBuilder coordsBuilder0 =
+                withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f);
+        PointerCoordsBuilder coordsBuilder1 =
+                withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTouch(2.2f, 0.6f);
+
+        PointerPropertiesBuilder propertiesBuilder0 =
+                withProperties(0, MotionEvent.TOOL_TYPE_FINGER);
+        PointerPropertiesBuilder propertiesBuilder1 =
+                withProperties(1, MotionEvent.TOOL_TYPE_FINGER);
+
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_MOVE, 2,
+                new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() },
+                new PointerCoords[] { coordsBuilder0.build(), coordsBuilder1.build() },
+                0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+
+        // We expect to have data for two pointers
+        assertEquals(2, mMotionEventDynamic.getPointerCount());
+        assertEquals(0, mMotionEventDynamic.getPointerId(0));
+        assertEquals(1, mMotionEventDynamic.getPointerId(1));
+        assertEquals(0, mMotionEventDynamic.getFlags());
+        verifyCurrentPointerData(mMotionEventDynamic,
+                new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 },
+                new PointerCoordsBuilder[] { coordsBuilder0, coordsBuilder1 });
+    }
+
+    @Test
+    public void testGetHistoricalDataWithTwoPointers() {
+        // PHASE 1 - construct the initial data for the event
+        PointerCoordsBuilder coordsBuilderInitial0 =
+                withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f).
+                        withTouch(0.7f, 0.6f).withOrientation(2.0f);
+        PointerCoordsBuilder coordsBuilderInitial1 =
+                withCoords(30.0f, 40.0f).withPressure(1.4f).withSize(3.0f).withTool(1.3f, 1.7f).
+                        withTouch(2.7f, 3.6f).withOrientation(1.0f);
+
+        PointerPropertiesBuilder propertiesBuilder0 =
+                withProperties(0, MotionEvent.TOOL_TYPE_FINGER);
+        PointerPropertiesBuilder propertiesBuilder1 =
+                withProperties(1, MotionEvent.TOOL_TYPE_FINGER);
+
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_MOVE, 2,
+                new PointerProperties[] { propertiesBuilder0.build(), propertiesBuilder1.build() },
+                new PointerCoords[] {
+                        coordsBuilderInitial0.build(), coordsBuilderInitial1.build() },
+                0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+
+        // We expect to have data for two pointers
+        assertEquals(2, mMotionEventDynamic.getPointerCount());
+        assertEquals(0, mMotionEventDynamic.getPointerId(0));
+        assertEquals(1, mMotionEventDynamic.getPointerId(1));
+        assertEquals(0, mMotionEventDynamic.getFlags());
+        verifyCurrentPointerData(mMotionEventDynamic,
+                new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 },
+                new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 });
+
+        // PHASE 2 - add a new batch of data to our event
+        PointerCoordsBuilder coordsBuilderNext0 =
+                withCoords(15.0f, 25.0f).withPressure(1.6f).withSize(2.2f).withTool(1.2f, 1.4f).
+                        withTouch(1.0f, 0.9f).withOrientation(2.2f);
+        PointerCoordsBuilder coordsBuilderNext1 =
+                withCoords(35.0f, 45.0f).withPressure(1.8f).withSize(3.2f).withTool(1.2f, 1.4f).
+                        withTouch(0.7f, 0.6f).withOrientation(2.9f);
+
+        mMotionEventDynamic.addBatch(mEventTime + 10,
+                new PointerCoords[] { coordsBuilderNext0.build(), coordsBuilderNext1.build() }, 0);
+        // We still expect to have data for two pointers
+        assertEquals(2, mMotionEventDynamic.getPointerCount());
+        assertEquals(0, mMotionEventDynamic.getPointerId(0));
+        assertEquals(1, mMotionEventDynamic.getPointerId(1));
+        assertEquals(0, mMotionEventDynamic.getFlags());
+
+        // The newly added batch should be the "new" values of the event
+        verifyCurrentPointerData(mMotionEventDynamic,
+                new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 },
+                new PointerCoordsBuilder[] { coordsBuilderNext0, coordsBuilderNext1 });
+        assertEquals(mEventTime + 10, mMotionEventDynamic.getEventTime());
+        // We should have history with 1 entry
+        assertEquals(1, mMotionEventDynamic.getHistorySize());
+        // And the previous / original data should be history at index 0
+        assertEquals(1, mMotionEventDynamic.getHistorySize());
+        verifyHistoricalPointerData(mMotionEventDynamic,
+                new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 },
+                0);
+
+        // PHASE 3 - add one more new batch of data to our event
+        PointerCoordsBuilder coordsBuilderLast0 =
+                withCoords(18.0f, 28.0f).withPressure(1.1f).withSize(2.9f).withTool(1.5f, 1.9f).
+                        withTouch(1.2f, 5.0f).withOrientation(3.2f);
+        PointerCoordsBuilder coordsBuilderLast1 =
+                withCoords(38.0f, 48.0f).withPressure(1.2f).withSize(2.5f).withTool(0.2f, 0.4f).
+                        withTouch(2.7f, 4.6f).withOrientation(0.2f);
+
+        mMotionEventDynamic.addBatch(mEventTime + 20,
+                new PointerCoords[] { coordsBuilderLast0.build(), coordsBuilderLast1.build() }, 0);
+        // We still expect to have data for two pointers
+        assertEquals(2, mMotionEventDynamic.getPointerCount());
+        assertEquals(0, mMotionEventDynamic.getPointerId(0));
+        assertEquals(1, mMotionEventDynamic.getPointerId(1));
+        assertEquals(0, mMotionEventDynamic.getFlags());
+
+        // The newly added batch should be the "new" values of the event
+        verifyCurrentPointerData(mMotionEventDynamic,
+                new PointerPropertiesBuilder[] { propertiesBuilder0, propertiesBuilder1 },
+                new PointerCoordsBuilder[] { coordsBuilderLast0, coordsBuilderLast1 });
+        assertEquals(mEventTime + 20, mMotionEventDynamic.getEventTime());
+        // We should have history with 2 entries
+        assertEquals(2, mMotionEventDynamic.getHistorySize());
+        // The previous data should be history at index 1
+        verifyHistoricalPointerData(mMotionEventDynamic,
+                new PointerCoordsBuilder[] { coordsBuilderNext0, coordsBuilderNext1 },
+                1);
+        assertEquals(mEventTime + 10, mMotionEventDynamic.getHistoricalEventTime(1));
+        // And the original data should be history at index 0
+        verifyHistoricalPointerData(mMotionEventDynamic,
+                new PointerCoordsBuilder[] { coordsBuilderInitial0, coordsBuilderInitial1 },
+                0);
+        assertEquals(mEventTime, mMotionEventDynamic.getHistoricalEventTime(0));
+    }
+
+    @Test
     public void testGetHistorySize() {
         long eventTime = SystemClock.uptimeMillis();
         float x = 10.0f;
@@ -339,6 +557,7 @@
         assertEquals(1, mMotionEvent2.getHistorySize());
     }
 
+    @Test
     public void testRecycle() {
         mMotionEvent2.setAction(MotionEvent.ACTION_MOVE);
         assertEquals(0, mMotionEvent2.getHistorySize());
@@ -346,24 +565,23 @@
         assertEquals(1, mMotionEvent2.getHistorySize());
 
         mMotionEvent2.recycle();
-        
+
         try {
             mMotionEvent2.recycle();
             fail("recycle() should throw an exception when the event has already been recycled.");
         } catch (RuntimeException ex) {
         }
-        
+
         mMotionEvent2 = null; // since it was recycled, don't try to recycle again in tear down
     }
 
+    @Test(expected=IllegalArgumentException.class)
     public void testTransformShouldThrowWhenMatrixIsNull() {
-        try {
-            mMotionEvent1.transform(null);
-            fail("transform() should throw an exception when matrix is null.");
-        } catch (IllegalArgumentException ex) {
-        }
+        // transform() should throw an exception when matrix is null
+        mMotionEvent1.transform(null);
     }
 
+    @Test
     public void testTransformShouldApplyMatrixToPointsAndPreserveRawPosition() {
         // Generate some points on a circle.
         // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
@@ -445,20 +663,22 @@
         }
     }
 
+    @Test
     public void testPointerCoordsDefaultConstructor() {
         PointerCoords coords = new PointerCoords();
 
-        assertEquals(0f, coords.x);
-        assertEquals(0f, coords.y);
-        assertEquals(0f, coords.pressure);
-        assertEquals(0f, coords.size);
-        assertEquals(0f, coords.touchMajor);
-        assertEquals(0f, coords.touchMinor);
-        assertEquals(0f, coords.toolMajor);
-        assertEquals(0f, coords.toolMinor);
-        assertEquals(0f, coords.orientation);
+        assertEquals(0f, coords.x, 0.0f);
+        assertEquals(0f, coords.y, 0.0f);
+        assertEquals(0f, coords.pressure, 0.0f);
+        assertEquals(0f, coords.size, 0.0f);
+        assertEquals(0f, coords.touchMajor, 0.0f);
+        assertEquals(0f, coords.touchMinor, 0.0f);
+        assertEquals(0f, coords.toolMajor, 0.0f);
+        assertEquals(0f, coords.toolMinor, 0.0f);
+        assertEquals(0f, coords.orientation, 0.0f);
     }
 
+    @Test
     public void testPointerCoordsCopyConstructor() {
         PointerCoords coords = new PointerCoords();
         coords.x = 1;
@@ -473,18 +693,19 @@
         coords.setAxisValue(MotionEvent.AXIS_GENERIC_1, 10);
 
         PointerCoords copy = new PointerCoords(coords);
-        assertEquals(1f, copy.x);
-        assertEquals(2f, copy.y);
-        assertEquals(3f, copy.pressure);
-        assertEquals(4f, copy.size);
-        assertEquals(5f, copy.touchMajor);
-        assertEquals(6f, copy.touchMinor);
-        assertEquals(7f, copy.toolMajor);
-        assertEquals(8f, copy.toolMinor);
-        assertEquals(9f, copy.orientation);
-        assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1));
+        assertEquals(1f, copy.x, 0.0f);
+        assertEquals(2f, copy.y, 0.0f);
+        assertEquals(3f, copy.pressure, 0.0f);
+        assertEquals(4f, copy.size, 0.0f);
+        assertEquals(5f, copy.touchMajor, 0.0f);
+        assertEquals(6f, copy.touchMinor, 0.0f);
+        assertEquals(7f, copy.toolMajor, 0.0f);
+        assertEquals(8f, copy.toolMinor, 0.0f);
+        assertEquals(9f, copy.orientation, 0.0f);
+        assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1), 0.0f);
     }
 
+    @Test
     public void testPointerCoordsCopyFrom() {
         PointerCoords coords = new PointerCoords();
         coords.x = 1;
@@ -500,18 +721,19 @@
 
         PointerCoords copy = new PointerCoords();
         copy.copyFrom(coords);
-        assertEquals(1f, copy.x);
-        assertEquals(2f, copy.y);
-        assertEquals(3f, copy.pressure);
-        assertEquals(4f, copy.size);
-        assertEquals(5f, copy.touchMajor);
-        assertEquals(6f, copy.touchMinor);
-        assertEquals(7f, copy.toolMajor);
-        assertEquals(8f, copy.toolMinor);
-        assertEquals(9f, copy.orientation);
-        assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1));
+        assertEquals(1f, copy.x, 0.0f);
+        assertEquals(2f, copy.y, 0.0f);
+        assertEquals(3f, copy.pressure, 0.0f);
+        assertEquals(4f, copy.size, 0.0f);
+        assertEquals(5f, copy.touchMajor, 0.0f);
+        assertEquals(6f, copy.touchMinor, 0.0f);
+        assertEquals(7f, copy.toolMajor, 0.0f);
+        assertEquals(8f, copy.toolMinor, 0.0f);
+        assertEquals(9f, copy.orientation, 0.0f);
+        assertEquals(10f, coords.getAxisValue(MotionEvent.AXIS_GENERIC_1), 0.0f);
     }
 
+    @Test
     public void testPointerPropertiesDefaultConstructor() {
         PointerProperties properties = new PointerProperties();
 
@@ -519,6 +741,7 @@
         assertEquals(MotionEvent.TOOL_TYPE_UNKNOWN, properties.toolType);
     }
 
+    @Test
     public void testPointerPropertiesCopyConstructor() {
         PointerProperties properties = new PointerProperties();
         properties.id = 1;
@@ -529,6 +752,7 @@
         assertEquals(MotionEvent.TOOL_TYPE_MOUSE, copy.toolType);
     }
 
+    @Test
     public void testPointerPropertiesCopyFrom() {
         PointerProperties properties = new PointerProperties();
         properties.id = 1;
@@ -539,4 +763,152 @@
         assertEquals(1, copy.id);
         assertEquals(MotionEvent.TOOL_TYPE_MOUSE, copy.toolType);
     }
+
+    @Test
+    public void testActionToString() {
+        final int[] actions = {
+                MotionEvent.ACTION_DOWN,
+                MotionEvent.ACTION_UP,
+                MotionEvent.ACTION_MOVE,
+                MotionEvent.ACTION_CANCEL,
+                MotionEvent.ACTION_OUTSIDE,
+                MotionEvent.ACTION_HOVER_MOVE,
+                MotionEvent.ACTION_SCROLL,
+                MotionEvent.ACTION_HOVER_ENTER,
+                MotionEvent.ACTION_HOVER_EXIT,
+                MotionEvent.ACTION_BUTTON_PRESS,
+                MotionEvent.ACTION_BUTTON_RELEASE
+        };
+
+        // There is no hard guarantee on the actual return result on any specific action
+        // from MotionEvent.actionToString. Verify that we are not crashing on those calls
+        // and that the return result on each is not empty
+        for (int i = 0; i < actions.length; i++) {
+            assertFalse(TextUtils.isEmpty(MotionEvent.actionToString(actions[i])));
+        }
+
+        final int[] pointerActions = {
+                MotionEvent.ACTION_POINTER_UP,
+                MotionEvent.ACTION_POINTER_DOWN
+        };
+
+        for (int i = 0; i < pointerActions.length; i++) {
+            for (int pointer = 0; pointer < 5; pointer++) {
+                int pointerAction =
+                        pointerActions[i] | pointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                assertFalse(TextUtils.isEmpty(MotionEvent.actionToString(pointerAction)));
+            }
+        }
+    }
+
+    @Test
+    public void testAxisFromToString() {
+        final int[] axes = {
+                MotionEvent.AXIS_X,
+                MotionEvent.AXIS_Y,
+                MotionEvent.AXIS_PRESSURE,
+                MotionEvent.AXIS_SIZE,
+                MotionEvent.AXIS_TOUCH_MAJOR,
+                MotionEvent.AXIS_TOUCH_MINOR,
+                MotionEvent.AXIS_TOOL_MAJOR,
+                MotionEvent.AXIS_TOOL_MINOR,
+                MotionEvent.AXIS_ORIENTATION,
+                MotionEvent.AXIS_VSCROLL,
+                MotionEvent.AXIS_HSCROLL,
+                MotionEvent.AXIS_Z,
+                MotionEvent.AXIS_RX,
+                MotionEvent.AXIS_RY,
+                MotionEvent.AXIS_RZ,
+                MotionEvent.AXIS_HAT_X,
+                MotionEvent.AXIS_HAT_Y,
+                MotionEvent.AXIS_LTRIGGER,
+                MotionEvent.AXIS_RTRIGGER,
+                MotionEvent.AXIS_THROTTLE,
+                MotionEvent.AXIS_RUDDER,
+                MotionEvent.AXIS_WHEEL,
+                MotionEvent.AXIS_GAS,
+                MotionEvent.AXIS_BRAKE,
+                MotionEvent.AXIS_DISTANCE,
+                MotionEvent.AXIS_TILT,
+                MotionEvent.AXIS_SCROLL,
+                MotionEvent.AXIS_RELATIVE_X,
+                MotionEvent.AXIS_RELATIVE_Y,
+                MotionEvent.AXIS_GENERIC_1,
+                MotionEvent.AXIS_GENERIC_2,
+                MotionEvent.AXIS_GENERIC_3,
+                MotionEvent.AXIS_GENERIC_4,
+                MotionEvent.AXIS_GENERIC_5,
+                MotionEvent.AXIS_GENERIC_6,
+                MotionEvent.AXIS_GENERIC_7,
+                MotionEvent.AXIS_GENERIC_8,
+                MotionEvent.AXIS_GENERIC_9,
+                MotionEvent.AXIS_GENERIC_10,
+                MotionEvent.AXIS_GENERIC_11,
+                MotionEvent.AXIS_GENERIC_12,
+                MotionEvent.AXIS_GENERIC_13,
+                MotionEvent.AXIS_GENERIC_14,
+                MotionEvent.AXIS_GENERIC_15,
+                MotionEvent.AXIS_GENERIC_16
+        };
+
+        // There is no hard guarantee on the actual return result on any specific axis
+        // from MotionEvent.axisToString. Verify that we are not crashing on those calls
+        // and that the return result on each is not empty. However, we do expect the two-way
+        // call chain of to/from to get us back to the original integer value.
+        for (int i = 0; i < axes.length; i++) {
+            String axisToString = MotionEvent.axisToString(axes[i]);
+            assertFalse(TextUtils.isEmpty(axisToString));
+            assertEquals(axes[i], MotionEvent.axisFromString(axisToString));
+        }
+    }
+
+    @Test
+    public void testGetActionButton() {
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_BUTTON_PRESS, X_3F, Y_4F, 0);
+        mMotionEventDynamic.setActionButton(MotionEvent.BUTTON_STYLUS_PRIMARY);
+        assertEquals(MotionEvent.BUTTON_STYLUS_PRIMARY, mMotionEventDynamic.getActionButton());
+        mMotionEventDynamic.recycle();
+
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_BUTTON_PRESS, X_3F, Y_4F, 0);
+        mMotionEventDynamic.setActionButton(MotionEvent.BUTTON_SECONDARY);
+        assertEquals(MotionEvent.BUTTON_SECONDARY, mMotionEventDynamic.getActionButton());
+    }
+
+    @Test
+    public void testIsButtonPressed() {
+        mMotionEventDynamic = MotionEvent.obtain(mDownTime, mEventTime,
+                MotionEvent.ACTION_DOWN, X_3F, Y_4F, 0);
+        mMotionEventDynamic.setSource(InputDevice.SOURCE_MOUSE);
+
+        mMotionEventDynamic.setButtonState(
+                MotionEvent.BUTTON_PRIMARY | MotionEvent.BUTTON_STYLUS_PRIMARY);
+        assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+        assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD));
+
+        mMotionEventDynamic.setButtonState(MotionEvent.BUTTON_PRIMARY);
+        assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD));
+
+        mMotionEventDynamic.setButtonState(
+                MotionEvent.BUTTON_FORWARD | MotionEvent.BUTTON_TERTIARY);
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_SECONDARY));
+        assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+        assertFalse(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_BACK));
+        assertTrue(mMotionEventDynamic.isButtonPressed(MotionEvent.BUTTON_FORWARD));
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/MotionEventUtils.java b/tests/tests/view/src/android/view/cts/MotionEventUtils.java
new file mode 100644
index 0000000..74291c7
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/MotionEventUtils.java
@@ -0,0 +1,393 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+public class MotionEventUtils {
+    private static final float DELTA = 0.01f;
+
+    private MotionEventUtils() {
+    }
+
+    public static PointerCoordsBuilder withCoords(float x, float y) {
+        final PointerCoordsBuilder builder = new PointerCoordsBuilder();
+        builder.x = x;
+        builder.y = y;
+        return builder;
+    }
+
+    public static PointerPropertiesBuilder withProperties(int id, int toolType) {
+        final PointerPropertiesBuilder builder = new PointerPropertiesBuilder();
+        builder.id = id;
+        builder.toolType = toolType;
+        return builder;
+    }
+
+    public static class PointerPropertiesBuilder {
+        private int id;
+        private int toolType;
+
+        public PointerProperties build() {
+            final PointerProperties pointerProperties =
+                    new PointerProperties();
+            pointerProperties.id = id;
+            pointerProperties.toolType = toolType;
+            return pointerProperties;
+        }
+
+        public void verifyMatches(MotionEvent that, int pointerIndex) {
+            assertEquals("Pointer ID should be the same",
+                    that.getPointerId(pointerIndex), this.id);
+            assertEquals("Tool type should be the same",
+                    that.getToolType(pointerIndex), this.toolType);
+        }
+
+        public void verifyMatchesPointerProperties(PointerProperties that) {
+            assertEquals("Pointer ID should be the same", that.id, this.id);
+            assertEquals("Tool type should be the same", that.toolType, this.toolType);
+        }
+
+        public void verifyMatchesPointerProperties(MotionEvent motionEvent, int pointerIndex) {
+            final PointerProperties that = new PointerProperties();
+            motionEvent.getPointerProperties(pointerIndex, that);
+
+            verifyMatchesPointerProperties(that);
+        }
+    }
+
+    public static class PointerCoordsBuilder {
+        private float x;
+        private float y;
+        private float pressure = 1.0f;
+        private float size = 1.0f;
+        private float touchMajor;
+        private float touchMinor;
+        private float toolMajor;
+        private float toolMinor;
+        private float orientation;
+
+        public PointerCoordsBuilder withPressure(float pressure) {
+            this.pressure = pressure;
+            return this;
+        }
+
+        public PointerCoordsBuilder withSize(float size) {
+            this.size = size;
+            return this;
+        }
+
+        public PointerCoordsBuilder withTouch(float touchMajor, float touchMinor) {
+            this.touchMajor = touchMajor;
+            this.touchMinor = touchMinor;
+            return this;
+        }
+
+        public PointerCoordsBuilder withTool(float toolMajor, float toolMinor) {
+            this.toolMajor = toolMajor;
+            this.toolMinor = toolMinor;
+            return this;
+        }
+
+        public PointerCoordsBuilder withOrientation(float orientation) {
+            this.orientation = orientation;
+            return this;
+        }
+
+        public PointerCoords build() {
+            final PointerCoords pointerCoords = new PointerCoords();
+            pointerCoords.x = x;
+            pointerCoords.y = y;
+            pointerCoords.pressure = pressure;
+            pointerCoords.size = size;
+            pointerCoords.touchMajor = touchMajor;
+            pointerCoords.touchMinor = touchMinor;
+            pointerCoords.toolMajor = toolMajor;
+            pointerCoords.toolMinor = toolMinor;
+            pointerCoords.orientation = orientation;
+            return pointerCoords;
+        }
+
+        public void verifyMatches(MotionEvent that) {
+            assertEquals("X coordinates should be the same", that.getX(), this.x, DELTA);
+            assertEquals("X coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_X), this.x, DELTA);
+
+            assertEquals("Y coordinates should be the same", that.getY(), this.y, DELTA);
+            assertEquals("Y coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_Y), this.y, DELTA);
+
+            assertEquals("Pressure should be the same", that.getPressure(), this.pressure, DELTA);
+            assertEquals("Pressure should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_PRESSURE), this.pressure, DELTA);
+
+            assertEquals("Size should be the same", that.getSize(), this.size, DELTA);
+            assertEquals("Size should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_SIZE), this.size, DELTA);
+
+            assertEquals("Touch major should be the same",
+                    that.getTouchMajor(), this.touchMajor,DELTA);
+            assertEquals("Touch major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MAJOR), this.touchMajor, DELTA);
+
+            assertEquals("Touch minor should be the same",
+                    that.getTouchMinor(), this.touchMinor, DELTA);
+            assertEquals("Touch minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MINOR), this.touchMinor, DELTA);
+
+            assertEquals("Tool major should be the same",
+                    that.getToolMajor(), this.toolMajor, DELTA);
+            assertEquals("Tool major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MAJOR), this.toolMajor, DELTA);
+
+            assertEquals("Tool minor should be the same",
+                    that.getToolMinor(), this.toolMinor, DELTA);
+            assertEquals("Tool minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MINOR), this.toolMinor, DELTA);
+
+            assertEquals("Orientation should be the same",
+                    that.getOrientation(), this.orientation, DELTA);
+            assertEquals("Orientation should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_ORIENTATION), this.orientation, DELTA);
+        }
+
+        public void verifyMatches(MotionEvent that, int pointerIndex) {
+            assertEquals("X coordinates should be the same",
+                    that.getX(pointerIndex), this.x, DELTA);
+            assertEquals("X coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_X, pointerIndex), this.x, DELTA);
+
+            assertEquals("Y coordinates should be the same",
+                    that.getY(pointerIndex), this.y, DELTA);
+            assertEquals("Y coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_Y, pointerIndex), this.y, DELTA);
+
+            assertEquals("Pressure should be the same",
+                    that.getPressure(pointerIndex), this.pressure, DELTA);
+            assertEquals("Pressure should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_PRESSURE, pointerIndex), this.pressure,
+                        DELTA);
+
+            assertEquals("Size should be the same",
+                    that.getSize(pointerIndex), this.size, DELTA);
+            assertEquals("Size should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_SIZE, pointerIndex), this.size, DELTA);
+
+            assertEquals("Touch major should be the same",
+                    that.getTouchMajor(pointerIndex), this.touchMajor,DELTA);
+            assertEquals("Touch major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MAJOR, pointerIndex), this.touchMajor,
+                        DELTA);
+
+            assertEquals("Touch minor should be the same",
+                    that.getTouchMinor(pointerIndex), this.touchMinor, DELTA);
+            assertEquals("Touch minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MINOR, pointerIndex), this.touchMinor,
+                        DELTA);
+
+            assertEquals("Tool major should be the same",
+                    that.getToolMajor(pointerIndex), this.toolMajor, DELTA);
+            assertEquals("Tool major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MAJOR, pointerIndex), this.toolMajor,
+                        DELTA);
+
+            assertEquals("Tool minor should be the same",
+                    that.getToolMinor(pointerIndex), this.toolMinor, DELTA);
+            assertEquals("Tool minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MINOR, pointerIndex), this.toolMinor,
+                        DELTA);
+
+            assertEquals("Orientation should be the same",
+                    that.getOrientation(pointerIndex), this.orientation, DELTA);
+            assertEquals("Orientation should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_ORIENTATION, pointerIndex), this.orientation,
+                        DELTA);
+        }
+
+        public void verifyMatchesHistorical(MotionEvent that, int position) {
+            assertEquals("X coordinates should be the same",
+                    that.getHistoricalX(position), this.x, DELTA);
+            assertEquals("X coordinates should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_X, position), this.x, DELTA);
+
+            assertEquals("Y coordinates should be the same",
+                    that.getHistoricalY(position), this.y, DELTA);
+            assertEquals("Y coordinates should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_Y, position), this.y, DELTA);
+
+            assertEquals("Pressure should be the same",
+                    that.getHistoricalPressure(position), this.pressure, DELTA);
+            assertEquals("Pressure should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_PRESSURE, position), this.pressure,
+                    DELTA);
+
+            assertEquals("Size should be the same",
+                    that.getHistoricalSize(position), this.size, DELTA);
+            assertEquals("Size should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_SIZE, position), this.size, DELTA);
+
+            assertEquals("Touch major should be the same",
+                    that.getHistoricalTouchMajor(position), this.touchMajor,DELTA);
+            assertEquals("Touch major should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOUCH_MAJOR, position),
+                    this.touchMajor, DELTA);
+
+            assertEquals("Touch minor should be the same",
+                    that.getHistoricalTouchMinor(position), this.touchMinor, DELTA);
+            assertEquals("Touch minor should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOUCH_MINOR, position),
+                    this.touchMinor, DELTA);
+
+            assertEquals("Tool major should be the same",
+                    that.getHistoricalToolMajor(position), this.toolMajor, DELTA);
+            assertEquals("Tool major should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOOL_MAJOR, position),
+                    this.toolMajor, DELTA);
+
+            assertEquals("Tool minor should be the same",
+                    that.getHistoricalToolMinor(position), this.toolMinor, DELTA);
+            assertEquals("Tool minor should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOOL_MINOR, position),
+                    this.toolMinor, DELTA);
+
+            assertEquals("Orientation should be the same",
+                    that.getHistoricalOrientation(position), this.orientation, DELTA);
+            assertEquals("Orientation should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_ORIENTATION, position),
+                    this.orientation, DELTA);
+        }
+
+        public void verifyMatchesHistorical(MotionEvent that, int pointerIndex, int position) {
+            assertEquals("X coordinates should be the same",
+                    that.getHistoricalX(pointerIndex, position), this.x, DELTA);
+            assertEquals("X coordinates should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_X, pointerIndex, position),
+                    this.x, DELTA);
+
+            assertEquals("Y coordinates should be the same",
+                    that.getHistoricalY(pointerIndex, position), this.y, DELTA);
+            assertEquals("Y coordinates should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_Y, pointerIndex, position),
+                    this.y, DELTA);
+
+            assertEquals("Pressure should be the same",
+                    that.getHistoricalPressure(pointerIndex, position), this.pressure, DELTA);
+            assertEquals("Pressure should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_PRESSURE, pointerIndex, position),
+                    this.pressure, DELTA);
+
+            assertEquals("Size should be the same",
+                    that.getHistoricalSize(pointerIndex, position), this.size, DELTA);
+            assertEquals("Size should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_SIZE, pointerIndex, position),
+                    this.size, DELTA);
+
+            assertEquals("Touch major should be the same",
+                    that.getHistoricalTouchMajor(pointerIndex, position), this.touchMajor, DELTA);
+            assertEquals("Touch major should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOUCH_MAJOR,
+                            pointerIndex, position),
+                    this.touchMajor, DELTA);
+
+            assertEquals("Touch minor should be the same",
+                    that.getHistoricalTouchMinor(pointerIndex, position), this.touchMinor, DELTA);
+            assertEquals("Touch minor should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOUCH_MINOR,
+                            pointerIndex, position),
+                    this.touchMinor, DELTA);
+
+            assertEquals("Tool major should be the same",
+                    that.getHistoricalToolMajor(pointerIndex, position), this.toolMajor, DELTA);
+            assertEquals("Tool major should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOOL_MAJOR,
+                            pointerIndex, position),
+                    this.toolMajor, DELTA);
+
+            assertEquals("Tool minor should be the same",
+                    that.getHistoricalToolMinor(pointerIndex, position), this.toolMinor, DELTA);
+            assertEquals("Tool minor should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_TOOL_MINOR,
+                            pointerIndex, position),
+                    this.toolMinor, DELTA);
+
+            assertEquals("Orientation should be the same",
+                    that.getHistoricalOrientation(pointerIndex, position), this.orientation, DELTA);
+            assertEquals("Orientation should be the same",
+                    that.getHistoricalAxisValue(MotionEvent.AXIS_ORIENTATION,
+                            pointerIndex, position),
+                    this.orientation, DELTA);
+        }
+
+        public void verifyMatchesPointerCoords(PointerCoords that) {
+            assertEquals("X coordinates should be the same", that.x, this.x, DELTA);
+            assertEquals("X coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_X), this.x, DELTA);
+
+            assertEquals("Y coordinates should be the same", that.y, this.y, DELTA);
+            assertEquals("Y coordinates should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_Y), this.y, DELTA);
+
+            assertEquals("Pressure should be the same", that.pressure, this.pressure, DELTA);
+            assertEquals("Pressure should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_PRESSURE), this.pressure, DELTA);
+
+            assertEquals("Size should be the same", that.size, this.size, DELTA);
+            assertEquals("Size should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_SIZE), this.size, DELTA);
+
+            assertEquals("Touch major should be the same", that.touchMajor, this.touchMajor, DELTA);
+            assertEquals("Touch major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MAJOR), this.touchMajor, DELTA);
+
+            assertEquals("Touch minor should be the same", that.touchMinor, this.touchMinor, DELTA);
+            assertEquals("Touch minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOUCH_MINOR), this.touchMinor, DELTA);
+
+            assertEquals("Tool major should be the same", that.toolMajor, this.toolMajor, DELTA);
+            assertEquals("Tool major should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MAJOR), this.toolMajor, DELTA);
+
+            assertEquals("Tool minor should be the same", that.toolMinor, this.toolMinor, DELTA);
+            assertEquals("Tool minor should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_TOOL_MINOR), this.toolMinor, DELTA);
+
+            assertEquals("Orientation should be the same",
+                    that.orientation, this.orientation, DELTA);
+            assertEquals("Orientation should be the same",
+                    that.getAxisValue(MotionEvent.AXIS_ORIENTATION), this.orientation, DELTA);
+        }
+
+        public void verifyMatchesPointerCoords(MotionEvent motionEvent, int pointerIndex) {
+            final PointerCoords that = new PointerCoords();
+            motionEvent.getPointerCoords(pointerIndex, that);
+
+            verifyMatchesPointerCoords(that);
+        }
+
+        public void verifyMatchesHistoricalPointerCoords(MotionEvent motionEvent, int pointerIndex,
+                int pos) {
+            final PointerCoords that = new PointerCoords();
+            motionEvent.getHistoricalPointerCoords(pointerIndex, pos, that);
+
+            verifyMatchesPointerCoords(that);
+        }
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/MotionEvent_PointerCoordsTest.java b/tests/tests/view/src/android/view/cts/MotionEvent_PointerCoordsTest.java
new file mode 100644
index 0000000..1f3acbb
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/MotionEvent_PointerCoordsTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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 static android.view.cts.MotionEventUtils.withCoords;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.cts.MotionEventUtils.PointerCoordsBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link MotionEvent.PointerCoords}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MotionEvent_PointerCoordsTest {
+    private PointerCoordsBuilder mBuilder;
+    private MotionEvent.PointerCoords mPointerCoords;
+
+    @Before
+    public void setup() {
+        mBuilder = withCoords(10.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f).
+                withTouch(3.0f, 2.4f);
+        mPointerCoords = mBuilder.build();
+    }
+
+    @Test
+    public void testCreation() {
+        mBuilder.verifyMatchesPointerCoords(mPointerCoords);
+    }
+
+    @Test
+    public void testAxesModifications() {
+        // Change value of X
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_X, 15.0f);
+        withCoords(15.0f, 20.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of Y
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_Y, 25.0f);
+        withCoords(15.0f, 25.0f).withPressure(1.2f).withSize(2.0f).withTool(1.2f, 1.4f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of pressure
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_PRESSURE, 2.2f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(2.0f).withTool(1.2f, 1.4f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of size
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_SIZE, 10.0f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(10.0f).withTool(1.2f, 1.4f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of tool major
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_TOOL_MAJOR, 7.0f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(10.0f).withTool(7.0f, 1.4f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of tool minor
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_TOOL_MINOR, 2.0f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(10.0f).withTool(7.0f, 2.0f).
+                withTouch(3.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of tool major
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_TOUCH_MAJOR, 5.0f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(10.0f).withTool(7.0f, 2.0f).
+                withTouch(5.0f, 2.4f).verifyMatchesPointerCoords(mPointerCoords);
+
+        // Change value of tool minor
+        mPointerCoords.setAxisValue(MotionEvent.AXIS_TOUCH_MINOR, 2.1f);
+        withCoords(15.0f, 25.0f).withPressure(2.2f).withSize(10.0f).withTool(7.0f, 2.0f).
+                withTouch(5.0f, 2.1f).verifyMatchesPointerCoords(mPointerCoords);
+    }
+
+    @Test
+    public void testCopyFrom() {
+        final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+        pointerCoords.copyFrom(mPointerCoords);
+        mBuilder.verifyMatchesPointerCoords(pointerCoords);
+    }
+
+    @Test
+    public void testClear() {
+        mPointerCoords.clear();
+        withCoords(0.0f, 0.0f).withPressure(0.0f).withSize(0.0f).withTool(0.0f, 0.0f).
+                withTouch(0.0f, 0.0f).verifyMatchesPointerCoords(mPointerCoords);
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/MotionEvent_PointerPropertiesTest.java b/tests/tests/view/src/android/view/cts/MotionEvent_PointerPropertiesTest.java
new file mode 100644
index 0000000..ac05c1c
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/MotionEvent_PointerPropertiesTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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 static android.view.cts.MotionEventUtils.withProperties;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link MotionEvent.PointerProperties}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MotionEvent_PointerPropertiesTest {
+    private MotionEventUtils.PointerPropertiesBuilder mBuilder;
+    private MotionEvent.PointerProperties mPointerProperties;
+
+    @Before
+    public void setup() {
+        mBuilder = withProperties(3, MotionEvent.TOOL_TYPE_MOUSE);
+        mPointerProperties = mBuilder.build();
+    }
+
+    @Test
+    public void testCreation() {
+        mBuilder.verifyMatchesPointerProperties(mPointerProperties);
+    }
+
+    @Test
+    public void testCopyFrom() {
+        final MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+        pointerProperties.copyFrom(mPointerProperties);
+        mBuilder.verifyMatchesPointerProperties(pointerProperties);
+    }
+
+    @Test
+    public void testClear() {
+        mPointerProperties.clear();
+        withProperties(MotionEvent.INVALID_POINTER_ID, MotionEvent.TOOL_TYPE_UNKNOWN).
+                verifyMatchesPointerProperties(mPointerProperties);
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/MyScrollView.java b/tests/tests/view/src/android/view/cts/MyScrollView.java
deleted file mode 100644
index 3701ab0..0000000
--- a/tests/tests/view/src/android/view/cts/MyScrollView.java
+++ /dev/null
@@ -1,69 +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.view.cts;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ScrollView;
-
-public class MyScrollView extends ScrollView {
-    public MyScrollView(Context context) {
-        super(context);
-    }
-
-    public MyScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
-        return super.computeScrollDeltaToGetChildRectOnScreen(rect);
-    }
-
-    @Override
-    protected int computeVerticalScrollRange() {
-        return super.computeVerticalScrollRange();
-    }
-
-    @Override
-    protected float getBottomFadingEdgeStrength() {
-        return super.getBottomFadingEdgeStrength();
-    }
-
-    @Override
-    protected float getTopFadingEdgeStrength() {
-        return super.getTopFadingEdgeStrength();
-    }
-
-    @Override
-    protected void measureChild(View c, int pWidthMeasureSpec, int pHeightMeasureSpec) {
-        super.measureChild(c, pWidthMeasureSpec, pHeightMeasureSpec);
-    }
-
-    @Override
-    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
-            int parentHeightMeasureSpec, int heightUsed) {
-        super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
-                parentHeightMeasureSpec, heightUsed);
-    }
-}
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/OrientationEventListenerTest.java b/tests/tests/view/src/android/view/cts/OrientationEventListenerTest.java
index f5062ff..c163440 100644
--- a/tests/tests/view/src/android/view/cts/OrientationEventListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/OrientationEventListenerTest.java
@@ -16,44 +16,63 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.OrientationEventListener;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link OrientationEventListener}.
  */
-public class OrientationEventListenerTest extends AndroidTestCase {
-    public void testConstructor() {
-        new MockOrientationEventListener(mContext);
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class OrientationEventListenerTest {
+    private Context mContext;
 
-        new MockOrientationEventListener(mContext, SensorManager.SENSOR_DELAY_UI);
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
+    public void testConstructor() {
+        new MyOrientationEventListener(mContext);
+
+        new MyOrientationEventListener(mContext, SensorManager.SENSOR_DELAY_UI);
+    }
+
+    @Test
     public void testEnableAndDisable() {
-        MockOrientationEventListener listener = new MockOrientationEventListener(mContext);
+        MyOrientationEventListener listener = new MyOrientationEventListener(mContext);
         listener.enable();
         listener.disable();
     }
 
+    @Test
     public void testCanDetectOrientation() {
         SensorManager sm = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
         // Orientation can only be detected if there is an accelerometer
         boolean hasSensor = (sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null);
-        
-        MockOrientationEventListener listener = new MockOrientationEventListener(mContext);
+
+        MyOrientationEventListener listener = new MyOrientationEventListener(mContext);
         assertEquals(hasSensor, listener.canDetectOrientation());
     }
 
-    private static class MockOrientationEventListener extends OrientationEventListener {
-        public MockOrientationEventListener(Context context) {
+    private static class MyOrientationEventListener extends OrientationEventListener {
+        public MyOrientationEventListener(Context context) {
             super(context);
         }
 
-        public MockOrientationEventListener(Context context, int rate) {
+        public MyOrientationEventListener(Context context, int rate) {
             super(context, rate);
         }
 
diff --git a/tests/tests/view/src/android/view/cts/OrientationListenerTest.java b/tests/tests/view/src/android/view/cts/OrientationListenerTest.java
index 114cf5f..696f034 100644
--- a/tests/tests/view/src/android/view/cts/OrientationListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/OrientationListenerTest.java
@@ -16,30 +16,38 @@
 
 package android.view.cts;
 
-
 import android.content.Context;
 import android.hardware.SensorManager;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.OrientationListener;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link OrientationListener}.
  */
-public class OrientationListenerTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class OrientationListenerTest {
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
     public void testConstructor() {
         new MockOrientationListener(mContext);
 
         new MockOrientationListener(mContext, SensorManager.SENSOR_DELAY_UI);
     }
 
+    @Test
     public void testRegisterationOfOrientationListener() {
         // these methods are called to assure that no exception is thrown
         MockOrientationListener listener = new MockOrientationListener(mContext);
@@ -47,6 +55,7 @@
         listener.enable();
     }
 
+    @Test
     public void testOnAccuracyChanged() {
         // this method is called to assure that no exception is thrown
         new MockOrientationListener(mContext).onAccuracyChanged(SensorManager.SENSOR_ACCELEROMETER,
@@ -56,6 +65,7 @@
                 SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM);
     }
 
+    @Test
     public void testOnSensorChanged() {
         // this method is called to assure that no exception is thrown
         MockOrientationListener listener = new MockOrientationListener(mContext);
@@ -69,11 +79,11 @@
         mockData[SensorManager.RAW_DATA_X] = 4.0f;
         mockData[SensorManager.RAW_DATA_Y] = 4.0f;
         mockData[SensorManager.RAW_DATA_Z] = 5.0f * 2.0f;
-        listener.reset();
         new MockOrientationListener(mContext).onSensorChanged(SensorManager.SENSOR_MAGNETIC_FIELD,
                 mockData);
     }
 
+    @Test
     public void testOnOrientationChanged() {
         MockOrientationListener listener = new MockOrientationListener(mContext);
         listener.enable();
@@ -81,16 +91,6 @@
     }
 
     private class MockOrientationListener extends OrientationListener {
-        private boolean mHasCalledOnOrientationChanged;
-
-        public boolean hasCalledOnOrientationChanged() {
-            return mHasCalledOnOrientationChanged;
-        }
-
-        public void reset() {
-            mHasCalledOnOrientationChanged = false;
-        }
-
         public MockOrientationListener(Context context) {
             super(context);
         }
@@ -101,7 +101,6 @@
 
         @Override
         public void onOrientationChanged(int orientation) {
-            mHasCalledOnOrientationChanged = true;
         }
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/PanicPressBackActivity.java b/tests/tests/view/src/android/view/cts/PanicPressBackActivity.java
new file mode 100644
index 0000000..bb52491
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PanicPressBackActivity.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.view.cts;
+
+import android.app.Activity;
+
+import java.util.concurrent.CountDownLatch;
+
+public class PanicPressBackActivity extends Activity {
+
+    private boolean mWasPaused;
+
+    public final CountDownLatch mWaitForPanicBackLatch = new CountDownLatch(1);
+
+    @Override
+    public void onBackPressed() {
+        // Prevent back press from exiting app
+    }
+
+    @Override
+    public void onPause() {
+        mWaitForPanicBackLatch.countDown();
+        super.onPause();
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/PanicPressBackTest.java b/tests/tests/view/src/android/view/cts/PanicPressBackTest.java
new file mode 100644
index 0000000..8a0bf31
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PanicPressBackTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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 static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+import android.app.UiAutomation;
+import android.content.pm.PackageManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class PanicPressBackTest {
+    static final String TAG = "PanicPressBackTest";
+
+    @Rule
+    public ActivityTestRule<PanicPressBackActivity> mActivityRule =
+            new ActivityTestRule<>(PanicPressBackActivity.class);
+
+    private static final int PANIC_PRESS_COUNT = 4;
+    private PanicPressBackActivity mActivity;
+
+    @Before
+    public void setUp() {
+        mActivity = mActivityRule.getActivity();
+    }
+
+    /**
+     * Tests to ensure that the foregrounded app does not handle back button panic press on
+     * non-watch devices
+     */
+    @Test
+    public void testNonWatchBackPanicDoesNothing() throws Exception {
+        // Only run for non-watch devices
+        if (mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            return;
+        }
+
+        final UiAutomation automation = InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation();
+
+        // Press back button PANIC_PRESS_COUNT times
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < PANIC_PRESS_COUNT; ++i) {
+            long currentTime = startTime + i;
+            automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN,
+                    KeyEvent.KEYCODE_BACK, 0), true);
+            automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_UP,
+                    KeyEvent.KEYCODE_BACK, 0), true);
+        }
+
+        // Wait multi press time out plus some time to give the system time to respond
+        long timeoutMs = ViewConfiguration.getMultiPressTimeout() + TimeUnit.SECONDS.toMillis(1);
+
+        // Assert activity was not stopped, indicating panic press was not able to exit the app
+        assertFalse(mActivity.mWaitForPanicBackLatch.await(timeoutMs, TimeUnit.MILLISECONDS));
+    }
+
+    /**
+     * Tests to ensure that the foregrounded app does handle back button panic press on watch
+     * devices
+     */
+    @Test
+    public void testWatchBackPanicReceivesHomeRequest() throws Exception {
+        // Only run for watch devices
+        if (!mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            return;
+        }
+
+        final UiAutomation automation = InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation();
+
+        // Press back button PANIC_PRESS_COUNT times
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < PANIC_PRESS_COUNT; ++i) {
+            // Assert activity hasn't stopped yet
+            assertFalse(mActivity.mWaitForPanicBackLatch.await(0, TimeUnit.MILLISECONDS));
+            long currentTime = startTime + i;
+            automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN,
+                    KeyEvent.KEYCODE_BACK, 0), true);
+            automation.injectInputEvent(new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_UP,
+                    KeyEvent.KEYCODE_BACK, 0), true);
+        }
+
+        // Wait multi press time out plus some time to give the system time to respond
+        long timeoutMs = ViewConfiguration.getMultiPressTimeout() + TimeUnit.SECONDS.toMillis(1);
+
+        // Assert activity was stopped, indicating that panic press was able to exit the app
+        assertTrue(mActivity.mWaitForPanicBackLatch.await(timeoutMs, TimeUnit.MILLISECONDS));
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyGLProducerCtsActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyGLProducerCtsActivity.java
new file mode 100644
index 0000000..b7518a5
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyGLProducerCtsActivity.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.view.cts;
+
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_SCISSOR_TEST;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glEnable;
+import static android.opengl.GLES20.glScissor;
+
+import android.graphics.Color;
+import android.opengl.GLSurfaceView;
+
+import java.util.concurrent.CountDownLatch;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class PixelCopyGLProducerCtsActivity extends GLSurfaceViewCtsActivity {
+    private static class QuadColorGLRenderer implements GLSurfaceView.Renderer {
+
+        private final int mTopLeftColor;
+        private final int mTopRightColor;
+        private final int mBottomLeftColor;
+        private final int mBottomRightColor;
+
+        private CountDownLatch mFence;
+
+        private int mWidth, mHeight;
+
+        public QuadColorGLRenderer(int topLeft, int topRight, int bottomLeft, int bottomRight) {
+            mTopLeftColor = topLeft;
+            mTopRightColor = topRight;
+            mBottomLeftColor = bottomLeft;
+            mBottomRightColor = bottomRight;
+        }
+
+        @Override
+        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        }
+
+        @Override
+        public void onSurfaceChanged(GL10 gl, int width, int height) {
+            mWidth = width;
+            mHeight = height;
+        }
+
+        @Override
+        public void onDrawFrame(GL10 gl) {
+            int cx = mWidth / 2;
+            int cy = mHeight / 2;
+
+            glEnable(GL_SCISSOR_TEST);
+
+            glScissor(0, cy, cx, mHeight - cy);
+            clearColor(mTopLeftColor);
+
+            glScissor(cx, cy, mWidth - cx, mHeight - cy);
+            clearColor(mTopRightColor);
+
+            glScissor(0, 0, cx, cy);
+            clearColor(mBottomLeftColor);
+
+            glScissor(cx, 0, mWidth - cx, cy);
+            clearColor(mBottomRightColor);
+
+            if (mFence != null) {
+                mFence.countDown();
+            }
+        }
+
+        private void clearColor(int color) {
+            glClearColor(Color.red(color) / 255.0f,
+                    Color.green(color) / 255.0f,
+                    Color.blue(color) / 255.0f,
+                    Color.alpha(color) / 255.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+        }
+    }
+
+    private QuadColorGLRenderer mRenderer;
+
+    @Override
+    protected void configureGLSurfaceView() {
+        mView.setEGLContextClientVersion(2);
+        mRenderer = new QuadColorGLRenderer(
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+        mView.setRenderer(mRenderer);
+        mView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+        mView.getHolder().setFixedSize(100, 100);
+    }
+
+    public void setSwapFence(CountDownLatch swapFence) {
+        mRenderer.mFence = swapFence;
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
new file mode 100644
index 0000000..0f37f41
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -0,0 +1,494 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Debug;
+import android.os.Debug.MemoryInfo;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.PixelCopy;
+import android.view.Surface;
+import android.view.View;
+import android.view.Window;
+
+import com.android.compatibility.common.util.SynchronousPixelCopy;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PixelCopyTest {
+    private static final String TAG = "PixelCopyTests";
+
+    @Rule
+    public ActivityTestRule<PixelCopyGLProducerCtsActivity> mGLSurfaceViewActivityRule =
+            new ActivityTestRule<>(PixelCopyGLProducerCtsActivity.class, false, false);
+
+    @Rule
+    public ActivityTestRule<PixelCopyVideoSourceActivity> mVideoSourceActivityRule =
+            new ActivityTestRule<>(PixelCopyVideoSourceActivity.class, false, false);
+
+    @Rule
+    public ActivityTestRule<PixelCopyViewProducerActivity> mWindowSourceActivityRule =
+            new ActivityTestRule<>(PixelCopyViewProducerActivity.class, false, false);
+
+    @Rule
+    public SurfaceTextureRule mSurfaceRule = new SurfaceTextureRule();
+
+    private Instrumentation mInstrumentation;
+    private SynchronousPixelCopy mCopyHelper;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        assertNotNull(mInstrumentation);
+        mCopyHelper = new SynchronousPixelCopy();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullDest() {
+        Bitmap dest = null;
+        mCopyHelper.request(mSurfaceRule.getSurface(), dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testRecycledDest() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Config.ARGB_8888);
+        dest.recycle();
+        mCopyHelper.request(mSurfaceRule.getSurface(), dest);
+    }
+
+    @Test
+    public void testNoSourceData() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        int result = mCopyHelper.request(mSurfaceRule.getSurface(), dest);
+        assertEquals(PixelCopy.ERROR_SOURCE_NO_DATA, result);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptySourceRectSurface() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        mCopyHelper.request(mSurfaceRule.getSurface(), new Rect(), dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptySourceRectWindow() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        mCopyHelper.request(mock(Window.class), new Rect(), dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidSourceRectSurface() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        mCopyHelper.request(mSurfaceRule.getSurface(), new Rect(10, 10, 0, 0), dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidSourceRectWindow() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        mCopyHelper.request(mock(Window.class), new Rect(10, 10, 0, 0), dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNoDecorView() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        Window mockWindow = mock(Window.class);
+        mCopyHelper.request(mockWindow, dest);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNoViewRoot() {
+        Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+        Window mockWindow = mock(Window.class);
+        View view = new View(mInstrumentation.getTargetContext());
+        when(mockWindow.peekDecorView()).thenReturn(view);
+        mCopyHelper.request(mockWindow, dest);
+    }
+
+    private PixelCopyGLProducerCtsActivity waitForGlProducerActivity() {
+        CountDownLatch swapFence = new CountDownLatch(2);
+
+        PixelCopyGLProducerCtsActivity activity =
+                mGLSurfaceViewActivityRule.launchActivity(null);
+        activity.setSwapFence(swapFence);
+
+        try {
+            while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
+                activity.getView().requestRender();
+            }
+        } catch (InterruptedException ex) {
+            fail("Interrupted, error=" + ex.getMessage());
+        }
+        return activity;
+    }
+
+    @Test
+    public void testGlProducerFullsize() {
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), bitmap);
+        assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+        assertEquals(100, bitmap.getWidth());
+        assertEquals(100, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testGlProducerCropTopLeft() {
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), new Rect(0, 0, 50, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.RED, Color.RED, Color.RED);
+    }
+
+    @Test
+    public void testGlProducerCropCenter() {
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), new Rect(25, 25, 75, 75), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testGlProducerCropBottomHalf() {
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), new Rect(0, 50, 100, 100), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testGlProducerCropClamping() {
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), new Rect(50, -50, 150, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN);
+    }
+
+    @Test
+    public void testGlProducerScaling() {
+        // Since we only sample mid-pixel of each qudrant, filtering
+        // quality isn't tested
+        PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888);
+        int result = mCopyHelper.request(activity.getView(), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        // Make sure nothing messed with the bitmap
+        assertEquals(20, bitmap.getWidth());
+        assertEquals(20, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    private Window waitForWindowProducerActivity() {
+        PixelCopyViewProducerActivity activity =
+                mWindowSourceActivityRule.launchActivity(null);
+        try {
+            activity.waitForFirstDrawCompleted(1, TimeUnit.SECONDS);
+        } catch (InterruptedException ex) {
+            fail("Interrupted, error=" + ex.getMessage());
+        }
+        return activity.getWindow();
+    }
+
+    @Test
+    public void testWindowProducer() {
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        Window window = waitForWindowProducerActivity();
+        int result = mCopyHelper.request(window, bitmap);
+        assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+        assertEquals(100, bitmap.getWidth());
+        assertEquals(100, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testWindowProducerCropTopLeft() {
+        Window window = waitForWindowProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(window, new Rect(0, 0, 50, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.RED, Color.RED, Color.RED);
+    }
+
+    @Test
+    public void testWindowProducerCropCenter() {
+        Window window = waitForWindowProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(window, new Rect(25, 25, 75, 75), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testWindowProducerCropBottomHalf() {
+        Window window = waitForWindowProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(window, new Rect(0, 50, 100, 100), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    public void testWindowProducerCropClamping() {
+        Window window = waitForWindowProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int result = mCopyHelper.request(window, new Rect(50, -50, 150, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        assertBitmapQuadColor(bitmap,
+                Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN);
+    }
+
+    @Test
+    public void testWindowProducerScaling() {
+        // Since we only sample mid-pixel of each qudrant, filtering
+        // quality isn't tested
+        Window window = waitForWindowProducerActivity();
+        Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888);
+        int result = mCopyHelper.request(window, bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+        // Make sure nothing messed with the bitmap
+        assertEquals(20, bitmap.getWidth());
+        assertEquals(20, bitmap.getHeight());
+        assertEquals(Config.ARGB_8888, bitmap.getConfig());
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+    }
+
+    @Test
+    @LargeTest
+    public void testNotLeaking() {
+        try {
+            CountDownLatch swapFence = new CountDownLatch(2);
+
+            PixelCopyGLProducerCtsActivity activity =
+                    mGLSurfaceViewActivityRule.launchActivity(null);
+            activity.setSwapFence(swapFence);
+
+            while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
+                activity.getView().requestRender();
+            }
+
+            // Test a fullsize copy
+            Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+
+            MemoryInfo meminfoStart = new MemoryInfo();
+            MemoryInfo meminfoEnd = new MemoryInfo();
+
+            for (int i = 0; i < 1000; i++) {
+                if (i == 2) {
+                    // Not really the "start" but by having done a couple
+                    // we've fully initialized any state that may be required,
+                    // so memory usage should be stable now
+                    Debug.getMemoryInfo(meminfoStart);
+                }
+                if (i % 10 == 5) {
+                    Debug.getMemoryInfo(meminfoEnd);
+                    if (meminfoEnd.getTotalPss() - meminfoStart.getTotalPss() > 1000 /* kb */) {
+                        assertEquals("Memory leaked, iteration=" + i,
+                                meminfoStart.getTotalPss(), meminfoEnd.getTotalPss(),
+                                1000 /* kb */);
+                    }
+                }
+                int result = mCopyHelper.request(activity.getView(), bitmap);
+                assertEquals("Copy request failed", PixelCopy.SUCCESS, result);
+                // Make sure nothing messed with the bitmap
+                assertEquals(100, bitmap.getWidth());
+                assertEquals(100, bitmap.getHeight());
+                assertEquals(Config.ARGB_8888, bitmap.getConfig());
+                assertBitmapQuadColor(bitmap,
+                        Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+            }
+
+        } catch (InterruptedException e) {
+            fail("Interrupted, error=" + e.getMessage());
+        }
+    }
+
+    @Test
+    public void testVideoProducer() throws InterruptedException {
+        PixelCopyVideoSourceActivity activity =
+                mVideoSourceActivityRule.launchActivity(null);
+        if (!activity.canPlayVideo()) {
+            Log.i(TAG, "Skipping testVideoProducer, video codec isn't supported");
+            return;
+        }
+        // This returns when the video has been prepared and playback has
+        // been started, it doesn't necessarily means a frame has actually been
+        // produced. There sadly isn't a callback for that.
+        // So we'll try for up to 900ms after this event to acquire a frame, otherwise
+        // it's considered a timeout.
+        activity.waitForPlaying();
+        assertTrue("Failed to start video playback", activity.canPlayVideo());
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        int copyResult = PixelCopy.ERROR_SOURCE_NO_DATA;
+        for (int i = 0; i < 30; i++) {
+            copyResult = mCopyHelper.request(activity.getVideoView(), bitmap);
+            if (copyResult != PixelCopy.ERROR_SOURCE_NO_DATA) {
+                break;
+            }
+            Thread.sleep(30);
+        }
+        assertEquals(PixelCopy.SUCCESS, copyResult);
+        // A large threshold is used because decoder accuracy is covered in the
+        // media CTS tests, so we are mainly interested in verifying that rotation
+        // and YUV->RGB conversion were handled properly.
+        assertBitmapQuadColor(bitmap, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30);
+
+        // Test that cropping works.
+        copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(0, 0, 50, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.RED, Color.RED, Color.RED, 30);
+
+        copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(25, 25, 75, 75), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult);
+        assertBitmapQuadColor(bitmap,
+                Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30);
+
+        copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(0, 50, 100, 100), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult);
+        assertBitmapQuadColor(bitmap,
+                Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK, 30);
+
+        // Test that clamping works
+        copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(50, -50, 150, 50), bitmap);
+        assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult);
+        assertBitmapQuadColor(bitmap,
+                Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN, 30);
+    }
+
+    private static int getPixelFloatPos(Bitmap bitmap, float xpos, float ypos) {
+        return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
+    }
+
+    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+                int bottomLeft, int bottomRight) {
+        // Just quickly sample 4 pixels in the various regions.
+        assertEquals("Top left " + Integer.toHexString(topLeft) + ", actual= "
+                + Integer.toHexString(getPixelFloatPos(bitmap, .25f, .25f))
+                , topLeft, getPixelFloatPos(bitmap, .25f, .25f));
+        assertEquals("Top right", topRight, getPixelFloatPos(bitmap, .75f, .25f));
+        assertEquals("Bottom left", bottomLeft, getPixelFloatPos(bitmap, .25f, .75f));
+        assertEquals("Bottom right", bottomRight, getPixelFloatPos(bitmap, .75f, .75f));
+    }
+
+    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+            int bottomLeft, int bottomRight, int threshold) {
+        // Just quickly sample 4 pixels in the various regions.
+        assertTrue("Top left", pixelsAreSame(topLeft, getPixelFloatPos(bitmap, .25f, .25f),
+                threshold));
+        assertTrue("Top right", pixelsAreSame(topRight, getPixelFloatPos(bitmap, .75f, .25f),
+                threshold));
+        assertTrue("Bottom left", pixelsAreSame(bottomLeft, getPixelFloatPos(bitmap, .25f, .75f),
+                threshold));
+        assertTrue("Bottom right", pixelsAreSame(bottomRight, getPixelFloatPos(bitmap, .75f, .75f),
+                threshold));
+    }
+
+    private boolean pixelsAreSame(int ideal, int given, int threshold) {
+        int error = Math.abs(Color.red(ideal) - Color.red(given));
+        error += Math.abs(Color.green(ideal) - Color.green(given));
+        error += Math.abs(Color.blue(ideal) - Color.blue(given));
+        return (error < threshold);
+    }
+
+    private static class SurfaceTextureRule implements TestRule {
+        private SurfaceTexture mSurfaceTexture = null;
+        private Surface mSurface = null;
+
+        private void createIfNecessary() {
+            mSurfaceTexture = new SurfaceTexture(false);
+            mSurface = new Surface(mSurfaceTexture);
+        }
+
+        public Surface getSurface() {
+            createIfNecessary();
+            return mSurface;
+        }
+
+        @Override
+        public Statement apply(Statement base, Description description) {
+            return new CreateSurfaceTextureStatement(base);
+        }
+
+        private class CreateSurfaceTextureStatement extends Statement {
+
+            private final Statement mBase;
+
+            public CreateSurfaceTextureStatement(Statement base) {
+                mBase = base;
+            }
+
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    mBase.evaluate();
+                } finally {
+                    try {
+                        if (mSurface != null) mSurface.release();
+                    } catch (Throwable t) {}
+                    try {
+                        if (mSurfaceTexture != null) mSurfaceTexture.release();
+                    } catch (Throwable t) {}
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTests.java b/tests/tests/view/src/android/view/cts/PixelCopyTests.java
deleted file mode 100644
index f8bf79a..0000000
--- a/tests/tests/view/src/android/view/cts/PixelCopyTests.java
+++ /dev/null
@@ -1,394 +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;
-
-import android.app.Instrumentation;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
-import android.graphics.SurfaceTexture;
-import android.opengl.GLSurfaceView;
-import android.opengl.GLSurfaceView.Renderer;
-import android.os.Debug;
-import android.os.Debug.MemoryInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.util.Log;
-import android.view.PixelCopy;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.PixelCopy.OnPixelCopyFinishedListener;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
-import static android.opengl.GLES20.GL_SCISSOR_TEST;
-import static android.opengl.GLES20.glClear;
-import static android.opengl.GLES20.glClearColor;
-import static android.opengl.GLES20.glEnable;
-import static android.opengl.GLES20.glScissor;
-
-import static org.junit.Assert.*;
-
-@MediumTest
-public class PixelCopyTests {
-    private static final String TAG = "PixelCopyTests";
-
-    @Rule
-    public ActivityTestRule<GLSurfaceViewCtsActivity> mGLSurfaceViewActivityRule =
-            new ActivityTestRule<>(GLSurfaceViewCtsActivity.class, false, false);
-
-    @Rule
-    public ActivityTestRule<PixelCopyVideoSourceActivity> mVideoSourceActivityRule =
-            new ActivityTestRule<>(PixelCopyVideoSourceActivity.class, false, false);
-
-    private Instrumentation mInstrumentation;
-
-    @Before
-    public void setUp() throws Exception {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        assertNotNull(mInstrumentation);
-    }
-
-    @Test
-    public void testErrors() {
-        Bitmap dest = null;
-        SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
-        SurfaceTexture surfaceTexture = null;
-        Surface surface = null;
-
-        try {
-            surfaceTexture = new SurfaceTexture(false);
-            surface = new Surface(surfaceTexture);
-            try {
-                copyHelper.request(surface, dest);
-                fail("Should have generated an IllegalArgumentException, null dest!");
-            } catch (IllegalArgumentException iae) {
-                // success!
-            } catch (Throwable t) {
-                throw new AssertionError("Should have generated an IllegalArgumentException!", t);
-            }
-
-            dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
-            int result = copyHelper.request(surface, dest);
-            assertEquals(PixelCopy.ERROR_SOURCE_NO_DATA, result);
-
-            dest.recycle();
-            try {
-                copyHelper.request(surface, dest);
-                fail("Should have generated an IllegalArgumentException!");
-            } catch (IllegalArgumentException iae) {
-                // success!
-            } catch (Throwable t) {
-                throw new AssertionError(
-                        "Should have generated an IllegalArgumentException, recycled bitmap!", t);
-            }
-        } finally {
-            try {
-                if (surface != null) surface.release();
-            } catch (Throwable t) {}
-            try {
-                if (surfaceTexture != null) surfaceTexture.release();
-            } catch (Throwable t) {}
-            surface = null;
-            surfaceTexture = null;
-        }
-    }
-
-    @Test
-    public void testGlProducer() {
-        try {
-            CountDownLatch swapFence = new CountDownLatch(2);
-            GLSurfaceViewCtsActivity.setGlVersion(2);
-            GLSurfaceViewCtsActivity.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
-            GLSurfaceViewCtsActivity.setFixedSize(100, 100);
-            GLSurfaceViewCtsActivity.setRenderer(new QuadColorGLRenderer(
-                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, swapFence));
-
-            GLSurfaceViewCtsActivity activity =
-                    mGLSurfaceViewActivityRule.launchActivity(null);
-
-            while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
-                activity.getView().requestRender();
-            }
-
-            // Test a fullsize copy
-            Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
-            SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
-            int result = copyHelper.request(activity.getView(), bitmap);
-            assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
-            // Make sure nothing messed with the bitmap
-            assertEquals(100, bitmap.getWidth());
-            assertEquals(100, bitmap.getHeight());
-            assertEquals(Config.ARGB_8888, bitmap.getConfig());
-            assertBitmapQuadColor(bitmap,
-                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
-
-            // Test that scaling works
-            // Since we only sample mid-pixel of each qudrant, filtering
-            // quality isn't tested
-            bitmap.reconfigure(20, 20, Config.ARGB_8888);
-            result = copyHelper.request(activity.getView(), bitmap);
-            assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
-            // Make sure nothing messed with the bitmap
-            assertEquals(20, bitmap.getWidth());
-            assertEquals(20, bitmap.getHeight());
-            assertEquals(Config.ARGB_8888, bitmap.getConfig());
-            assertBitmapQuadColor(bitmap,
-                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
-
-        } catch (InterruptedException e) {
-            fail("Interrupted, error=" + e.getMessage());
-        } finally {
-            GLSurfaceViewCtsActivity.resetFixedSize();
-            GLSurfaceViewCtsActivity.resetGlVersion();
-            GLSurfaceViewCtsActivity.resetRenderer();
-            GLSurfaceViewCtsActivity.resetRenderMode();
-        }
-    }
-
-    @Test
-    @LargeTest
-    public void testNotLeaking() {
-        try {
-            CountDownLatch swapFence = new CountDownLatch(2);
-            GLSurfaceViewCtsActivity.setGlVersion(2);
-            GLSurfaceViewCtsActivity.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
-            GLSurfaceViewCtsActivity.setFixedSize(100, 100);
-            GLSurfaceViewCtsActivity.setRenderer(new QuadColorGLRenderer(
-                    Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, swapFence));
-
-            GLSurfaceViewCtsActivity activity =
-                    mGLSurfaceViewActivityRule.launchActivity(null);
-
-            while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
-                activity.getView().requestRender();
-            }
-
-            // Test a fullsize copy
-            Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
-
-            MemoryInfo meminfoStart = new MemoryInfo();
-            MemoryInfo meminfoEnd = new MemoryInfo();
-
-            for (int i = 0; i < 1000; i++) {
-                if (i == 2) {
-                    // Not really the "start" but by having done a couple
-                    // we've fully initialized any state that may be required,
-                    // so memory usage should be stable now
-                    Debug.getMemoryInfo(meminfoStart);
-                }
-                if (i % 10 == 5) {
-                    Debug.getMemoryInfo(meminfoEnd);
-                    if (meminfoEnd.getTotalPss() - meminfoStart.getTotalPss() > 1000 /* kb */) {
-                        assertEquals("Memory leaked, iteration=" + i,
-                                meminfoStart.getTotalPss(), meminfoEnd.getTotalPss(),
-                                1000 /* kb */);
-                    }
-                }
-                SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
-                int result = copyHelper.request(activity.getView(), bitmap);
-                assertEquals("Copy request failed", PixelCopy.SUCCESS, result);
-                // Make sure nothing messed with the bitmap
-                assertEquals(100, bitmap.getWidth());
-                assertEquals(100, bitmap.getHeight());
-                assertEquals(Config.ARGB_8888, bitmap.getConfig());
-                assertBitmapQuadColor(bitmap,
-                        Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
-            }
-
-        } catch (InterruptedException e) {
-            fail("Interrupted, error=" + e.getMessage());
-        }
-    }
-
-    @Test
-    public void testVideoProducer() throws InterruptedException {
-        PixelCopyVideoSourceActivity activity =
-                mVideoSourceActivityRule.launchActivity(null);
-        if (!activity.canPlayVideo()) {
-            Log.i(TAG, "Skipping testVideoProducer, video codec isn't supported");
-            return;
-        }
-        // This returns when the video has been prepared and playback has
-        // been started, it doesn't necessarily means a frame has actually been
-        // produced. There sadly isn't a callback for that.
-        // So we'll try for up to 900ms after this event to acquire a frame, otherwise
-        // it's considered a timeout.
-        activity.waitForPlaying();
-        assertTrue("Failed to start video playback", activity.canPlayVideo());
-        SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
-        Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
-        int copyResult = PixelCopy.ERROR_SOURCE_NO_DATA;
-        for (int i = 0; i < 30; i++) {
-            copyResult = copyHelper.request(activity.getVideoView(), bitmap);
-            if (copyResult != PixelCopy.ERROR_SOURCE_NO_DATA) {
-                break;
-            }
-            Thread.sleep(30);
-        }
-        assertEquals(PixelCopy.SUCCESS, copyResult);
-        // A large threshold is used because decoder accuracy is covered in the
-        // media CTS tests, so we are mainly interested in verifying that rotation
-        // and YUV->RGB conversion were handled properly.
-        assertBitmapQuadColor(bitmap, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30);
-    }
-
-    private static int getPixelFloatPos(Bitmap bitmap, float xpos, float ypos) {
-        return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
-    }
-
-    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
-                int bottomLeft, int bottomRight) {
-        // Just quickly sample 4 pixels in the various regions.
-        assertEquals("Top left", topLeft, getPixelFloatPos(bitmap, .25f, .25f));
-        assertEquals("Top right", topRight, getPixelFloatPos(bitmap, .75f, .25f));
-        assertEquals("Bottom left", bottomLeft, getPixelFloatPos(bitmap, .25f, .75f));
-        assertEquals("Bottom right", bottomRight, getPixelFloatPos(bitmap, .75f, .75f));
-    }
-
-    private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
-            int bottomLeft, int bottomRight, int threshold) {
-        // Just quickly sample 4 pixels in the various regions.
-        assertTrue("Top left", pixelsAreSame(topLeft, getPixelFloatPos(bitmap, .25f, .25f), threshold));
-        assertTrue("Top right", pixelsAreSame(topRight, getPixelFloatPos(bitmap, .75f, .25f), threshold));
-        assertTrue("Bottom left", pixelsAreSame(bottomLeft, getPixelFloatPos(bitmap, .25f, .75f), threshold));
-        assertTrue("Bottom right", pixelsAreSame(bottomRight, getPixelFloatPos(bitmap, .75f, .75f), threshold));
-    }
-
-    private boolean pixelsAreSame(int ideal, int given, int threshold) {
-        int error = Math.abs(Color.red(ideal) - Color.red(given));
-        error += Math.abs(Color.green(ideal) - Color.green(given));
-        error += Math.abs(Color.blue(ideal) - Color.blue(given));
-        return (error < threshold);
-    }
-
-    private static class QuadColorGLRenderer implements Renderer {
-
-        private final int mTopLeftColor;
-        private final int mTopRightColor;
-        private final int mBottomLeftColor;
-        private final int mBottomRightColor;
-
-        private final CountDownLatch mFence;
-
-        private int mWidth, mHeight;
-
-        public QuadColorGLRenderer(int topLeft, int topRight,
-                int bottomLeft, int bottomRight, CountDownLatch fence) {
-            mTopLeftColor = topLeft;
-            mTopRightColor = topRight;
-            mBottomLeftColor = bottomLeft;
-            mBottomRightColor = bottomRight;
-            mFence = fence;
-        }
-
-        @Override
-        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-        }
-
-        @Override
-        public void onSurfaceChanged(GL10 gl, int width, int height) {
-            mWidth = width;
-            mHeight = height;
-        }
-
-        @Override
-        public void onDrawFrame(GL10 gl) {
-            int cx = mWidth / 2;
-            int cy = mHeight / 2;
-
-            glEnable(GL_SCISSOR_TEST);
-
-            glScissor(0, cy, cx, mHeight - cy);
-            clearColor(mTopLeftColor);
-
-            glScissor(cx, cy, mWidth - cx, mHeight - cy);
-            clearColor(mTopRightColor);
-
-            glScissor(0, 0, cx, cy);
-            clearColor(mBottomLeftColor);
-
-            glScissor(cx, 0, mWidth - cx, cy);
-            clearColor(mBottomRightColor);
-
-            mFence.countDown();
-        }
-
-        private void clearColor(int color) {
-            glClearColor(Color.red(color) / 255.0f,
-                    Color.green(color) / 255.0f,
-                    Color.blue(color) / 255.0f,
-                    Color.alpha(color) / 255.0f);
-            glClear(GL_COLOR_BUFFER_BIT);
-        }
-    }
-
-    private static class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
-        private static Handler sHandler;
-        static {
-            HandlerThread thread = new HandlerThread("PixelCopyHelper");
-            thread.start();
-            sHandler = new Handler(thread.getLooper());
-        }
-
-        private int mStatus = -1;
-
-        public int request(Surface source, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(SurfaceView source, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        private int getResultLocked() {
-            try {
-                this.wait(1000);
-            } catch (InterruptedException e) {
-                fail("PixelCopy request didn't complete within 1s");
-            }
-            return mStatus;
-        }
-
-        @Override
-        public void onPixelCopyFinished(int copyResult) {
-            synchronized (this) {
-                mStatus = copyResult;
-                this.notify();
-            }
-        }
-    }
-}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java
index e250390..246e5aa 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java
@@ -17,12 +17,13 @@
 package android.view.cts;
 
 import android.app.Activity;
-import android.cts.util.MediaUtils;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.widget.VideoView;
 
+import com.android.compatibility.common.util.MediaUtils;
+
 import java.util.concurrent.CountDownLatch;
 
 public class PixelCopyVideoSourceActivity extends Activity {
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
new file mode 100644
index 0000000..e625042
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.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 android.view.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver.OnDrawListener;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class PixelCopyViewProducerActivity extends Activity implements OnDrawListener {
+    private View mContent;
+    private CountDownLatch mFence = new CountDownLatch(1);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContent = new ColoredGrid(this);
+        setContentView(mContent);
+        mContent.getViewTreeObserver().addOnDrawListener(this);
+    }
+
+    private static final class ColoredGrid extends View {
+        private Paint mPaint = new Paint();
+        private Rect mRect = new Rect();
+
+        public ColoredGrid(Context context) {
+            super(context);
+            setWillNotDraw(false);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            int cx = getWidth() / 2;
+            int cy = getHeight() / 2;
+
+            mRect.set(0, 0, cx, cy);
+            mPaint.setColor(Color.RED);
+            canvas.drawRect(mRect, mPaint);
+
+            mRect.set(cx, 0, getWidth(), cy);
+            mPaint.setColor(Color.GREEN);
+            canvas.drawRect(mRect, mPaint);
+
+            mRect.set(0, cy, cx, getHeight());
+            mPaint.setColor(Color.BLUE);
+            canvas.drawRect(mRect, mPaint);
+
+            mRect.set(cx, cy, getWidth(), getHeight());
+            mPaint.setColor(Color.BLACK);
+            canvas.drawRect(mRect, mPaint);
+        }
+    }
+
+    @Override
+    public void onDraw() {
+        mContent.post(() -> {
+            mContent.getViewTreeObserver().removeOnDrawListener(PixelCopyViewProducerActivity.this);
+            mFence.countDown();
+        });
+    }
+
+    public void waitForFirstDrawCompleted(int timeout, TimeUnit unit)
+            throws InterruptedException {
+        mFence.await(timeout, unit);
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java b/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
index b56d67e..53dd062 100644
--- a/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
+++ b/tests/tests/view/src/android/view/cts/ScaleGestureDetectorTest.java
@@ -16,40 +16,49 @@
 
 package android.view.cts;
 
-import android.content.Context;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Handler;
 import android.os.Looper;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
 
-public class ScaleGestureDetectorTest extends
-        ActivityInstrumentationTestCase2<ScaleGestureDetectorCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScaleGestureDetectorTest {
 
     private ScaleGestureDetector mScaleGestureDetector;
     private ScaleGestureDetectorCtsActivity mActivity;
-    private Context mContext;
 
-    public ScaleGestureDetectorTest() {
-        super("android.view.cts", ScaleGestureDetectorCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ScaleGestureDetectorCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ScaleGestureDetectorCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mScaleGestureDetector = mActivity.getScaleGestureDetector();
-        mContext = getInstrumentation().getTargetContext();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new ScaleGestureDetector(
-                mContext, new SimpleOnScaleGestureListener(), new Handler(Looper.getMainLooper()));
-        new ScaleGestureDetector(mContext, new SimpleOnScaleGestureListener());
+                mActivity, new SimpleOnScaleGestureListener(), new Handler(Looper.getMainLooper()));
+        new ScaleGestureDetector(mActivity, new SimpleOnScaleGestureListener());
     }
 
+    @Test
     public void testAccessStylusScaleEnabled() {
         assertTrue(mScaleGestureDetector.isStylusScaleEnabled());
         mScaleGestureDetector.setStylusScaleEnabled(true);
diff --git a/tests/tests/view/src/android/view/cts/SearchEventActivity.java b/tests/tests/view/src/android/view/cts/SearchEventActivity.java
index 292ecb9..2adee51 100644
--- a/tests/tests/view/src/android/view/cts/SearchEventActivity.java
+++ b/tests/tests/view/src/android/view/cts/SearchEventActivity.java
@@ -16,15 +16,12 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.SearchEvent;
 
 public class SearchEventActivity extends Activity {
-
-    private static SearchEvent mSearchEvent;
+    private SearchEvent mSearchEvent;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -41,8 +38,4 @@
     public SearchEvent getTestSearchEvent() {
         return mSearchEvent;
     }
-
-    public void reset() {
-        mSearchEvent = null;
-    }
 }
diff --git a/tests/tests/view/src/android/view/cts/SearchEventTest.java b/tests/tests/view/src/android/view/cts/SearchEventTest.java
index d4a95d5..9ae9e61 100644
--- a/tests/tests/view/src/android/view/cts/SearchEventTest.java
+++ b/tests/tests/view/src/android/view/cts/SearchEventTest.java
@@ -16,45 +16,63 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
+import android.content.Context;
+import android.hardware.input.InputManager;
+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.InputDevice;
 import android.view.KeyEvent;
 import android.view.SearchEvent;
 
-public class SearchEventTest extends ActivityInstrumentationTestCase2<SearchEventActivity> {
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SearchEventTest {
 
     private Instrumentation mInstrumentation;
     private SearchEventActivity mActivity;
 
-    public SearchEventTest() {
-        super(SearchEventActivity.class);
+    @Rule
+    public ActivityTestRule<SearchEventActivity> mActivityRule =
+            new ActivityTestRule<>(SearchEventActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(5000, mActivity::hasWindowFocus);
     }
 
-    // Wait until mActivity has window focus, or timeout ms elapses.  Return true
-    // iff mActivity gained window focus.
-    private boolean waitForActivityToHaveFocus(long timeout) {
-        long start = System.currentTimeMillis();
-        long cur = System.currentTimeMillis();
-        try {
-            while (!mActivity.hasWindowFocus() && (cur - start) < timeout) {
-                Thread.sleep(50);
+    @Test
+    public void testConstructor() {
+        final InputManager inputManager = (InputManager) mInstrumentation.getTargetContext().
+                getSystemService(Context.INPUT_SERVICE);
+        if (inputManager == null) {
+            return;
+        }
+        final int[] inputDeviceIds = inputManager.getInputDeviceIds();
+        if (inputDeviceIds != null) {
+            for (int inputDeviceId : inputDeviceIds) {
+                final InputDevice inputDevice = inputManager.getInputDevice(inputDeviceId);
+                new SearchEvent(inputDevice);
             }
-        } catch (InterruptedException x) {}
-        return mActivity.hasWindowFocus();
+        }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-        assertTrue(waitForActivityToHaveFocus(5000 /* ms = 5s */));
-    }
-
-    public void testTest() throws Exception {
+    @Test
+    public void testBasics() {
         mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_SEARCH);
         SearchEvent se = mActivity.getTestSearchEvent();
         assertNotNull(se);
diff --git a/tests/tests/view/src/android/view/cts/SoundEffectConstantsTest.java b/tests/tests/view/src/android/view/cts/SoundEffectConstantsTest.java
index e1a047e..186e06d 100644
--- a/tests/tests/view/src/android/view/cts/SoundEffectConstantsTest.java
+++ b/tests/tests/view/src/android/view/cts/SoundEffectConstantsTest.java
@@ -16,20 +16,21 @@
 
 package android.view.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.SoundEffectConstants;
 import android.view.View;
 
-public class SoundEffectConstantsTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-    }
-
-    public void testgetContantForFocusDirection() {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SoundEffectConstantsTest {
+    @Test
+    public void testGetContantForFocusDirection() {
         assertEquals(SoundEffectConstants.NAVIGATION_RIGHT,
                 SoundEffectConstants
                         .getContantForFocusDirection(View.FOCUS_RIGHT));
@@ -45,11 +46,10 @@
 
         assertEquals(SoundEffectConstants.NAVIGATION_UP, SoundEffectConstants
                 .getContantForFocusDirection(View.FOCUS_BACKWARD));
-        try {
-            SoundEffectConstants.getContantForFocusDirection(-1);
-            fail("should throw exception");
-        } catch (RuntimeException e) {
+    }
 
-        }
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetContantForFocusDirectionInvalid() {
+        SoundEffectConstants.getContantForFocusDirection(-1);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/SurfaceHolder_BadSurfaceTypeExceptionTest.java b/tests/tests/view/src/android/view/cts/SurfaceHolder_BadSurfaceTypeExceptionTest.java
index 7571453..79990e9 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceHolder_BadSurfaceTypeExceptionTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceHolder_BadSurfaceTypeExceptionTest.java
@@ -15,37 +15,47 @@
  */
 package android.view.cts;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.SurfaceHolder.BadSurfaceTypeException;
 
-public class SurfaceHolder_BadSurfaceTypeExceptionTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SurfaceHolder_BadSurfaceTypeExceptionTest {
+    @Test
     public void testBadSurfaceTypeException(){
         BadSurfaceTypeException ne = null;
-        boolean isThrowed = false;
+        boolean isThrown = false;
 
         try {
             ne = new BadSurfaceTypeException();
             throw ne;
         } catch (BadSurfaceTypeException e) {
             assertSame(ne, e);
-            isThrowed = true;
+            isThrown = true;
         } finally {
-            if (!isThrowed) {
+            if (!isThrown) {
                 fail("should throw out InflateException");
             }
         }
 
         String name = "SurfaceHolder_BadSurfaceTypeExceptionTest";
-        isThrowed = false;
+        isThrown = false;
 
         try {
             ne = new BadSurfaceTypeException(name);
             throw ne;
         } catch (BadSurfaceTypeException e) {
             assertSame(ne, e);
-            isThrowed = true;
+            isThrown = true;
         } finally {
-            if (!isThrowed) {
+            if (!isThrown) {
                 fail("should throw out InflateException");
             }
         }
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewSyncTest.java b/tests/tests/view/src/android/view/cts/SurfaceViewSyncTest.java
new file mode 100644
index 0000000..ff283a6
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewSyncTest.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.view.cts;
+
+import static org.junit.Assert.assertTrue;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.media.MediaPlayer;
+import android.os.Environment;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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.util.Log;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.LinearInterpolator;
+import android.view.cts.surfacevalidator.AnimationFactory;
+import android.view.cts.surfacevalidator.AnimationTestCase;
+import android.view.cts.surfacevalidator.CapturedActivity;
+import android.view.cts.surfacevalidator.ViewFactory;
+import android.widget.FrameLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+@SuppressLint("RtlHardcoded")
+public class SurfaceViewSyncTest {
+    private static final String TAG = "SurfaceViewSyncTests";
+    private static final int PERMISSION_DIALOG_WAIT_MS = 1000;
+
+    @Rule
+    public ActivityTestRule<CapturedActivity> mActivityRule =
+            new ActivityTestRule<>(CapturedActivity.class);
+
+    @Rule
+    public TestName mName = new TestName();
+
+    private CapturedActivity mActivity;
+    private MediaPlayer mMediaPlayer;
+
+
+    /**
+     * Want to be especially sure we don't leave up the permission dialog, so try and dismiss both
+     * before and after test.
+     */
+    @Before
+    @After
+    public void setup() throws UiObjectNotFoundException {
+        // The permission dialog will be auto-opened by the activity - find it and accept
+        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        UiSelector acceptButtonSelector = new UiSelector().resourceId("android:id/button1");
+        UiObject acceptButton = uiDevice.findObject(acceptButtonSelector);
+        if (acceptButton.waitForExists(PERMISSION_DIALOG_WAIT_MS)) {
+            boolean success = acceptButton.click();
+            Log.d(TAG, "found permission dialog, click attempt success = " + success);
+        }
+
+        mActivity = mActivityRule.getActivity();
+        mMediaPlayer = mActivity.getMediaPlayer();
+    }
+
+    private static ValueAnimator makeInfinite(ValueAnimator a) {
+        a.setRepeatMode(ObjectAnimator.REVERSE);
+        a.setRepeatCount(ObjectAnimator.INFINITE);
+        a.setDuration(200);
+        a.setInterpolator(new LinearInterpolator());
+        return a;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ViewFactories
+    ///////////////////////////////////////////////////////////////////////////
+
+    private ViewFactory sEmptySurfaceViewFactory = SurfaceView::new;
+
+    private ViewFactory sGreenSurfaceViewFactory = context -> {
+        SurfaceView surfaceView = new SurfaceView(context);
+        surfaceView.getHolder().setFixedSize(640, 480);
+        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {}
+
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                Canvas canvas = holder.lockCanvas();
+                canvas.drawColor(Color.GREEN);
+                holder.unlockCanvasAndPost(canvas);
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {}
+        });
+        return surfaceView;
+    };
+
+    private ViewFactory sVideoViewFactory = context -> {
+        SurfaceView surfaceView = new SurfaceView(context);
+        surfaceView.getHolder().setFixedSize(640, 480);
+        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                mMediaPlayer.setSurface(holder.getSurface());
+                mMediaPlayer.start();
+            }
+
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                mMediaPlayer.pause();
+                mMediaPlayer.setSurface(null);
+            }
+        });
+        return surfaceView;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // AnimationFactories
+    ///////////////////////////////////////////////////////////////////////////
+
+    private AnimationFactory sSmallScaleAnimationFactory = view -> {
+        view.setPivotX(0);
+        view.setPivotY(0);
+        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.01f, 1f);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.01f, 1f);
+        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
+    };
+
+    private AnimationFactory sBigScaleAnimationFactory = view -> {
+        view.setTranslationX(10);
+        view.setTranslationY(10);
+        view.setPivotX(0);
+        view.setPivotY(0);
+        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1f, 3f);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f, 3f);
+        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
+    };
+
+    private AnimationFactory sTranslateAnimationFactory = view -> {
+        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f);
+        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f);
+        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Bad frame capture
+    ///////////////////////////////////////////////////////////////////////////
+
+    private void saveFailureCaptures(SparseArray<Bitmap> failFrames) {
+        if (failFrames.size() == 0) return;
+
+        String directoryName = Environment.getExternalStorageDirectory()
+                + "/" + getClass().getSimpleName()
+                + "/" + mName.getMethodName();
+        File testDirectory = new File(directoryName);
+        if (testDirectory.exists()) {
+            String[] children = testDirectory.list();
+            if (children == null) {
+                return;
+            }
+            for (String file : children) {
+                new File(testDirectory, file).delete();
+            }
+        } else {
+            testDirectory.mkdirs();
+        }
+
+        for (int i = 0; i < failFrames.size(); i++) {
+            int frameNr = failFrames.keyAt(i);
+            Bitmap bitmap = failFrames.valueAt(i);
+
+            String bitmapName =  "frame_" + frameNr + ".png";
+            Log.d(TAG, "Saving file : " + bitmapName + " in directory : " + directoryName);
+
+            File file = new File(directoryName, bitmapName);
+            try (FileOutputStream fileStream = new FileOutputStream(file)) {
+                bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+                fileStream.flush();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Tests
+    ///////////////////////////////////////////////////////////////////////////
+
+    private void verifyTest(AnimationTestCase testCase) throws InterruptedException {
+        CapturedActivity.TestResult result = mActivity.runTest(testCase);
+        saveFailureCaptures(result.failures);
+
+        float failRatio = 1.0f * result.failFrames / (result.failFrames + result.passFrames);
+        assertTrue("Error: " + failRatio + " fail ratio - extremely high, is activity obstructed?",
+                failRatio < 0.95f);
+        assertTrue("Error: " + result.failFrames
+                + " incorrect frames observed - incorrect positioning",
+                result.failFrames == 0);
+        float framesPerSecond = 1.0f * result.passFrames
+                / TimeUnit.MILLISECONDS.toSeconds(CapturedActivity.CAPTURE_DURATION_MS);
+        assertTrue("Error, only " + result.passFrames
+                + " frames observed, virtual display only capturing at "
+                + framesPerSecond + " frames per second",
+                result.passFrames > 100);
+    }
+
+    /** Draws a moving 10x10 black rectangle, validates 100 pixels of black are seen each frame */
+    @Test
+    public void testSmallRect() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                context -> new View(context) {
+                    // draw a single pixel
+                    final Paint sBlackPaint = new Paint();
+                    @Override
+                    protected void onDraw(Canvas canvas) {
+                        canvas.drawRect(0, 0, 10, 10, sBlackPaint);
+                    }
+
+                    @SuppressWarnings("unused")
+                    void setOffset(int offset) {
+                        // Note: offset by integer values, to ensure no rounding
+                        // is done in rendering layer, as that may be brittle
+                        setTranslationX(offset);
+                        setTranslationY(offset);
+                    }
+                },
+                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
+                view -> makeInfinite(ObjectAnimator.ofInt(view, "offset", 10, 30)),
+                (blackishPixelCount, width, height) ->
+                        blackishPixelCount >= 90 && blackishPixelCount <= 110));
+    }
+
+    /**
+     * Verifies that a SurfaceView without a surface is entirely black, with pixel count being
+     * approximate to avoid rounding brittleness.
+     */
+    @Test
+    public void testEmptySurfaceView() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sEmptySurfaceViewFactory,
+                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
+                sTranslateAnimationFactory,
+                (blackishPixelCount, width, height) ->
+                        blackishPixelCount > 9000 && blackishPixelCount < 11000));
+    }
+
+    @Test
+    public void testSurfaceViewSmallScale() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sGreenSurfaceViewFactory,
+                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
+                sSmallScaleAnimationFactory,
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+
+    @Test
+    public void testSurfaceViewBigScale() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sGreenSurfaceViewFactory,
+                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
+                sBigScaleAnimationFactory,
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+
+    @Test
+    public void testVideoSurfaceViewTranslate() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sVideoViewFactory,
+                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
+                sTranslateAnimationFactory,
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+
+    @Test
+    public void testVideoSurfaceViewRotated() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sVideoViewFactory,
+                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
+                view -> makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
+                        PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f),
+                        PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f),
+                        PropertyValuesHolder.ofFloat(View.ROTATION, 45f, 45f))),
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+
+    @Test
+    public void testVideoSurfaceViewEdgeCoverage() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sVideoViewFactory,
+                new FrameLayout.LayoutParams(640, 480, Gravity.CENTER),
+                view -> {
+                    ViewGroup parent = (ViewGroup) view.getParent();
+                    final int x = parent.getWidth() / 2;
+                    final int y = parent.getHeight() / 2;
+
+                    // Animate from left, to top, to right, to bottom
+                    return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
+                            PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -x, 0, x, 0, -x),
+                            PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0, -y, 0, y, 0)));
+                },
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+
+    @Test
+    public void testVideoSurfaceViewCornerCoverage() throws InterruptedException {
+        verifyTest(new AnimationTestCase(
+                sVideoViewFactory,
+                new FrameLayout.LayoutParams(640, 480, Gravity.CENTER),
+                view -> {
+                    ViewGroup parent = (ViewGroup) view.getParent();
+                    final int x = parent.getWidth() / 2;
+                    final int y = parent.getHeight() / 2;
+
+                    // Animate from top left, to top right, to bottom right, to bottom left
+                    return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
+                            PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -x, x, x, -x, -x),
+                            PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -y, -y, y, y, -y)));
+                },
+                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewSyncTests.java b/tests/tests/view/src/android/view/cts/SurfaceViewSyncTests.java
deleted file mode 100644
index 776e650..0000000
--- a/tests/tests/view/src/android/view/cts/SurfaceViewSyncTests.java
+++ /dev/null
@@ -1,354 +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;
-
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.media.MediaPlayer;
-import android.os.Environment;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.LinearInterpolator;
-import android.view.cts.surfacevalidator.AnimationFactory;
-import android.view.cts.surfacevalidator.AnimationTestCase;
-import android.view.cts.surfacevalidator.CapturedActivity;
-import android.view.cts.surfacevalidator.ViewFactory;
-import android.widget.FrameLayout;
-
-import libcore.io.IoUtils;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.*;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-@SuppressLint("RtlHardcoded")
-public class SurfaceViewSyncTests {
-    private static final String TAG = "SurfaceViewSyncTests";
-
-    private CapturedActivity getActivity() {
-        return (CapturedActivity) mActivityRule.getActivity();
-    }
-
-    /**
-     * Want to be especially sure we don't leave up the permission dialog, so try and dismiss
-     * after test.
-     */
-    @After
-    public void setUp() throws UiObjectNotFoundException {
-        getActivity().dismissPermissionDialog();
-    }
-
-    private MediaPlayer getMediaPlayer() {
-        return getActivity().getMediaPlayer();
-    }
-
-    @Rule
-    public ActivityTestRule mActivityRule = new ActivityTestRule<>(CapturedActivity.class);
-
-    @Rule
-    public TestName mName = new TestName();
-
-    static ValueAnimator makeInfinite(ValueAnimator a) {
-        a.setRepeatMode(ObjectAnimator.REVERSE);
-        a.setRepeatCount(ObjectAnimator.INFINITE);
-        a.setDuration(200);
-        a.setInterpolator(new LinearInterpolator());
-        return a;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // ViewFactories
-    ///////////////////////////////////////////////////////////////////////////
-
-    private ViewFactory sEmptySurfaceViewFactory = SurfaceView::new;
-
-    private ViewFactory sGreenSurfaceViewFactory = context -> {
-        SurfaceView surfaceView = new SurfaceView(context);
-        surfaceView.getHolder().setFixedSize(640, 480);
-        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceCreated(SurfaceHolder holder) {}
-
-            @Override
-            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-                Canvas canvas = holder.lockCanvas();
-                canvas.drawColor(Color.GREEN);
-                holder.unlockCanvasAndPost(canvas);
-            }
-
-            @Override
-            public void surfaceDestroyed(SurfaceHolder holder) {}
-        });
-        return surfaceView;
-    };
-
-    private ViewFactory sVideoViewFactory = context -> {
-        SurfaceView surfaceView = new SurfaceView(context);
-        surfaceView.getHolder().setFixedSize(640, 480);
-        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
-            @Override
-            public void surfaceCreated(SurfaceHolder holder) {
-                getMediaPlayer().setSurface(holder.getSurface());
-                getMediaPlayer().start();
-            }
-
-            @Override
-            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
-
-            @Override
-            public void surfaceDestroyed(SurfaceHolder holder) {
-                getMediaPlayer().pause();
-                getMediaPlayer().setSurface(null);
-            }
-        });
-        return surfaceView;
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-    // AnimationFactories
-    ///////////////////////////////////////////////////////////////////////////
-
-    private AnimationFactory sSmallScaleAnimationFactory = view -> {
-        view.setPivotX(0);
-        view.setPivotY(0);
-        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.01f, 1f);
-        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.01f, 1f);
-        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
-    };
-
-    private AnimationFactory sBigScaleAnimationFactory = view -> {
-        view.setTranslationX(10);
-        view.setTranslationY(10);
-        view.setPivotX(0);
-        view.setPivotY(0);
-        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1f, 3f);
-        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f, 3f);
-        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
-    };
-
-    private AnimationFactory sTranslateAnimationFactory = view -> {
-        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f);
-        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f);
-        return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY));
-    };
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Bad frame capture
-    ///////////////////////////////////////////////////////////////////////////
-
-    private void saveFailureCaptures(SparseArray<Bitmap> failFrames) {
-        if (failFrames.size() == 0) return;
-
-        String directoryName = Environment.getExternalStorageDirectory()
-                + "/" + getClass().getSimpleName()
-                + "/" + mName.getMethodName();
-        File testDirectory = new File(directoryName);
-        if (testDirectory.exists()) {
-            String[] children = testDirectory.list();
-            if (children == null) {
-                return;
-            }
-            for (String file : children) {
-                new File(testDirectory, file).delete();
-            }
-        } else {
-            testDirectory.mkdirs();
-        }
-
-        for (int i = 0; i < failFrames.size(); i++) {
-            int frameNr = failFrames.keyAt(i);
-            Bitmap bitmap = failFrames.valueAt(i);
-
-            String bitmapName =  "frame_" + frameNr + ".png";
-            Log.d(TAG, "Saving file : " + bitmapName + " in directory : " + directoryName);
-
-            File file = new File(directoryName, bitmapName);
-            FileOutputStream fileStream = null;
-            try {
-                fileStream = new FileOutputStream(file);
-                bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
-                fileStream.flush();
-            } catch (IOException e) {
-                e.printStackTrace();
-            } finally {
-                IoUtils.closeQuietly(fileStream);
-            }
-        }
-    }
-
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Tests
-    ///////////////////////////////////////////////////////////////////////////
-
-    public void verifyTest(AnimationTestCase testCase) throws Throwable {
-        CapturedActivity.TestResult result = getActivity().runTest(testCase);
-        saveFailureCaptures(result.failures);
-
-        float failRatio = 1.0f * result.failFrames / (result.failFrames + result.passFrames);
-        assertTrue("Error: " + failRatio + " fail ratio - extremely high, is activity obstructed?",
-                failRatio < 0.95f);
-        assertTrue("Error: " + result.failFrames
-                + " incorrect frames observed - incorrect positioning",
-                result.failFrames == 0);
-        float framesPerSecond = 1.0f * result.passFrames
-                / TimeUnit.MILLISECONDS.toSeconds(CapturedActivity.CAPTURE_DURATION_MS);
-        assertTrue("Error, only " + result.passFrames
-                + " frames observed, virtual display only capturing at "
-                + framesPerSecond + " frames per second",
-                result.passFrames > 100);
-    }
-
-    /** Draws a moving 10x10 black rectangle, validates 100 pixels of black are seen each frame */
-    @Test
-    public void testSmallRect() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                context -> new View(context) {
-                    // draw a single pixel
-                    final Paint sBlackPaint = new Paint();
-                    @Override
-                    protected void onDraw(Canvas canvas) {
-                        canvas.drawRect(0, 0, 10, 10, sBlackPaint);
-                    }
-
-                    @SuppressWarnings("unused")
-                    void setOffset(int offset) {
-                        // Note: offset by integer values, to ensure no rounding
-                        // is done in rendering layer, as that may be brittle
-                        setTranslationX(offset);
-                        setTranslationY(offset);
-                    }
-                },
-                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
-                view -> makeInfinite(ObjectAnimator.ofInt(view, "offset", 10, 30)),
-                (blackishPixelCount, width, height) ->
-                        blackishPixelCount >= 90 && blackishPixelCount <= 110));
-    }
-
-    /**
-     * Verifies that a SurfaceView without a surface is entirely black, with pixel count being
-     * approximate to avoid rounding brittleness.
-     */
-    @Test
-    public void testEmptySurfaceView() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sEmptySurfaceViewFactory,
-                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
-                sTranslateAnimationFactory,
-                (blackishPixelCount, width, height) ->
-                        blackishPixelCount > 9000 && blackishPixelCount < 11000));
-    }
-
-    @Test
-    public void testSurfaceViewSmallScale() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sGreenSurfaceViewFactory,
-                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
-                sSmallScaleAnimationFactory,
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-
-    @Test
-    public void testSurfaceViewBigScale() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sGreenSurfaceViewFactory,
-                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
-                sBigScaleAnimationFactory,
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-
-    @Test
-    public void testVideoSurfaceViewTranslate() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sVideoViewFactory,
-                new FrameLayout.LayoutParams(640, 480, Gravity.LEFT | Gravity.TOP),
-                sTranslateAnimationFactory,
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-
-    @Test
-    public void testVideoSurfaceViewRotated() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sVideoViewFactory,
-                new FrameLayout.LayoutParams(100, 100, Gravity.LEFT | Gravity.TOP),
-                view -> makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
-                        PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 10f, 30f),
-                        PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 10f, 30f),
-                        PropertyValuesHolder.ofFloat(View.ROTATION, 45f, 45f))),
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-
-    @Test
-    public void testVideoSurfaceViewEdgeCoverage() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sVideoViewFactory,
-                new FrameLayout.LayoutParams(640, 480, Gravity.CENTER),
-                view -> {
-                    ViewGroup parent = (ViewGroup) view.getParent();
-                    final int x = parent.getWidth() / 2;
-                    final int y = parent.getHeight() / 2;
-
-                    // Animate from left, to top, to right, to bottom
-                    return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
-                            PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -x, 0, x, 0, -x),
-                            PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0, -y, 0, y, 0)));
-                },
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-
-    @Test
-    public void testVideoSurfaceViewCornerCoverage() throws Throwable {
-        verifyTest(new AnimationTestCase(
-                sVideoViewFactory,
-                new FrameLayout.LayoutParams(640, 480, Gravity.CENTER),
-                view -> {
-                    ViewGroup parent = (ViewGroup) view.getParent();
-                    final int x = parent.getWidth() / 2;
-                    final int y = parent.getHeight() / 2;
-
-                    // Animate from top left, to top right, to bottom right, to bottom left
-                    return makeInfinite(ObjectAnimator.ofPropertyValuesHolder(view,
-                            PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -x, x, x, -x, -x),
-                            PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -y, -y, y, y, -y)));
-                },
-                (blackishPixelCount, width, height) -> blackishPixelCount == 0));
-    }
-}
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
index aa97ffd..277a094 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
@@ -16,52 +16,60 @@
 
 package android.view.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 android.app.Instrumentation;
-import android.content.Context;
-import android.cts.util.PollingCheck;
-import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Region;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.cts.SurfaceViewCtsActivity.MockSurfaceView;
 
-public class SurfaceViewTest extends ActivityInstrumentationTestCase2<SurfaceViewCtsActivity> {
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
 
-    private Context mContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SurfaceViewTest {
     private Instrumentation mInstrumentation;
+    private SurfaceViewCtsActivity mActivity;
     private MockSurfaceView mMockSurfaceView;
 
-    public SurfaceViewTest() {
-        super("android.view.cts", SurfaceViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<SurfaceViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SurfaceViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getContext();
-        final SurfaceViewCtsActivity activity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
-        mMockSurfaceView = activity.getSurfaceView();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
+        mMockSurfaceView = mActivity.getSurfaceView();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-        new SurfaceView(mContext);
-        new SurfaceView(mContext, null);
-        new SurfaceView(mContext, null, 0);
+        new SurfaceView(mActivity);
+        new SurfaceView(mActivity, null);
+        new SurfaceView(mActivity, null, 0);
     }
 
+    @Test
     public void testSurfaceView() {
         final int left = 40;
         final int top = 30;
@@ -99,11 +107,12 @@
         assertTrue(actual instanceof SurfaceHolder);
     }
 
-    @UiThreadTest
     /**
      * check point:
      * check surfaceView size before and after layout
      */
+    @UiThreadTest
+    @Test
     public void testOnSizeChanged() {
         final int left = 40;
         final int top = 30;
@@ -123,11 +132,12 @@
         assertEquals(bottom - top, mMockSurfaceView.getHeight());
     }
 
-    @UiThreadTest
     /**
      * check point:
      * check surfaceView scroll X and y before and after scrollTo
      */
+    @UiThreadTest
+    @Test
     public void testOnScrollChanged() {
         final int scrollToX = 200;
         final int scrollToY = 200;
@@ -143,25 +153,12 @@
         assertEquals(scrollToY, mMockSurfaceView.getScrollY());
     }
 
+    @Test
     public void testOnDetachedFromWindow() {
-        final MockSurfaceView mockSurfaceView = getActivity().getSurfaceView();
-        assertFalse(mockSurfaceView.isDetachedFromWindow());
-        assertTrue(mockSurfaceView.isShown());
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mockSurfaceView.isDetachedFromWindow() &&
-                       !mockSurfaceView.isShown();
-            }
-        }.run();
-    }
-
-    private void sleep(long time) {
-        try {
-            Thread.sleep(time);
-        } catch (InterruptedException e) {
-            fail("error occurs when wait for an action: " + e.toString());
-        }
+        assertFalse(mMockSurfaceView.isDetachedFromWindow());
+        assertTrue(mMockSurfaceView.isShown());
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mMockSurfaceView, KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(() -> mMockSurfaceView.isDetachedFromWindow() &&
+                !mMockSurfaceView.isShown());
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/Surface_OutOfResourcesExceptionTest.java b/tests/tests/view/src/android/view/cts/Surface_OutOfResourcesExceptionTest.java
index a98e818..438ff1b 100644
--- a/tests/tests/view/src/android/view/cts/Surface_OutOfResourcesExceptionTest.java
+++ b/tests/tests/view/src/android/view/cts/Surface_OutOfResourcesExceptionTest.java
@@ -16,15 +16,19 @@
 
 package android.view.cts;
 
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
 
-public class Surface_OutOfResourcesExceptionTest extends AndroidTestCase {
-    private static final String NAME = "Test_Surface_OutOfResourcesException";
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Surface_OutOfResourcesExceptionTest {
+    @Test
     public void testConstructor() {
         new Surface.OutOfResourcesException();
-        new Surface.OutOfResourcesException(NAME);
+        new Surface.OutOfResourcesException("Test_Surface_OutOfResourcesException");
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
index 029e308..16bbc18 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
@@ -44,7 +44,7 @@
 
 public class TextureViewCtsActivity extends Activity implements SurfaceTextureListener {
     private final static long TIME_OUT_MS = 10000;
-    private Object mLock = new Object();
+    private final Object mLock = new Object();
 
     private View mPreview;
     private TextureView mTextureView;
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index 12c689f..a9e215b 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -16,6 +16,10 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Instrumentation;
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -23,30 +27,32 @@
 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.cts.util.ViewTestUtils;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import static org.junit.Assert.*;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.TimeoutException;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TextureViewTest {
+    private Instrumentation mInstrumentation;
+    private TextureViewCtsActivity mActivity;
 
     @Rule
-    public ActivityTestRule<TextureViewCtsActivity> mActivityRule = new ActivityTestRule<>(
-            TextureViewCtsActivity.class);
-
-    private TextureViewCtsActivity mActivity;
-    private Instrumentation mInstrumentation;
+    public ActivityTestRule<TextureViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TextureViewCtsActivity.class);
 
     @Before
-    public void setUp() throws Exception {
-        mActivity = mActivityRule.getActivity();
+    public void setup() {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         assertNotNull(mActivity);
         assertNotNull(mInstrumentation);
     }
@@ -55,7 +61,7 @@
     public void testFirstFrames() throws Throwable {
         final Point center = new Point();
         mInstrumentation.waitForIdleSync();
-        mInstrumentation.runOnMainSync(() -> {
+        mActivityRule.runOnUiThread(() -> {
             View content = mActivity.findViewById(android.R.id.content);
             int[] outLocation = new int[2];
             content.getLocationOnScreen(outLocation);
@@ -74,11 +80,10 @@
         updatedCount = mActivity.waitForSurfaceUpdateCount(1);
         assertEquals(1, updatedCount);
         assertEquals(Color.WHITE, getPixel(center));
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mActivity,
-                () -> mActivity.removeCover());
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
+                mActivity.findViewById(android.R.id.content), () -> mActivity.removeCover());
 
-        int color;
-        color = waitForChange(center, Color.WHITE);
+        int color = waitForChange(center, Color.WHITE);
         assertEquals(Color.GREEN, color);
         mActivity.drawColor(Color.BLUE);
         updatedCount = mActivity.waitForSurfaceUpdateCount(2);
@@ -117,4 +122,4 @@
         }
         throw new TimeoutException();
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/view/src/android/view/cts/TooltipActivity.java b/tests/tests/view/src/android/view/cts/TooltipActivity.java
new file mode 100644
index 0000000..6cb9967
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.View;
+
+public class TooltipActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.tooltip_layout);
+    }
+
+    public void onCreateContextMenu(
+            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+        menu.add("context menu");
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
new file mode 100644
index 0000000..1903431
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -0,0 +1,746 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link View}.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TooltipTest {
+    private static final String LOG_TAG = "TooltipTest";
+
+    private static final long TIMEOUT_DELTA = 10000;
+    private static final long WAIT_MARGIN = 100;
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private ViewGroup mTopmostView;
+    private ViewGroup mGroupView;
+    private View mNoTooltipView;
+    private View mTooltipView;
+    private View mNoTooltipView2;
+    private View mEmptyGroup;
+
+    @Rule
+    public ActivityTestRule<TooltipActivity> mActivityRule =
+            new ActivityTestRule<>(TooltipActivity.class);
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mCtsActivityRule =
+            new ActivityTestRule<>(CtsActivity.class, false, false);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTopmostView = (ViewGroup) mActivity.findViewById(R.id.tooltip_layout);
+        mGroupView = (ViewGroup) mActivity.findViewById(R.id.tooltip_group);
+        mNoTooltipView = mActivity.findViewById(R.id.no_tooltip);
+        mTooltipView = mActivity.findViewById(R.id.has_tooltip);
+        mNoTooltipView2 = mActivity.findViewById(R.id.no_tooltip2);
+        mEmptyGroup = mActivity.findViewById(R.id.empty_group);
+
+        PollingCheck.waitFor(TIMEOUT_DELTA, mActivity::hasWindowFocus);
+    }
+
+    private void waitOut(long msDelay) {
+        try {
+            Thread.sleep(msDelay + WAIT_MARGIN);
+        } catch (InterruptedException e) {
+            Log.e(LOG_TAG, "Wait interrupted. Test may fail!", e);
+        }
+    }
+
+    private void setTooltip(View view, CharSequence tooltip) throws Throwable {
+        mActivityRule.runOnUiThread(() -> view.setTooltip(tooltip));
+    }
+
+    private boolean hasTooltip(View view) {
+        final View tooltipView = view.getTooltipView();
+        return tooltipView != null && tooltipView.getParent() != null;
+    }
+
+
+    private void addView(ViewGroup parent, View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> parent.addView(view));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void removeView(View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> ((ViewGroup) (view.getParent())).removeView(view));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void callPerformLongClick(View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> view.performLongClick(0, 0));
+    }
+
+    private void requestLowProfileSystemUi() throws Throwable {
+        final int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        mActivityRule.runOnUiThread(() -> mTooltipView.setSystemUiVisibility(flag));
+        PollingCheck.waitFor(TIMEOUT_DELTA,
+                () -> (mTooltipView.getWindowSystemUiVisibility() & flag) == flag);
+    }
+
+    private void injectKeyPress(View target, int keyCode, int duration) throws Throwable {
+        if (target != null) {
+            mActivityRule.runOnUiThread(() -> {
+                target.setFocusableInTouchMode(true);
+                target.requestFocus();
+            });
+            mInstrumentation.waitForIdleSync();
+            assertTrue(target.isFocused());
+        }
+        mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+        waitOut(duration);
+        mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
+    }
+
+    private void injectArbitraryShortKeyPress() throws Throwable {
+        injectKeyPress(null, KeyEvent.KEYCODE_0, 0);
+    }
+
+    private void injectLongKeyPress(View target, int keyCode) throws Throwable {
+        injectKeyPress(target, keyCode, ViewConfiguration.getLongPressTimeout());
+    }
+
+    private void injectLongEnter(View target) throws Throwable {
+        injectLongKeyPress(target, KeyEvent.KEYCODE_ENTER);
+    }
+
+    private void injectShortClick(View target) {
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, target);
+    }
+
+    private void injectLongClick(View target) {
+        CtsTouchUtils.emulateLongPressOnView(mInstrumentation, target,
+                target.getWidth() / 2, target.getHeight() / 2);
+    }
+
+    private void injectMotionEvent(MotionEvent event) {
+        mInstrumentation.sendPointerSync(event);
+    }
+
+    private void injectHoverMove(View target, int offsetX, int offsetY) {
+        injectMotionEvent(obtainMouseEvent(
+                target, MotionEvent.ACTION_HOVER_MOVE, offsetX,  offsetY));
+    }
+
+    private void injectHoverMove(View target) {
+        injectHoverMove(target, 0, 0);
+    }
+
+    private void injectLongHoverMove(View target) {
+        injectHoverMove(target);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+    }
+
+    private static MotionEvent obtainMouseEvent(View target, int action, int offsetX, int offsetY) {
+        final long eventTime = SystemClock.uptimeMillis();
+        final int[] xy = new int[2];
+        target.getLocationOnScreen(xy);
+        MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action,
+                xy[0] + target.getWidth() / 2 + offsetX, xy[1] + target.getHeight() / 2 + offsetY,
+                0);
+        event.setSource(InputDevice.SOURCE_MOUSE);
+        return event;
+    }
+
+    @Test
+    public void testGetSetTooltip() throws Throwable {
+        // No tooltip set in resource
+        assertEquals(null, mNoTooltipView.getTooltip());
+
+        // Set the tooltip, read it back
+        final String tooltipString1 = "new tooltip";
+        setTooltip(mNoTooltipView, tooltipString1);
+        assertEquals(tooltipString1, mNoTooltipView.getTooltip());
+
+        // Clear the tooltip.
+        setTooltip(mNoTooltipView, null);
+        assertEquals(null, mNoTooltipView.getTooltip());
+
+        // Check the tooltip set in resource
+        assertEquals("tooltip text", mTooltipView.getTooltip());
+
+        // Clear the tooltip set in resource
+        setTooltip(mTooltipView, null);
+        assertEquals(null, mTooltipView.getTooltip());
+
+        // Set the tooltip again, read it back
+        final String tooltipString2 = "new tooltip 2";
+        setTooltip(mTooltipView, tooltipString2);
+        assertEquals(tooltipString2, mTooltipView.getTooltip());
+    }
+
+    @Test
+    public void testNoTooltipWhenNotSet() throws Throwable {
+        callPerformLongClick(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongClick(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongEnter(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+    }
+
+    @Test
+    public void testNoTooltipOnDisabledView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongEnter(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testUpdateOpenTooltip() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        setTooltip(mTooltipView, "updated tooltip");
+        assertTrue(hasTooltip(mTooltipView));
+
+        setTooltip(mTooltipView, null);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testTooltipHidesOnActivityFocusChange() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        CtsActivity activity = mCtsActivityRule.launchActivity(null);
+        PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mActivity.hasWindowFocus());
+        assertFalse(hasTooltip(mTooltipView));
+        activity.finish();
+    }
+
+    @Test
+    public void testTooltipHidesOnWindowFocusChange() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Show a context menu on another widget.
+        mActivity.registerForContextMenu(mNoTooltipView);
+        mActivityRule.runOnUiThread(() -> mNoTooltipView.showContextMenu(0, 0));
+
+        PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mTooltipView.hasWindowFocus());
+        mInstrumentation.waitForIdleSync();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by long click.
+
+    @Test
+    public void testShortClickDoesNotShowTooltip() throws Throwable {
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testPerformLongClickShowsTooltipImmediately() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipBlockedByLongClickListener() throws Throwable {
+        mTooltipView.setOnLongClickListener(v -> true);
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipBlockedByContextMenu() throws Throwable {
+        mActivity.registerForContextMenu(mTooltipView);
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnNonClickableView() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipStaysOnMouseMove() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-click-triggered tooltip stays while the mouse to another widget.
+        injectHoverMove(mNoTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesAfterUp() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-click-triggered tooltip hides after ACTION_UP (with a delay).
+        waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnClick() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnClickElsewhere() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnKey() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by long key press.
+
+    @Test
+    public void testShortKeyPressDoesNotShowTooltip() throws Throwable {
+        injectKeyPress(null, KeyEvent.KEYCODE_ENTER, 0);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectKeyPress(mTooltipView, KeyEvent.KEYCODE_ENTER, 0);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongArbitraryKeyPressDoesNotShowTooltip() throws Throwable {
+        injectLongKeyPress(mTooltipView, KeyEvent.KEYCODE_0);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressWithoutFocusDoesNotShowTooltip() throws Throwable {
+        injectLongEnter(null);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressOnAnotherViewDoesNotShowTooltip() throws Throwable {
+        injectLongEnter(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnNonClickableView() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipStaysOnMouseMove() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-keypress-triggered tooltip stays while the mouse to another widget.
+        injectHoverMove(mNoTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesAfterUp() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-keypress-triggered tooltip hides after ACTION_UP (with a delay).
+        waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnClick() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnClickElsewhere() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnKey() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by mouse hover.
+
+    @Test
+    public void testMouseClickDoesNotShowTooltip() throws Throwable {
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_DOWN, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_PRESS, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_RELEASE, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_UP, 0, 0));
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverDoesNotShowTooltipImmediately() throws Throwable {
+        injectHoverMove(mTooltipView, 0, 0);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 1, 1);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 2, 2);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverExitCancelsPendingTooltip() throws Throwable {
+        injectHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipStaysOnMouseMove() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView, 1, 1);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 2, 2);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnExit() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip hides once the mouse moves out of the widget.
+        injectHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnClick() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnClickOnElsewhere() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnKey() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnTimeout() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        waitOut(ViewConfiguration.getHoverTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnShortTimeout() throws Throwable {
+        requestLowProfileSystemUi();
+
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        waitOut(ViewConfiguration.getHoverTooltipHideShortTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipWithHoverListener() throws Throwable {
+        mTooltipView.setOnHoverListener((v, event) -> true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipUnsetWhileHovering() throws Throwable {
+        injectHoverMove(mTooltipView);
+        setTooltip(mTooltipView, null);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipDisableWhileHovering() throws Throwable {
+        injectHoverMove(mTooltipView);
+        mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipFromParent() throws Throwable {
+        // Hover listeners should not interfere with tooltip dispatch.
+        mNoTooltipView.setOnHoverListener((v, event) -> true);
+        mTooltipView.setOnHoverListener((v, event) -> true);
+
+        setTooltip(mTopmostView, "tooltip");
+
+        // Hover over a child with a tooltip works normally.
+        injectLongHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTopmostView));
+        assertTrue(hasTooltip(mTooltipView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Hover over a child with no tooltip triggers a tooltip on its parent.
+        injectLongHoverMove(mNoTooltipView2);
+        assertFalse(hasTooltip(mNoTooltipView2));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Same but the child is and empty view group.
+        injectLongHoverMove(mEmptyGroup);
+        assertFalse(hasTooltip(mEmptyGroup));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Hover over a grandchild with no tooltip triggers a tooltip on its grandparent.
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+        assertTrue(hasTooltip(mTopmostView));
+        // Move to another child one level up, the tooltip stays.
+        injectHoverMove(mNoTooltipView2);
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Set a tooltip on the intermediate parent, now it is showing tooltips.
+        setTooltip(mGroupView, "tooltip");
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+        assertFalse(hasTooltip(mTopmostView));
+        assertTrue(hasTooltip(mGroupView));
+
+        // Move out of this group, the tooltip is now back on the grandparent.
+        injectLongHoverMove(mNoTooltipView2);
+        assertFalse(hasTooltip(mGroupView));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipRemoveWhileWaiting() throws Throwable {
+        // Remove the view while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mTooltipView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mGroupView, mTooltipView);
+
+        // Remove and re-add the view while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mTooltipView);
+        addView(mGroupView, mTooltipView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Remove the view's parent while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mGroupView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mTopmostView, mGroupView);
+
+        // Remove and re-add view's parent while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mGroupView);
+        addView(mTopmostView, mGroupView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipRemoveWhileShowing() throws Throwable {
+        // Remove the view while showing the tooltip.
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+        removeView(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mGroupView, mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Remove the view's parent while showing the tooltip.
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+        removeView(mGroupView);
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mTopmostView, mGroupView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/TouchDelegateTest.java b/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
index 47fe6c6..1fd3d8c 100644
--- a/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
+++ b/tests/tests/view/src/android/view/cts/TouchDelegateTest.java
@@ -16,12 +16,18 @@
 
 package android.view.cts;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.MotionEvent;
 import android.view.TouchDelegate;
 import android.view.View;
@@ -29,78 +35,46 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 
-public class TouchDelegateTest extends ActivityInstrumentationTestCase2<MockActivity> {
-    private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
-    private static final int ACTION_DOWN = MotionEvent.ACTION_DOWN;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TouchDelegateTest {
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private Button mButton;
-    private Rect mRect;
 
-    private int mXInside;
-    private int mYInside;
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule =
+            new ActivityTestRule<>(MockActivity.class);
 
-    private Exception mException;
-
-    public TouchDelegateTest() {
-        super("android.view.cts", MockActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() throws Throwable {
+        mActivity = mActivityRule.getActivity();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
 
         mButton = new Button(mActivity);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                try {
-                    mActivity.addContentView(mButton, new LinearLayout.LayoutParams(WRAP_CONTENT,
-                                                                                    WRAP_CONTENT));
-                } catch (Exception e) {
-                    mException = e;
-                }
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mActivity.addContentView(
+                mButton, new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)));
         mInstrumentation.waitForIdleSync();
-
-        if(mException != null) {
-            throw mException;
-        }
-
-        int right = mButton.getRight();
-        int bottom = mButton.getBottom();
-        mXInside = (mButton.getLeft() + right) / 3;
-        mYInside = (mButton.getTop() + bottom) / 3;
-
-        mRect = new Rect();
-        mButton.getHitRect(mRect);
     }
 
     @UiThreadTest
+    @Test
     public void testOnTouchEvent() {
         // test callback of onTouchEvent
-        View view = new View(mActivity);
-        MockTouchDelegate touchDelegate = new MockTouchDelegate(mRect, mButton);
+        final View view = new View(mActivity);
+        final TouchDelegate touchDelegate = mock(TouchDelegate.class);
         view.setTouchDelegate(touchDelegate);
-        assertFalse(touchDelegate.mOnTouchEventCalled);
-        view.onTouchEvent(MotionEvent.obtain(0, 0, ACTION_DOWN, mXInside, mYInside, 0));
-        assertTrue(touchDelegate.mOnTouchEventCalled);
-    }
 
-    class MockTouchDelegate extends TouchDelegate {
-        private boolean mOnTouchEventCalled;
+        final int xInside = (mButton.getLeft() + mButton.getRight()) / 3;
+        final int yInside = (mButton.getTop() + mButton.getBottom()) / 3;
 
-        public MockTouchDelegate(Rect bounds, View delegateView) {
-            super(bounds, delegateView);
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            mOnTouchEventCalled = true;
-            return true;
-        }
+        view.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, xInside, yInside, 0));
+        verify(touchDelegate, times(1)).onTouchEvent(any(MotionEvent.class));
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
index ed6b0c1..774aadb 100644
--- a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
+++ b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
@@ -16,15 +16,25 @@
 
 package android.view.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
-import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link VelocityTracker}.
  */
-public class VelocityTrackerTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VelocityTrackerTest {
     private static final String TAG = "VelocityTrackerTest";
 
     private static final float TOLERANCE_EXACT = 0.01f;
@@ -41,9 +51,8 @@
     private float mVx, mVy;
     private float mAx, mAy;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mVelocityTracker = VelocityTracker.obtain();
         mTime = 1000;
         mLastTime = 0;
@@ -55,17 +64,18 @@
         mAy = 0;
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public void teardown() {
         mVelocityTracker.recycle();
     }
 
+    @Test
     public void testNoMovement() {
         move(100, 10);
         assertVelocity(TOLERANCE_EXACT, "Expect exact bound when no movement occurs.");
     }
 
+    @Test
     public void testLinearMovement() {
         mVx = 2.0f;
         mVy = -4.0f;
@@ -73,6 +83,7 @@
         assertVelocity(TOLERANCE_TIGHT, "Expect tight bound for linear motion.");
     }
 
+    @Test
     public void testAcceleratingMovement() {
         // A very good velocity tracking algorithm will produce a tight bound on
         // simple acceleration.  Certain alternate algorithms will fare less well but
@@ -85,6 +96,7 @@
         assertVelocity(TOLERANCE_WEAK, "Expect weak bound when there is acceleration.");
     }
 
+    @Test
     public void testDeceleratingMovement() {
         // A very good velocity tracking algorithm will produce a tight bound on
         // simple acceleration.  Certain alternate algorithms will fare less well but
@@ -97,6 +109,7 @@
         assertVelocity(TOLERANCE_WEAK, "Expect weak bound when there is deceleration.");
     }
 
+    @Test
     public void testLinearSharpDirectionChange() {
         // After a sharp change of direction we expect the velocity to eventually
         // converge but it might take a moment to get there.
@@ -112,6 +125,7 @@
         assertVelocity(TOLERANCE_TIGHT, "Expect tight bound after 200ms of new direction.");
     }
 
+    @Test
     public void testLinearSharpDirectionChangeAfterALongPause() {
         // Should be able to get a tighter bound if there is a pause before the
         // change of direction.
@@ -127,6 +141,7 @@
                 "Expect tight bound after a 100ms pause and 100ms of new direction.");
     }
 
+    @Test
     public void testChangingAcceleration() {
         // In real circumstances, the acceleration changes continuously throughout a
         // gesture.  Try to model this and see how the algorithm copes.
diff --git a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
index 5fe4aea..8e478a8 100644
--- a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
@@ -16,21 +16,23 @@
 
 package android.view.cts;
 
-import android.content.Context;
-import android.test.InstrumentationTestCase;
+import static org.junit.Assert.assertNotNull;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ViewConfiguration;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ViewConfiguration}.
  */
-public class ViewConfigurationTest extends InstrumentationTestCase {
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
-    @SuppressWarnings("deprecation")
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewConfigurationTest {
+    @Test
     public void testStaticValues() {
         ViewConfiguration.getScrollBarSize();
         ViewConfiguration.getFadingEdgeLength();
@@ -55,14 +57,16 @@
         ViewConfiguration.getDefaultActionModeHideDuration();
     }
 
-    @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
         new ViewConfiguration();
     }
 
+    @Test
     public void testInstanceValues() {
-        ViewConfiguration vc = ViewConfiguration.get(getInstrumentation().getTargetContext());
+        ViewConfiguration vc = ViewConfiguration.get(InstrumentationRegistry.getTargetContext());
         assertNotNull(vc);
+
         vc.getScaledDoubleTapSlop();
         vc.getScaledEdgeSlop();
         vc.getScaledFadingEdgeLength();
@@ -73,6 +77,7 @@
         vc.getScaledOverscrollDistance();
         vc.getScaledPagingTouchSlop();
         vc.getScaledScrollBarSize();
+        vc.getScaledScrollFactor();
         vc.getScaledTouchSlop();
         vc.getScaledWindowTouchSlop();
         vc.hasPermanentMenuKey();
diff --git a/tests/tests/view/src/android/view/cts/ViewDebugTest.java b/tests/tests/view/src/android/view/cts/ViewDebugTest.java
index f6c4043..8af8bd9 100644
--- a/tests/tests/view/src/android/view/cts/ViewDebugTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewDebugTest.java
@@ -17,20 +17,30 @@
 package android.view.cts;
 
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ViewDebug;
 
-public class ViewDebugTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewDebugTest {
+    @Test
     public void testConstructor() {
         new ViewDebug();
     }
 
+    @Test
     public void testRecyclerTracing() {
         // debugging should be disabled on production devices
         assertFalse(ViewDebug.TRACE_RECYCLER);
     }
 
+    @Test
     public void testHierarchyTracing() {
         // debugging should be disabled on production devices
         assertFalse(ViewDebug.TRACE_HIERARCHY);
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
index de1db19..7bad954 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupCtsActivity.java
@@ -17,17 +17,18 @@
 package android.view.cts;
 
 import android.app.Activity;
-import android.cts.util.CTSResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.widget.TextView;
 
-public class ViewGroupCtsActivity extends Activity {
+import com.android.compatibility.common.util.CTSResult;
 
+public class ViewGroupCtsActivity extends Activity {
     public static final String ACTION_INVALIDATE_CHILD = "invalidateChild";
 
     private final Handler mHandler = new Handler();
     private static CTSResult sResult;
+
     public static void setResult(CTSResult result) {
         sResult = result;
     }
@@ -36,7 +37,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(android.view.cts.R.layout.viewgrouptest_stub);
-        TextView textView = (TextView)findViewById(android.view.cts.R.id.viewgrouptest_stub);
+        TextView textView = (TextView) findViewById(android.view.cts.R.id.viewgrouptest_stub);
         textView.setText("test");
     }
 
@@ -46,18 +47,15 @@
 
         String action = getIntent().getAction();
         if (action.equals(ACTION_INVALIDATE_CHILD)) {
-            mHandler.postDelayed(new Runnable() {
-                public void run() {
-                    MockLinearLayout mll =
-                        (MockLinearLayout) findViewById(android.view.cts.R.id.
-                                                                        mocklinearlayout);
-                    if (!mll.mIsInvalidateChildInParentCalled) {
-                        fail();
-                        return;
-                    }
-                    sResult.setResult(CTSResult.RESULT_OK);
-                    finish();
+            mHandler.postDelayed(() -> {
+                MockLinearLayout mll =
+                        (MockLinearLayout) findViewById(R.id.mocklinearlayout);
+                if (!mll.mIsInvalidateChildInParentCalled) {
+                    fail();
+                    return;
                 }
+                sResult.setResult(CTSResult.RESULT_OK);
+                finish();
             }, 2000);
         }
     }
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java b/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
index 886cc81..f1b3ea5 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupOverlayTest.java
@@ -16,78 +16,91 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
 import android.app.Instrumentation;
-import android.content.Context;
 import android.graphics.Color;
 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.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
 import android.view.cts.util.DrawingUtils;
 
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.mockito.Mockito.*;
-
-@SmallTest
-public class ViewGroupOverlayTest extends
-        ActivityInstrumentationTestCase2<ViewGroupOverlayCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewGroupOverlayTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private ViewGroup mViewGroupWithOverlay;
     private ViewGroupOverlay mViewGroupOverlay;
-    private Context mContext;
 
-    public ViewGroupOverlayTest() {
-        super("android.view.cts", ViewGroupOverlayCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewGroupOverlayCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewGroupOverlayCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mViewGroupWithOverlay = (ViewGroup) getActivity().findViewById(R.id.viewgroup_with_overlay);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mViewGroupWithOverlay = (ViewGroup) mActivity.findViewById(R.id.viewgroup_with_overlay);
         mViewGroupOverlay = mViewGroupWithOverlay.getOverlay();
-        mContext = getInstrumentation().getTargetContext();
     }
 
     @Presubmit
+    @Test
     public void testBasics() {
         DrawingUtils.assertAllPixelsOfColor("Default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
         assertNotNull("Overlay is not null", mViewGroupOverlay);
     }
 
-    public void testAddNullView() throws Throwable {
-        try {
-            runTestOnUiThread(() -> mViewGroupOverlay.add((View) null));
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddNullView() {
+        mViewGroupOverlay.add((View) null);
     }
 
-    public void testRemoveNullView() throws Throwable {
-        try {
-            runTestOnUiThread(() -> mViewGroupOverlay.remove((View) null));
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testRemoveNullView() {
+         mViewGroupOverlay.remove((View) null);
     }
 
-    public void testOverlayWithOneView() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithOneView() {
         // Add one colored view to the overlay
-        final View redView = new View(mContext);
+        final View redView = new View(mActivity);
         redView.setBackgroundColor(Color.RED);
         redView.layout(10, 20, 30, 40);
 
-        runTestOnUiThread(() -> mViewGroupOverlay.add(redView));
+        mViewGroupOverlay.add(redView);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
@@ -95,29 +108,28 @@
                 mViewGroupWithOverlay, Color.WHITE, colorRectangles);
 
         // Now remove that view from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewGroupOverlay.remove(redView));
+        mViewGroupOverlay.remove(redView);
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayWithNonOverlappingViews() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithNonOverlappingViews() {
         // Add three views to the overlay
-        final View redView = new View(mContext);
+        final View redView = new View(mActivity);
         redView.setBackgroundColor(Color.RED);
         redView.layout(10, 20, 30, 40);
-        final View greenView = new View(mContext);
+        final View greenView = new View(mActivity);
         greenView.setBackgroundColor(Color.GREEN);
         greenView.layout(60, 30, 90, 50);
-        final View blueView = new View(mContext);
+        final View blueView = new View(mActivity);
         blueView.setBackgroundColor(Color.BLUE);
         blueView.layout(40, 60, 80, 90);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewGroupOverlay.add(redView);
-                    mViewGroupOverlay.add(greenView);
-                    mViewGroupOverlay.add(blueView);
-                });
+        mViewGroupOverlay.add(redView);
+        mViewGroupOverlay.add(greenView);
+        mViewGroupOverlay.add(blueView);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
@@ -127,7 +139,7 @@
                 Color.WHITE, colorRectangles);
 
         // Remove one of the views from the overlay
-        runTestOnUiThread(() -> mViewGroupOverlay.remove(greenView));
+        mViewGroupOverlay.remove(greenView);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
         colorRectangles.add(new Pair<>(new Rect(40, 60, 80, 90), Color.BLUE));
@@ -135,25 +147,23 @@
                 Color.WHITE, colorRectangles);
 
         // Clear all views from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewGroupOverlay.clear());
+        mViewGroupOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
     }
 
-
-    public void testOverlayWithNonOverlappingViewAndDrawable() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithNonOverlappingViewAndDrawable() {
         // Add one view and one drawable to the overlay
-        final View redView = new View(mContext);
+        final View redView = new View(mActivity);
         redView.setBackgroundColor(Color.RED);
         redView.layout(10, 20, 30, 40);
         final Drawable greenDrawable = new ColorDrawable(Color.GREEN);
         greenDrawable.setBounds(60, 30, 90, 50);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewGroupOverlay.add(redView);
-                    mViewGroupOverlay.add(greenDrawable);
-                });
+        mViewGroupOverlay.add(redView);
+        mViewGroupOverlay.add(greenDrawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
@@ -162,32 +172,31 @@
                 mViewGroupWithOverlay, Color.WHITE, colorRectangles);
 
         // Remove the view from the overlay
-        runTestOnUiThread(() -> mViewGroupOverlay.remove(redView));
+        mViewGroupOverlay.remove(redView);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(60, 30, 90, 50), Color.GREEN));
         DrawingUtils.assertAllPixelsOfColor("Overlay with one drawable", mViewGroupWithOverlay,
                 Color.WHITE, colorRectangles);
 
         // Clear everything from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewGroupOverlay.clear());
+        mViewGroupOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayWithOverlappingViews() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithOverlappingViews() {
         // Add two overlapping colored views to the overlay
-        final View redView = new View(mContext);
+        final View redView = new View(mActivity);
         redView.setBackgroundColor(Color.RED);
         redView.layout(10, 20, 60, 40);
-        final View greenView = new View(mContext);
+        final View greenView = new View(mActivity);
         greenView.setBackgroundColor(Color.GREEN);
         greenView.layout(30, 20, 80, 40);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewGroupOverlay.add(redView);
-                    mViewGroupOverlay.add(greenView);
-                });
+        mViewGroupOverlay.add(redView);
+        mViewGroupOverlay.add(greenView);
 
         // Our overlay views overlap in horizontal 30-60 range. Here we test that the
         // second view is the one that is drawn last in that range.
@@ -198,31 +207,30 @@
                 Color.WHITE, colorRectangles);
 
         // Remove the second view from the overlay
-        runTestOnUiThread(() -> mViewGroupOverlay.remove(greenView));
+        mViewGroupOverlay.remove(greenView);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 60, 40), Color.RED));
         DrawingUtils.assertAllPixelsOfColor("Overlay with one drawable", mViewGroupWithOverlay,
                 Color.WHITE, colorRectangles);
 
         // Clear all views from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewGroupOverlay.clear());
+        mViewGroupOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayWithOverlappingViewAndDrawable() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithOverlappingViewAndDrawable() {
         // Add two overlapping colored views to the overlay
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(10, 20, 60, 40);
-        final View greenView = new View(mContext);
+        final View greenView = new View(mActivity);
         greenView.setBackgroundColor(Color.GREEN);
         greenView.layout(30, 20, 80, 40);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewGroupOverlay.add(redDrawable);
-                    mViewGroupOverlay.add(greenView);
-                });
+        mViewGroupOverlay.add(redDrawable);
+        mViewGroupOverlay.add(greenView);
 
         // Our overlay views overlap in horizontal 30-60 range. Even though the green view was
         // added after the red drawable, *all* overlay drawables are drawn after the overlay views.
@@ -234,70 +242,39 @@
                 mViewGroupWithOverlay, Color.WHITE, colorRectangles);
 
         // Remove the drawable from the overlay
-        runTestOnUiThread(() -> mViewGroupOverlay.remove(redDrawable));
+        mViewGroupOverlay.remove(redDrawable);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(30, 20, 80, 40), Color.GREEN));
         DrawingUtils.assertAllPixelsOfColor("Overlay with one view", mViewGroupWithOverlay,
                 Color.WHITE, colorRectangles);
 
         // Clear all views from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewGroupOverlay.clear());
+        mViewGroupOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewGroupWithOverlay,
                 Color.WHITE, null);
     }
 
+    @Test
     public void testOverlayViewNoClicks() throws Throwable {
         // Add one colored view with mock click listener to the overlay
-        final View redView = new View(mContext);
+        final View redView = new View(mActivity);
         redView.setBackgroundColor(Color.RED);
         final View.OnClickListener mockClickListener = mock(View.OnClickListener.class);
         redView.setOnClickListener(mockClickListener);
         redView.layout(10, 20, 30, 40);
 
-        runTestOnUiThread(() -> mViewGroupOverlay.add(redView));
+        mActivityRule.runOnUiThread(() -> mViewGroupOverlay.add(redView));
 
-        // If we call performClick or dispatchTouchEvent on the view that we've added to the
-        // overlay, that will invoke the listener that we've registered. But here we need to
-        // test that such a view doesn't get clicks in the regular event processing pipeline
-        // that handles individual events at the screen level. Use Instrumentation to emulate
-        // the high-level sequence of events instead.
-        final int[] viewGroupOnScreenXY = new int[2];
-        mViewGroupWithOverlay.getLocationOnScreen(viewGroupOnScreenXY);
-
-        // Compute the coordinates for emulating a tap in the center of the view we've added
-        // to the overlay.
-        final int emulatedTapX = viewGroupOnScreenXY[0] + redView.getLeft()
-                + redView.getWidth() / 2;
-        final int emulatedTapY = viewGroupOnScreenXY[1] + redView.getTop()
-                + redView.getHeight() / 2;
-        final Instrumentation instrumentation = 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();
+        // Emulate a tap in the center of the view we've added to the overlay
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mViewGroupWithOverlay);
 
         // Verify that our mock listener hasn't been called
         verify(mockClickListener, never()).onClick(any(View.class));
     }
 
-    public void testOverlayReparenting() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayReparenting() {
         // Find the view that we're about to add to our overlay
         final View level2View = mViewGroupWithOverlay.findViewById(R.id.level2);
         final View level3View = level2View.findViewById(R.id.level3);
@@ -305,11 +282,8 @@
         assertTrue(level2View == level3View.getParent());
 
         // Set the fill of this view to red
-        runTestOnUiThread(
-                () -> {
-                    level3View.setBackgroundColor(Color.RED);
-                    mViewGroupOverlay.add(level3View);
-                });
+        level3View.setBackgroundColor(Color.RED);
+        mViewGroupOverlay.add(level3View);
 
         // At this point we expect the view that was added to the overlay to have been removed
         // from its original parent
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index dba02ee..395a4a7 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -16,10 +16,22 @@
 
 package android.view.cts;
 
+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.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
-import android.cts.util.CTSResult;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
@@ -29,7 +41,11 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.SparseArray;
@@ -43,10 +59,8 @@
 import android.view.View;
 import android.view.View.BaseSavedState;
 import android.view.View.MeasureSpec;
-import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewGroup.OnHierarchyChangeListener;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -57,600 +71,613 @@
 import android.view.cts.util.XmlUtils;
 import android.widget.TextView;
 
+import com.android.compatibility.common.util.CTSResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
 import java.util.ArrayList;
 
-public class ViewGroupTest extends InstrumentationTestCase implements CTSResult{
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewGroupTest implements CTSResult {
     private Context mContext;
     private MotionEvent mMotionEvent;
     private int mResultCode;
 
-    private Sync mSync = new Sync();
+    private MockViewGroup mMockViewGroup;
+    private TextView mTextView;
+    private MockTextView mMockTextView;
+
+    private final Sync mSync = new Sync();
     private static class Sync {
         boolean mHasNotify;
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mMockViewGroup = new MockViewGroup(mContext);
+        mTextView = new TextView(mContext);
+        mMockTextView = new MockTextView(mContext);
     }
 
+    @Test
     public void testConstructor() {
         new MockViewGroup(mContext);
         new MockViewGroup(mContext, null);
         new MockViewGroup(mContext, null, 0);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddFocusables() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setFocusable(true);
+        mMockViewGroup.setFocusable(true);
 
-        ArrayList<View> list = new ArrayList<View>();
-        TextView textView = new TextView(mContext);
-        list.add(textView);
-        vg.addView(textView);
-        vg.addFocusables(list, 0);
+        ArrayList<View> list = new ArrayList<>();
+        list.add(mTextView);
+        mMockViewGroup.addView(mTextView);
+        mMockViewGroup.addFocusables(list, 0);
 
         assertEquals(2, list.size());
 
-        list = new ArrayList<View>();
-        list.add(textView);
-        vg.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        vg.setFocusable(false);
-        vg.addFocusables(list, 0);
+        list = new ArrayList<>();
+        list.add(mTextView);
+        mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        mMockViewGroup.setFocusable(false);
+        mMockViewGroup.addFocusables(list, 0);
         assertEquals(1, list.size());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddStatesFromChildren() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
-        vg.addView(textView);
-        assertFalse(vg.addStatesFromChildren());
+        mMockViewGroup.addView(mTextView);
+        assertFalse(mMockViewGroup.addStatesFromChildren());
 
-        vg.setAddStatesFromChildren(true);
-        textView.performClick();
-        assertTrue(vg.addStatesFromChildren());
-        assertTrue(vg.isDrawableStateChangedCalled);
+        mMockViewGroup.setAddStatesFromChildren(true);
+        mTextView.performClick();
+        assertTrue(mMockViewGroup.addStatesFromChildren());
+        assertTrue(mMockViewGroup.isDrawableStateChangedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddTouchables() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setFocusable(true);
+        mMockViewGroup.setFocusable(true);
 
-        ArrayList<View> list = new ArrayList<View>();
-        TextView textView = new TextView(mContext);
-        textView.setVisibility(View.VISIBLE);
-        textView.setClickable(true);
-        textView.setEnabled(true);
+        ArrayList<View> list = new ArrayList<>();
+        mTextView.setVisibility(View.VISIBLE);
+        mTextView.setClickable(true);
+        mTextView.setEnabled(true);
 
-        list.add(textView);
-        vg.addView(textView);
-        vg.addTouchables(list);
+        list.add(mTextView);
+        mMockViewGroup.addView(mTextView);
+        mMockViewGroup.addTouchables(list);
 
         assertEquals(2, list.size());
 
-        View v = vg.getChildAt(0);
-        assertSame(textView, v);
+        View v = mMockViewGroup.getChildAt(0);
+        assertSame(mTextView, v);
 
-        v = vg.getChildAt(-1);
+        v = mMockViewGroup.getChildAt(-1);
         assertNull(v);
 
-        v = vg.getChildAt(1);
+        v = mMockViewGroup.getChildAt(1);
         assertNull(v);
 
-        v = vg.getChildAt(100);
+        v = mMockViewGroup.getChildAt(100);
         assertNull(v);
 
-        v = vg.getChildAt(-100);
+        v = mMockViewGroup.getChildAt(-100);
         assertNull(v);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddView() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
-
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
+        mMockViewGroup.addView(mTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithParaViewInt() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
-
-        vg.addView(textView, -1);
-        assertEquals(1, vg.getChildCount());
+        mMockViewGroup.addView(mTextView, -1);
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithParaViewLayoutPara() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
+        mMockViewGroup.addView(mTextView, new ViewGroup.LayoutParams(100, 200));
 
-        vg.addView(textView, new ViewGroup.LayoutParams(100, 200));
-
-        assertEquals(1, vg.getChildCount());
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithParaViewIntInt() {
         final int width = 100;
         final int height = 200;
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
 
-        assertEquals(0, vg.getChildCount());
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        vg.addView(textView, width, height);
-        assertEquals(width, textView.getLayoutParams().width);
-        assertEquals(height, textView.getLayoutParams().height);
+        mMockViewGroup.addView(mTextView, width, height);
+        assertEquals(width, mTextView.getLayoutParams().width);
+        assertEquals(height, mTextView.getLayoutParams().height);
 
-        assertEquals(1, vg.getChildCount());
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWidthParaViewIntLayoutParam() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
+        mMockViewGroup.addView(mTextView, -1, new ViewGroup.LayoutParams(100, 200));
 
-        vg.addView(textView, -1, new ViewGroup.LayoutParams(100, 200));
-
-        assertEquals(1, vg.getChildCount());
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewInLayout() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
-
-        assertTrue(vg.isRequestLayoutCalled);
-        vg.isRequestLayoutCalled = false;
-        assertTrue(vg.addViewInLayout(textView, -1, new ViewGroup.LayoutParams(100, 200)));
-        assertEquals(1, vg.getChildCount());
+        assertTrue(mMockViewGroup.isRequestLayoutCalled);
+        mMockViewGroup.isRequestLayoutCalled = false;
+        assertTrue(mMockViewGroup.addViewInLayout(
+                mTextView, -1, new ViewGroup.LayoutParams(100, 200)));
+        assertEquals(1, mMockViewGroup.getChildCount());
         // check that calling addViewInLayout() does not trigger a
         // requestLayout() on this ViewGroup
-        assertFalse(vg.isRequestLayoutCalled);
+        assertFalse(mMockViewGroup.isRequestLayoutCalled);
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testAttachLayoutAnimationParameters() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10);
 
-        vg.attachLayoutAnimationParameters(null, param, 1, 2);
+        mMockViewGroup.attachLayoutAnimationParameters(null, param, 1, 2);
         assertEquals(2, param.layoutAnimationParameters.count);
         assertEquals(1, param.layoutAnimationParameters.index);
     }
 
+    @UiThreadTest
+    @Test
     public void testAttachViewToParent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setFocusable(true);
-        assertEquals(0, vg.getChildCount());
+        mMockViewGroup.setFocusable(true);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
         ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10);
 
-        TextView child = new TextView(mContext);
-        child.setFocusable(true);
-        vg.attachViewToParent(child, -1, param);
-        assertSame(vg, child.getParent());
-        assertEquals(1, vg.getChildCount());
-        assertSame(child, vg.getChildAt(0));
+        mTextView.setFocusable(true);
+        mMockViewGroup.attachViewToParent(mTextView, -1, param);
+        assertSame(mMockViewGroup, mTextView.getParent());
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertSame(mTextView, mMockViewGroup.getChildAt(0));
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewInLayoutWithParamViewIntLayB() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        assertEquals(0, vg.getChildCount());
+        assertTrue(mMockViewGroup.isRequestLayoutCalled);
+        mMockViewGroup.isRequestLayoutCalled = false;
+        assertTrue(mMockViewGroup.addViewInLayout(
+                mTextView, -1, new ViewGroup.LayoutParams(100, 200), true));
 
-        assertTrue(vg.isRequestLayoutCalled);
-        vg.isRequestLayoutCalled = false;
-        assertTrue(vg.addViewInLayout(textView, -1, new ViewGroup.LayoutParams(100, 200), true));
-
-        assertEquals(1, vg.getChildCount());
+        assertEquals(1, mMockViewGroup.getChildCount());
         // check that calling addViewInLayout() does not trigger a
         // requestLayout() on this ViewGroup
-        assertFalse(vg.isRequestLayoutCalled);
+        assertFalse(mMockViewGroup.isRequestLayoutCalled);
+        assertTrue(mMockViewGroup.isOnViewAddedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testBringChildToFront() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         TextView textView1 = new TextView(mContext);
         TextView textView2 = new TextView(mContext);
 
-        assertEquals(0, vg.getChildCount());
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        vg.addView(textView1);
-        vg.addView(textView2);
-        assertEquals(2, vg.getChildCount());
+        mMockViewGroup.addView(textView1);
+        mMockViewGroup.addView(textView2);
+        assertEquals(2, mMockViewGroup.getChildCount());
 
-        vg.bringChildToFront(textView1);
-        assertEquals(vg, textView1.getParent());
-        assertEquals(2, vg.getChildCount());
-        assertNotNull(vg.getChildAt(0));
-        assertSame(textView2, vg.getChildAt(0));
+        mMockViewGroup.bringChildToFront(textView1);
+        assertEquals(mMockViewGroup, textView1.getParent());
+        assertEquals(2, mMockViewGroup.getChildCount());
+        assertNotNull(mMockViewGroup.getChildAt(0));
+        assertSame(textView2, mMockViewGroup.getChildAt(0));
 
-        vg.bringChildToFront(textView2);
-        assertEquals(vg, textView2.getParent());
-        assertEquals(2, vg.getChildCount());
-        assertNotNull(vg.getChildAt(0));
-        assertSame(textView1, vg.getChildAt(0));
+        mMockViewGroup.bringChildToFront(textView2);
+        assertEquals(mMockViewGroup, textView2.getParent());
+        assertEquals(2, mMockViewGroup.getChildCount());
+        assertNotNull(mMockViewGroup.getChildAt(0));
+        assertSame(textView1, mMockViewGroup.getChildAt(0));
     }
 
+    @UiThreadTest
+    @Test
     public void testCanAnimate() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
-        assertFalse(vg.canAnimate());
+        assertFalse(mMockViewGroup.canAnimate());
 
         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
         LayoutAnimationController la = new LayoutAnimationController(animation);
-        vg.setLayoutAnimation(la);
-        assertTrue(vg.canAnimate());
+        mMockViewGroup.setLayoutAnimation(la);
+        assertTrue(mMockViewGroup.canAnimate());
     }
 
+    @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
-        MockViewGroup view = new MockViewGroup(mContext);
-        assertFalse(view.checkLayoutParams(null));
+        assertFalse(mMockViewGroup.checkLayoutParams(null));
 
-        assertTrue(view.checkLayoutParams(new ViewGroup.LayoutParams(100, 200)));
+        assertTrue(mMockViewGroup.checkLayoutParams(new ViewGroup.LayoutParams(100, 200)));
     }
 
+    @UiThreadTest
+    @Test
     public void testChildDrawableStateChanged() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setAddStatesFromChildren(true);
+        mMockViewGroup.setAddStatesFromChildren(true);
 
-        vg.childDrawableStateChanged(null);
-        assertTrue(vg.isRefreshDrawableStateCalled);
+        mMockViewGroup.childDrawableStateChanged(null);
+        assertTrue(mMockViewGroup.isRefreshDrawableStateCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testCleanupLayoutState() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertTrue(mTextView.isLayoutRequested());
 
-        assertTrue(textView.isLayoutRequested());
-
-        vg.cleanupLayoutState(textView);
-        assertFalse(textView.isLayoutRequested());
+        mMockViewGroup.cleanupLayoutState(mTextView);
+        assertFalse(mTextView.isLayoutRequested());
     }
 
+    @UiThreadTest
+    @Test
     public void testClearChildFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        mMockViewGroup.addView(mTextView);
+        mMockViewGroup.requestChildFocus(mTextView, null);
 
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
+        View focusedView = mMockViewGroup.getFocusedChild();
+        assertSame(mTextView, focusedView);
 
-        View focusedView = vg.getFocusedChild();
-        assertSame(textView, focusedView);
-
-        vg.clearChildFocus(textView);
-        assertNull(vg.getFocusedChild());
+        mMockViewGroup.clearChildFocus(mTextView);
+        assertNull(mMockViewGroup.getFocusedChild());
     }
 
+    @UiThreadTest
+    @Test
     public void testClearDisappearingChildren() {
-
         Canvas canvas = new Canvas();
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
         child.setAnimation(new MockAnimation());
-        vg.addView(child);
-        assertEquals(1, vg.getChildCount());
+        mMockViewGroup.addView(child);
+        assertEquals(1, mMockViewGroup.getChildCount());
 
         assertNotNull(child.getAnimation());
-        vg.dispatchDraw(canvas);
-        assertEquals(1, vg.drawChildCalledTime);
+        mMockViewGroup.dispatchDraw(canvas);
+        assertEquals(1, mMockViewGroup.drawChildCalledTime);
 
         child.setAnimation(new MockAnimation());
-        vg.removeAllViewsInLayout();
+        mMockViewGroup.removeAllViewsInLayout();
 
-        vg.drawChildCalledTime = 0;
-        vg.dispatchDraw(canvas);
-        assertEquals(1, vg.drawChildCalledTime);
+        mMockViewGroup.drawChildCalledTime = 0;
+        mMockViewGroup.dispatchDraw(canvas);
+        assertEquals(1, mMockViewGroup.drawChildCalledTime);
 
         child.setAnimation(new MockAnimation());
-        vg.clearDisappearingChildren();
+        mMockViewGroup.clearDisappearingChildren();
 
-        vg.drawChildCalledTime = 0;
-        vg.dispatchDraw(canvas);
-        assertEquals(0, vg.drawChildCalledTime);
+        mMockViewGroup.drawChildCalledTime = 0;
+        mMockViewGroup.dispatchDraw(canvas);
+        assertEquals(0, mMockViewGroup.drawChildCalledTime);
     }
 
+    @UiThreadTest
+    @Test
     public void testClearFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
-        vg.clearFocus();
-        assertTrue(textView.isClearFocusCalled);
+        mMockViewGroup.addView(mMockTextView);
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        mMockViewGroup.clearFocus();
+        assertTrue(mMockTextView.isClearFocusCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testDetachAllViewsFromParent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
-
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
-        assertSame(vg, textView.getParent());
-        vg.detachAllViewsFromParent();
-        assertEquals(0, vg.getChildCount());
-        assertNull(textView.getParent());
+        mMockViewGroup.addView(mTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertSame(mMockViewGroup, mTextView.getParent());
+        mMockViewGroup.detachAllViewsFromParent();
+        assertEquals(0, mMockViewGroup.getChildCount());
+        assertNull(mTextView.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testDetachViewFromParent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        mMockViewGroup.addView(mTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
 
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
+        mMockViewGroup.detachViewFromParent(0);
 
-        vg.detachViewFromParent(0);
-
-        assertEquals(0, vg.getChildCount());
-        assertNull(textView.getParent());
+        assertEquals(0, mMockViewGroup.getChildCount());
+        assertNull(mTextView.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testDetachViewFromParentWithParamView() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        mMockViewGroup.addView(mTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
+        assertSame(mMockViewGroup, mTextView.getParent());
 
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
-        assertSame(vg, textView.getParent());
+        mMockViewGroup.detachViewFromParent(mTextView);
 
-        vg.detachViewFromParent(textView);
-
-        assertEquals(0, vg.getChildCount());
-        assertNull(vg.getParent());
+        assertEquals(0, mMockViewGroup.getChildCount());
+        assertNull(mMockViewGroup.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testDetachViewsFromParent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         TextView textView1 = new TextView(mContext);
         TextView textView2 = new TextView(mContext);
         TextView textView3 = new TextView(mContext);
 
-        vg.addView(textView1);
-        vg.addView(textView2);
-        vg.addView(textView3);
-        assertEquals(3, vg.getChildCount());
+        mMockViewGroup.addView(textView1);
+        mMockViewGroup.addView(textView2);
+        mMockViewGroup.addView(textView3);
+        assertEquals(3, mMockViewGroup.getChildCount());
 
-        vg.detachViewsFromParent(0, 2);
+        mMockViewGroup.detachViewsFromParent(0, 2);
 
-        assertEquals(1, vg.getChildCount());
+        assertEquals(1, mMockViewGroup.getChildCount());
         assertNull(textView1.getParent());
         assertNull(textView2.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchDraw() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         Canvas canvas = new Canvas();
 
-        vg.draw(canvas);
-        assertTrue(vg.isDispatchDrawCalled);
-        assertSame(canvas, vg.canvas);
+        mMockViewGroup.draw(canvas);
+        assertTrue(mMockViewGroup.isDispatchDrawCalled);
+        assertSame(canvas, mMockViewGroup.canvas);
     }
 
-    @SuppressWarnings("unchecked")
+    @UiThreadTest
+    @Test
     public void testDispatchFreezeSelfOnly() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setId(1);
-        vg.setSaveEnabled(true);
+        mMockViewGroup.setId(1);
+        mMockViewGroup.setSaveEnabled(true);
 
         SparseArray container = new SparseArray();
         assertEquals(0, container.size());
-        vg.dispatchFreezeSelfOnly(container);
+        mMockViewGroup.dispatchFreezeSelfOnly(container);
         assertEquals(1, container.size());
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchKeyEvent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
-        assertFalse(vg.dispatchKeyEvent(event));
+        assertFalse(mMockViewGroup.dispatchKeyEvent(event));
 
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
-        textView.layout(1, 1, 100, 100);
+        mMockViewGroup.addView(mMockTextView);
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        mMockTextView.layout(1, 1, 100, 100);
 
-        assertTrue(vg.dispatchKeyEvent(event));
+        assertTrue(mMockViewGroup.dispatchKeyEvent(event));
     }
 
-    @SuppressWarnings("unchecked")
+    @UiThreadTest
+    @Test
     public void testDispatchSaveInstanceState() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setId(2);
-        vg.setSaveEnabled(true);
-        MockTextView textView = new MockTextView(mContext);
-        textView.setSaveEnabled(true);
-        textView.setId(1);
-        vg.addView(textView);
+        mMockViewGroup.setId(2);
+        mMockViewGroup.setSaveEnabled(true);
+        mMockTextView.setSaveEnabled(true);
+        mMockTextView.setId(1);
+        mMockViewGroup.addView(mMockTextView);
 
         SparseArray array = new SparseArray();
-        vg.dispatchSaveInstanceState(array);
+        mMockViewGroup.dispatchSaveInstanceState(array);
 
         assertTrue(array.size() > 0);
         assertNotNull(array.get(2));
 
         array = new SparseArray();
-        vg.dispatchRestoreInstanceState(array);
-        assertTrue(textView.isDispatchRestoreInstanceStateCalled);
+        mMockViewGroup.dispatchRestoreInstanceState(array);
+        assertTrue(mMockTextView.isDispatchRestoreInstanceStateCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchSetPressed() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        mMockViewGroup.addView(mMockTextView);
 
-        vg.dispatchSetPressed(true);
-        assertTrue(textView.isPressed());
+        mMockViewGroup.dispatchSetPressed(true);
+        assertTrue(mMockTextView.isPressed());
 
-        vg.dispatchSetPressed(false);
-        assertFalse(textView.isPressed());
+        mMockViewGroup.dispatchSetPressed(false);
+        assertFalse(mMockTextView.isPressed());
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchSetSelected() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        mMockViewGroup.addView(mMockTextView);
 
-        vg.dispatchSetSelected(true);
-        assertTrue(textView.isSelected());
+        mMockViewGroup.dispatchSetSelected(true);
+        assertTrue(mMockTextView.isSelected());
 
-        vg.dispatchSetSelected(false);
-        assertFalse(textView.isSelected());
+        mMockViewGroup.dispatchSetSelected(false);
+        assertFalse(mMockTextView.isSelected());
     }
 
-    @SuppressWarnings("unchecked")
+    @UiThreadTest
+    @Test
     public void testDispatchThawSelfOnly() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setId(1);
+        mMockViewGroup.setId(1);
         SparseArray array = new SparseArray();
         array.put(1, BaseSavedState.EMPTY_STATE);
 
-        vg.dispatchThawSelfOnly(array);
-        assertTrue(vg.isOnRestoreInstanceStateCalled);
-
+        mMockViewGroup.dispatchThawSelfOnly(array);
+        assertTrue(mMockViewGroup.isOnRestoreInstanceStateCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchTouchEvent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
         DisplayMetrics metrics = new DisplayMetrics();
         WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         Display d = wm.getDefaultDisplay();
         d.getMetrics(metrics);
         int screenWidth = metrics.widthPixels;
         int screenHeight = metrics.heightPixels;
-        vg.layout(0, 0, screenWidth, screenHeight);
-        vg.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight));
+        mMockViewGroup.layout(0, 0, screenWidth, screenHeight);
+        mMockViewGroup.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight));
 
-        MockTextView textView = new MockTextView(mContext);
         mMotionEvent = null;
-        textView.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                mMotionEvent = event;
-                return true;
-            }
+        mMockTextView.setOnTouchListener((View v, MotionEvent event) -> {
+            mMotionEvent = event;
+            return true;
         });
 
-        textView.setVisibility(View.VISIBLE);
-        textView.setEnabled(true);
+        mMockTextView.setVisibility(View.VISIBLE);
+        mMockTextView.setEnabled(true);
 
-        vg.addView(textView, new LayoutParams(screenWidth, screenHeight));
+        mMockViewGroup.addView(mMockTextView, new LayoutParams(screenWidth, screenHeight));
 
-        vg.requestDisallowInterceptTouchEvent(true);
+        mMockViewGroup.requestDisallowInterceptTouchEvent(true);
         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
                 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN,
                 screenWidth / 2, screenHeight / 2, 0);
 
-        assertFalse(vg.dispatchTouchEvent(me));
+        assertFalse(mMockViewGroup.dispatchTouchEvent(me));
         assertNull(mMotionEvent);
 
-        textView.layout(0, 0, screenWidth, screenHeight);
-        assertTrue(vg.dispatchTouchEvent(me));
+        mMockTextView.layout(0, 0, screenWidth, screenHeight);
+        assertTrue(mMockViewGroup.dispatchTouchEvent(me));
         assertSame(me, mMotionEvent);
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchTrackballEvent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
                 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100,
                 0);
-        assertFalse(vg.dispatchTrackballEvent(me));
+        assertFalse(mMockViewGroup.dispatchTrackballEvent(me));
 
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
-        textView.layout(1, 1, 100, 100);
-        vg.requestChildFocus(textView, null);
-        assertTrue(vg.dispatchTrackballEvent(me));
+        mMockViewGroup.addView(mMockTextView);
+        mMockTextView.layout(1, 1, 100, 100);
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        assertTrue(mMockViewGroup.dispatchTrackballEvent(me));
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchUnhandledMove() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        assertFalse(vg.dispatchUnhandledMove(textView, View.FOCUS_DOWN));
+        assertFalse(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN));
 
-        vg.addView(textView);
-        textView.layout(1, 1, 100, 100);
-        vg.requestChildFocus(textView, null);
-        assertTrue(vg.dispatchUnhandledMove(textView, View.FOCUS_DOWN));
+        mMockViewGroup.addView(mMockTextView);
+        mMockTextView.layout(1, 1, 100, 100);
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        assertTrue(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN));
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchWindowFocusChanged() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
+        mMockViewGroup.addView(mMockTextView);
+        mMockTextView.setPressed(true);
+        assertTrue(mMockTextView.isPressed());
 
-        vg.addView(textView);
-        textView.setPressed(true);
-        assertTrue(textView.isPressed());
-
-        vg.dispatchWindowFocusChanged(false);
-        assertFalse(textView.isPressed());
+        mMockViewGroup.dispatchWindowFocusChanged(false);
+        assertFalse(mMockTextView.isPressed());
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchWindowVisibilityChanged() {
         int expected = 10;
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
 
-        vg.addView(textView);
-        vg.dispatchWindowVisibilityChanged(expected);
-        assertEquals(expected, textView.visibility);
+        mMockViewGroup.addView(mMockTextView);
+        mMockViewGroup.dispatchWindowVisibilityChanged(expected);
+        assertEquals(expected, mMockTextView.visibility);
     }
 
+    @UiThreadTest
+    @Test
     public void testDrawableStateChanged() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        textView.setDuplicateParentStateEnabled(true);
+        mMockTextView.setDuplicateParentStateEnabled(true);
 
-        vg.addView(textView);
-        vg.setAddStatesFromChildren(false);
-        vg.drawableStateChanged();
-        assertTrue(textView.mIsRefreshDrawableStateCalled);
+        mMockViewGroup.addView(mMockTextView);
+        mMockViewGroup.setAddStatesFromChildren(false);
+        mMockViewGroup.drawableStateChanged();
+        assertTrue(mMockTextView.mIsRefreshDrawableStateCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testDrawChild() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        mMockViewGroup.addView(mMockTextView);
 
         MockCanvas canvas = new MockCanvas();
-        textView.setBackgroundDrawable(new BitmapDrawable(Bitmap.createBitmap(100, 100,
+        mMockTextView.setBackgroundDrawable(new BitmapDrawable(Bitmap.createBitmap(100, 100,
                 Config.ALPHA_8)));
-        assertFalse(vg.drawChild(canvas, textView, 100));
+        assertFalse(mMockViewGroup.drawChild(canvas, mMockTextView, 100));
         // test whether child's draw method is called.
-        assertTrue(textView.isDrawCalled);
+        assertTrue(mMockTextView.isDrawCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testFindFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertNull(mMockViewGroup.findFocus());
+        mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        mMockViewGroup.setFocusable(true);
+        mMockViewGroup.setVisibility(View.VISIBLE);
+        mMockViewGroup.setFocusableInTouchMode(true);
+        assertTrue(mMockViewGroup.requestFocus(1, new Rect()));
 
-        assertNull(vg.findFocus());
-        vg.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        vg.setFocusable(true);
-        vg.setVisibility(View.VISIBLE);
-        vg.setFocusableInTouchMode(true);
-        assertTrue(vg.requestFocus(1, new Rect()));
-
-        assertSame(vg, vg.findFocus());
+        assertSame(mMockViewGroup, mMockViewGroup.findFocus());
     }
 
+    @UiThreadTest
+    @Test
     public void testFitSystemWindows() {
         Rect rect = new Rect(1, 1, 100, 100);
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertFalse(vg.fitSystemWindows(rect));
+        assertFalse(mMockViewGroup.fitSystemWindows(rect));
 
-        vg = new MockViewGroup(mContext, null, 0);
+        mMockViewGroup = new MockViewGroup(mContext, null, 0);
         MockView mv = new MockView(mContext);
-        vg.addView(mv);
-        assertTrue(vg.fitSystemWindows(rect));
+        mMockViewGroup.addView(mv);
+        assertTrue(mMockViewGroup.fitSystemWindows(rect));
     }
 
     static class MockView extends ViewGroup {
@@ -680,75 +707,81 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testFocusableViewAvailable() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockView child = new MockView(mContext);
-        vg.addView(child);
+        mMockViewGroup.addView(child);
 
         child.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-        child.focusableViewAvailable(vg);
+        child.focusableViewAvailable(mMockViewGroup);
 
-        assertTrue(vg.isFocusableViewAvailable);
+        assertTrue(mMockViewGroup.isFocusableViewAvailable);
     }
 
+    @UiThreadTest
+    @Test
     public void testFocusSearch() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
         MockView child = new MockView(mContext);
-        vg.addView(child);
-        child.addView(textView);
-        assertNotNull(child.focusSearch(textView, 1));
-        assertSame(textView, child.focusSearch(textView, 1));
+        mMockViewGroup.addView(child);
+        child.addView(mMockTextView);
+        assertNotNull(child.focusSearch(mMockTextView, 1));
+        assertSame(mMockTextView, child.focusSearch(mMockTextView, 1));
     }
 
+    @UiThreadTest
+    @Test
     public void testGatherTransparentRegion() {
         Region region = new Region();
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        textView.setAnimation(new AlphaAnimation(mContext, null));
-        textView.setVisibility(100);
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
+        mMockTextView.setAnimation(new AlphaAnimation(mContext, null));
+        mMockTextView.setVisibility(100);
+        mMockViewGroup.addView(mMockTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
 
-        assertTrue(vg.gatherTransparentRegion(region));
-        assertTrue(vg.gatherTransparentRegion(null));
+        assertTrue(mMockViewGroup.gatherTransparentRegion(region));
+        assertTrue(mMockViewGroup.gatherTransparentRegion(null));
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams(){
-        MockViewGroup vg = new MockViewGroup(mContext);
-        LayoutParams lp = vg.generateDefaultLayoutParams();
+        LayoutParams lp = mMockViewGroup.generateDefaultLayoutParams();
 
         assertEquals(LayoutParams.WRAP_CONTENT, lp.width);
         assertEquals(LayoutParams.WRAP_CONTENT, lp.height);
     }
 
-    public void testGenerateLayoutParamsWithParaAttributeSet() throws Exception{
-        MockViewGroup vg = new MockViewGroup(mContext);
+    @UiThreadTest
+    @Test
+    public void testGenerateLayoutParamsWithParaAttributeSet() throws Exception {
         XmlResourceParser set = mContext.getResources().getLayout(
                 android.view.cts.R.layout.abslistview_layout);
         XmlUtils.beginDocument(set, "ViewGroup_Layout");
-        LayoutParams lp = vg.generateLayoutParams(set);
+        LayoutParams lp = mMockViewGroup.generateLayoutParams(set);
         assertNotNull(lp);
         assertEquals(25, lp.height);
         assertEquals(25, lp.width);
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateLayoutParams() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.MATCH_PARENT);
-        LayoutParams generatedParams = vg.generateLayoutParams(p);
+        LayoutParams generatedParams = mMockViewGroup.generateLayoutParams(p);
         assertEquals(generatedParams.getClass(), p.getClass());
         assertEquals(p.width, generatedParams.width);
         assertEquals(p.height, generatedParams.height);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetChildDrawingOrder() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertEquals(1, vg.getChildDrawingOrder(0, 1));
-        assertEquals(2, vg.getChildDrawingOrder(0, 2));
+        assertEquals(1, mMockViewGroup.getChildDrawingOrder(0, 1));
+        assertEquals(2, mMockViewGroup.getChildDrawingOrder(0, 2));
     }
 
+    @Test
     public void testGetChildMeasureSpec() {
         int spec = 1;
         int padding = 1;
@@ -762,54 +795,54 @@
                 ViewGroup.getChildMeasureSpec(spec, padding, childDimension));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetChildStaticTransformation() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertFalse(vg.getChildStaticTransformation(null, null));
+        assertFalse(mMockViewGroup.getChildStaticTransformation(null, null));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetChildVisibleRect() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-
-        textView.layout(1, 1, 100, 100);
+        mMockTextView.layout(1, 1, 100, 100);
         Rect rect = new Rect(1, 1, 50, 50);
         Point p = new Point();
-        assertFalse(vg.getChildVisibleRect(textView, rect, p));
+        assertFalse(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p));
 
-        textView.layout(0, 0, 0, 0);
-        vg.layout(20, 20, 60, 60);
+        mMockTextView.layout(0, 0, 0, 0);
+        mMockViewGroup.layout(20, 20, 60, 60);
         rect = new Rect(10, 10, 40, 40);
         p = new Point();
-        assertTrue(vg.getChildVisibleRect(textView, rect, p));
+        assertTrue(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetDescendantFocusability() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         final int FLAG_MASK_FOCUSABILITY = 0x60000;
-        assertFalse((vg.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
+        assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
 
-        vg.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        assertFalse((vg.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
+        mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetLayoutAnimation() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
-        assertNull(vg.getLayoutAnimation());
+        assertNull(mMockViewGroup.getLayoutAnimation());
         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
         LayoutAnimationController la = new LayoutAnimationController(animation);
-        vg.setLayoutAnimation(la);
-        assertTrue(vg.canAnimate());
-        assertSame(la, vg.getLayoutAnimation());
+        mMockViewGroup.setLayoutAnimation(la);
+        assertTrue(mMockViewGroup.canAnimate());
+        assertSame(la, mMockViewGroup.getLayoutAnimation());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetLayoutAnimationListener() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
-        assertNull(vg.getLayoutAnimationListener());
+        assertNull(mMockViewGroup.getLayoutAnimationListener());
 
         AnimationListener al = new AnimationListener() {
-
             @Override
             public void onAnimationEnd(Animation animation) {
             }
@@ -822,63 +855,62 @@
             public void onAnimationStart(Animation animation) {
             }
         };
-        vg.setLayoutAnimationListener(al);
-        assertSame(al, vg.getLayoutAnimationListener());
+        mMockViewGroup.setLayoutAnimationListener(al);
+        assertSame(al, mMockViewGroup.getLayoutAnimationListener());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetPersistentDrawingCache() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         final int mPersistentDrawingCache1 = 2;
         final int mPersistentDrawingCache2 = 3;
-        assertEquals(mPersistentDrawingCache1, vg.getPersistentDrawingCache());
+        assertEquals(mPersistentDrawingCache1, mMockViewGroup.getPersistentDrawingCache());
 
-        vg.setPersistentDrawingCache(mPersistentDrawingCache2);
-        assertEquals(mPersistentDrawingCache2, vg.getPersistentDrawingCache());
+        mMockViewGroup.setPersistentDrawingCache(mPersistentDrawingCache2);
+        assertEquals(mPersistentDrawingCache2, mMockViewGroup.getPersistentDrawingCache());
     }
 
+    @UiThreadTest
+    @Test
     public void testHasFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertFalse(vg.hasFocus());
+        assertFalse(mMockViewGroup.hasFocus());
 
-        TextView textView = new TextView(mContext);
+        mMockViewGroup.addView(mTextView);
+        mMockViewGroup.requestChildFocus(mTextView, null);
 
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
-
-        assertTrue(vg.hasFocus());
+        assertTrue(mMockViewGroup.hasFocus());
     }
 
+    @UiThreadTest
+    @Test
     public void testHasFocusable() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertFalse(vg.hasFocusable());
+        assertFalse(mMockViewGroup.hasFocusable());
 
-        vg.setVisibility(View.VISIBLE);
-        vg.setFocusable(true);
-        assertTrue(vg.hasFocusable());
+        mMockViewGroup.setVisibility(View.VISIBLE);
+        mMockViewGroup.setFocusable(true);
+        assertTrue(mMockViewGroup.hasFocusable());
     }
 
+    @UiThreadTest
+    @Test
     public void testIndexOfChild() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        assertEquals(-1, mMockViewGroup.indexOfChild(mTextView));
 
-        assertEquals(-1, vg.indexOfChild(textView));
-
-        vg.addView(textView);
-        assertEquals(0, vg.indexOfChild(textView));
+        mMockViewGroup.addView(mTextView);
+        assertEquals(0, mMockViewGroup.indexOfChild(mTextView));
     }
 
-    private void setupActivity(String action) {
-
-        Intent intent = new Intent(getInstrumentation().getTargetContext(),
-                ViewGroupCtsActivity.class);
-        intent.setAction(action);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getInstrumentation().getTargetContext().startActivity(intent);
-    }
-
+    @LargeTest
+    @Test
     public void testInvalidateChild() {
         ViewGroupCtsActivity.setResult(this);
-        setupActivity(ViewGroupCtsActivity.ACTION_INVALIDATE_CHILD);
+
+        Context context = InstrumentationRegistry.getTargetContext();
+        Intent intent = new Intent(context, ViewGroupCtsActivity.class);
+        intent.setAction(ViewGroupCtsActivity.ACTION_INVALIDATE_CHILD);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+
         waitForResult();
         assertEquals(CTSResult.RESULT_OK, mResultCode);
     }
@@ -894,75 +926,79 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testIsAlwaysDrawnWithCacheEnabled() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
 
-        assertTrue(vg.isAlwaysDrawnWithCacheEnabled());
-
-        vg.setAlwaysDrawnWithCacheEnabled(false);
-        assertFalse(vg.isAlwaysDrawnWithCacheEnabled());
-        vg.setAlwaysDrawnWithCacheEnabled(true);
-        assertTrue(vg.isAlwaysDrawnWithCacheEnabled());
+        mMockViewGroup.setAlwaysDrawnWithCacheEnabled(false);
+        assertFalse(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
+        mMockViewGroup.setAlwaysDrawnWithCacheEnabled(true);
+        assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled());
     }
 
+    @UiThreadTest
+    @Test
     public void testIsAnimationCacheEnabled() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertTrue(mMockViewGroup.isAnimationCacheEnabled());
 
-        assertTrue(vg.isAnimationCacheEnabled());
-
-        vg.setAnimationCacheEnabled(false);
-        assertFalse(vg.isAnimationCacheEnabled());
-        vg.setAnimationCacheEnabled(true);
-        assertTrue(vg.isAnimationCacheEnabled());
+        mMockViewGroup.setAnimationCacheEnabled(false);
+        assertFalse(mMockViewGroup.isAnimationCacheEnabled());
+        mMockViewGroup.setAnimationCacheEnabled(true);
+        assertTrue(mMockViewGroup.isAnimationCacheEnabled());
     }
 
+    @UiThreadTest
+    @Test
     public void testIsChildrenDrawnWithCacheEnabled() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
 
-        assertFalse(vg.isChildrenDrawnWithCacheEnabled());
-
-        vg.setChildrenDrawnWithCacheEnabled(true);
-        assertTrue(vg.isChildrenDrawnWithCacheEnabled());
+        mMockViewGroup.setChildrenDrawnWithCacheEnabled(true);
+        assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChild() {
         final int width = 100;
         final int height = 200;
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockView child = new MockView(mContext);
         child.setLayoutParams(new LayoutParams(width, height));
         child.forceLayout();
-        vg.addView(child);
+        mMockViewGroup.addView(child);
 
         final int parentWidthMeasureSpec = 1;
         final int parentHeightMeasureSpec = 2;
-        vg.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
+        mMockViewGroup.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, 0, width),
                 child.mWidthMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(parentHeightMeasureSpec, 0, height),
                 child.mHeightMeasureSpec);
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChildren() {
         final int widthMeasureSpec = 100;
         final int heightMeasureSpec = 200;
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockTextView textView1 = new MockTextView(mContext);
 
-        vg.addView(textView1);
-        vg.measureChildCalledTime = 0;
-        vg.measureChildren(widthMeasureSpec, heightMeasureSpec);
-        assertEquals(1, vg.measureChildCalledTime);
+        mMockViewGroup.addView(textView1);
+        mMockViewGroup.measureChildCalledTime = 0;
+        mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec);
+        assertEquals(1, mMockViewGroup.measureChildCalledTime);
 
         MockTextView textView2 = new MockTextView(mContext);
         textView2.setVisibility(View.GONE);
-        vg.addView(textView2);
+        mMockViewGroup.addView(textView2);
 
-        vg.measureChildCalledTime = 0;
-        vg.measureChildren(widthMeasureSpec, heightMeasureSpec);
-        assertEquals(1, vg.measureChildCalledTime);
+        mMockViewGroup.measureChildCalledTime = 0;
+        mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec);
+        assertEquals(1, mMockViewGroup.measureChildCalledTime);
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChildWithMargins() {
         final int width = 10;
         final int height = 20;
@@ -970,71 +1006,71 @@
         final int widthUsed = 2;
         final int parentHeightMeasureSpec = 3;
         final int heightUsed = 4;
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockView child = new MockView(mContext);
 
-        vg.addView(child);
+        mMockViewGroup.addView(child);
         child.setLayoutParams(new ViewGroup.LayoutParams(width, height));
         try {
-            vg.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+            mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
                     parentHeightMeasureSpec, heightUsed);
             fail("measureChildWithMargins should throw out class cast exception");
         } catch (RuntimeException e) {
         }
         child.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height));
 
-        vg.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec,
-                heightUsed);
+        mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+                parentHeightMeasureSpec, heightUsed);
         assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, parentHeightMeasureSpec,
                 width), child.mWidthMeasureSpec);
         assertEquals(ViewGroup.getChildMeasureSpec(widthUsed, heightUsed, height),
                 child.mHeightMeasureSpec);
     }
 
+    @UiThreadTest
+    @Test
     public void testOffsetDescendantRectToMyCoords() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-
         try {
-            vg.offsetDescendantRectToMyCoords(textView, new Rect());
+            mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, new Rect());
             fail("offsetDescendantRectToMyCoords should throw out "
                     + "IllegalArgumentException");
         } catch (RuntimeException e) {
             // expected
         }
-        vg.addView(textView);
-        textView.layout(1, 2, 3, 4);
+        mMockViewGroup.addView(mMockTextView);
+        mMockTextView.layout(1, 2, 3, 4);
         Rect rect = new Rect();
-        vg.offsetDescendantRectToMyCoords(textView, rect);
+        mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, rect);
         assertEquals(2, rect.bottom);
         assertEquals(2, rect.top);
         assertEquals(1, rect.left);
         assertEquals(1, rect.right);
     }
 
+    @UiThreadTest
+    @Test
     public void testOffsetRectIntoDescendantCoords() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.layout(10, 20, 30, 40);
-        MockTextView textView = new MockTextView(mContext);
+        mMockViewGroup.layout(10, 20, 30, 40);
 
         try {
-            vg.offsetRectIntoDescendantCoords(textView, new Rect());
+            mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, new Rect());
             fail("offsetRectIntoDescendantCoords should throw out "
                     + "IllegalArgumentException");
         } catch (RuntimeException e) {
             // expected
         }
-        textView.layout(1, 2, 3, 4);
-        vg.addView(textView);
+        mMockTextView.layout(1, 2, 3, 4);
+        mMockViewGroup.addView(mMockTextView);
 
         Rect rect = new Rect(5, 6, 7, 8);
-        vg.offsetRectIntoDescendantCoords(textView, rect);
+        mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, rect);
         assertEquals(6, rect.bottom);
         assertEquals(4, rect.top);
         assertEquals(4, rect.left);
         assertEquals(6, rect.right);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnAnimationEnd() {
         // this function is a call back function it should be tested in ViewGroup#drawChild.
         MockViewGroup parent = new MockViewGroup(mContext);
@@ -1065,6 +1101,8 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testOnAnimationStart() {
         // This is a call back method. It should be tested in ViewGroup#drawChild.
         MockViewGroup parent = new MockViewGroup(mContext);
@@ -1085,65 +1123,68 @@
         assertTrue(child.isOnAnimationStartCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnCreateDrawableState() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         // Call back function. Called in View#getDrawableState()
-        int[] data = vg.getDrawableState();
-        assertTrue(vg.isOnCreateDrawableStateCalled);
+        int[] data = mMockViewGroup.getDrawableState();
+        assertTrue(mMockViewGroup.isOnCreateDrawableStateCalled);
         assertEquals(1, data.length);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnInterceptTouchEvent() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100,
-                0);
+                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100, 0);
 
-        assertFalse(vg.dispatchTouchEvent(me));
-        assertTrue(vg.isOnInterceptTouchEventCalled);
+        assertFalse(mMockViewGroup.dispatchTouchEvent(me));
+        assertTrue(mMockViewGroup.isOnInterceptTouchEventCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnLayout() {
         final int left = 1;
         final int top = 2;
         final int right = 100;
         final int bottom = 200;
-        MockViewGroup mv = new MockViewGroup(mContext);
-        mv.layout(left, top, right, bottom);
-        assertEquals(left, mv.left);
-        assertEquals(top, mv.top);
-        assertEquals(right, mv.right);
-        assertEquals(bottom, mv.bottom);
+        mMockViewGroup.layout(left, top, right, bottom);
+        assertEquals(left, mMockViewGroup.left);
+        assertEquals(top, mMockViewGroup.top);
+        assertEquals(right, mMockViewGroup.right);
+        assertEquals(bottom, mMockViewGroup.bottom);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnRequestFocusInDescendants() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
-        vg.requestFocus(View.FOCUS_DOWN, new Rect());
-        assertTrue(vg.isOnRequestFocusInDescendantsCalled);
+        mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect());
+        assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveAllViews() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        assertEquals(0, vg.getChildCount());
+        assertEquals(0, mMockViewGroup.getChildCount());
 
-        vg.addView(textView);
-        assertEquals(1, vg.getChildCount());
+        mMockViewGroup.addView(mMockTextView);
+        assertEquals(1, mMockViewGroup.getChildCount());
 
-        vg.removeAllViews();
-        assertEquals(0, vg.getChildCount());
-        assertNull(textView.getParent());
+        mMockViewGroup.removeAllViews();
+        assertEquals(0, mMockViewGroup.getChildCount());
+        assertNull(mMockTextView.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveAllViewsInLayout() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
 
         assertEquals(0, parent.getChildCount());
 
-        child.addView(textView);
+        child.addView(mMockTextView);
         parent.addView(child);
         assertEquals(1, parent.getChildCount());
 
@@ -1151,39 +1192,31 @@
         assertEquals(0, parent.getChildCount());
         assertEquals(1, child.getChildCount());
         assertNull(child.getParent());
-        assertSame(child, textView.getParent());
+        assertSame(child, mMockTextView.getParent());
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveDetachedView() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child1 = new MockViewGroup(mContext);
         MockViewGroup child2 = new MockViewGroup(mContext);
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
+        ViewGroup.OnHierarchyChangeListener listener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
         parent.setOnHierarchyChangeListener(listener);
         parent.addView(child1);
         parent.addView(child2);
 
         parent.removeDetachedView(child1, false);
-        assertSame(parent, listener.sParent);
-        assertSame(child1, listener.sChild);
+
+        InOrder inOrder = inOrder(listener);
+        inOrder.verify(listener, times(1)).onChildViewAdded(parent, child1);
+        inOrder.verify(listener, times(1)).onChildViewAdded(parent, child2);
+        inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child1);
     }
 
-    static class MockOnHierarchyChangeListener implements OnHierarchyChangeListener {
-
-        public View sParent;
-        public View sChild;
-
-        @Override
-        public void onChildViewAdded(View parent, View child) {
-        }
-
-        @Override
-        public void onChildViewRemoved(View parent, View child) {
-            sParent = parent;
-            sChild = child;
-        }
-    }
-
+    @UiThreadTest
+    @Test
     public void testRemoveView() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1196,8 +1229,11 @@
         parent.removeView(child);
         assertEquals(0, parent.getChildCount());
         assertNull(child.getParent());
+        assertTrue(parent.isOnViewRemovedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveViewAt() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1218,8 +1254,11 @@
         parent.removeViewAt(0);
         assertEquals(0, parent.getChildCount());
         assertNull(child.getParent());
+        assertTrue(parent.isOnViewRemovedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveViewInLayout() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1232,8 +1271,11 @@
         parent.removeViewInLayout(child);
         assertEquals(0, parent.getChildCount());
         assertNull(child.getParent());
+        assertTrue(parent.isOnViewRemovedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveViews() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child1 = new MockViewGroup(mContext);
@@ -1267,8 +1309,11 @@
         parent.removeViews(0, 1);
         assertEquals(0, parent.getChildCount());
         assertNull(child2.getParent());
+        assertTrue(parent.isOnViewRemovedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRemoveViewsInLayout() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child1 = new MockViewGroup(mContext);
@@ -1302,43 +1347,47 @@
         parent.removeViewsInLayout(0, 1);
         assertEquals(0, parent.getChildCount());
         assertNull(child2.getParent());
+        assertTrue(parent.isOnViewRemovedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestChildFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        TextView textView = new TextView(mContext);
+        mMockViewGroup.addView(mTextView);
+        mMockViewGroup.requestChildFocus(mTextView, null);
 
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
+        assertNotNull(mMockViewGroup.getFocusedChild());
 
-        assertNotNull(vg.getFocusedChild());
-
-        vg.clearChildFocus(textView);
-        assertNull(vg.getFocusedChild());
+        mMockViewGroup.clearChildFocus(mTextView);
+        assertNull(mMockViewGroup.getFocusedChild());
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestChildRectangleOnScreen() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        assertFalse(vg.requestChildRectangleOnScreen(null, null, false));
+        assertFalse(mMockViewGroup.requestChildRectangleOnScreen(null, null, false));
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestDisallowInterceptTouchEvent() {
-        MockViewGroup parent = new MockViewGroup(mContext);
         MockView child = new MockView(mContext);
 
-        parent.addView(child);
+        mMockViewGroup.addView(child);
         child.requestDisallowInterceptTouchEvent(true);
         child.requestDisallowInterceptTouchEvent(false);
-        assertTrue(parent.isRequestDisallowInterceptTouchEventCalled);
+        assertTrue(mMockViewGroup.isRequestDisallowInterceptTouchEventCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestFocus() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-
-        vg.requestFocus(View.FOCUS_DOWN, new Rect());
-        assertTrue(vg.isOnRequestFocusInDescendantsCalled);
+        mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect());
+        assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestTransparentRegion() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockView child1 = new MockView(mContext);
@@ -1349,76 +1398,63 @@
         assertTrue(parent.isRequestTransparentRegionCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testScheduleLayoutAnimation() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         Animation animation = new AlphaAnimation(mContext, null);
 
-        MockLayoutAnimationController al = new MockLayoutAnimationController(animation);
-        vg.setLayoutAnimation(al);
-        vg.scheduleLayoutAnimation();
-        vg.dispatchDraw(new Canvas());
-        assertTrue(al.mIsStartCalled);
+        LayoutAnimationController al = spy(new LayoutAnimationController(animation));
+        mMockViewGroup.setLayoutAnimation(al);
+        mMockViewGroup.scheduleLayoutAnimation();
+        mMockViewGroup.dispatchDraw(new Canvas());
+        verify(al, times(1)).start();
     }
 
-    static class MockLayoutAnimationController extends LayoutAnimationController {
-
-        public boolean mIsStartCalled;
-
-        public MockLayoutAnimationController(Animation animation) {
-            super(animation);
-        }
-
-        @Override
-        public void start() {
-            mIsStartCalled = true;
-            super.start();
-        }
-    }
-
+    @UiThreadTest
+    @Test
     public void testSetAddStatesFromChildren() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setAddStatesFromChildren(true);
-        assertTrue(vg.addStatesFromChildren());
+        mMockViewGroup.setAddStatesFromChildren(true);
+        assertTrue(mMockViewGroup.addStatesFromChildren());
 
-        vg.setAddStatesFromChildren(false);
-        assertFalse(vg.addStatesFromChildren());
+        mMockViewGroup.setAddStatesFromChildren(false);
+        assertFalse(mMockViewGroup.addStatesFromChildren());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetChildrenDrawingCacheEnabled() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertTrue(mMockViewGroup.isAnimationCacheEnabled());
 
-        assertTrue(vg.isAnimationCacheEnabled());
+        mMockViewGroup.setAnimationCacheEnabled(false);
+        assertFalse(mMockViewGroup.isAnimationCacheEnabled());
 
-        vg.setAnimationCacheEnabled(false);
-        assertFalse(vg.isAnimationCacheEnabled());
-
-        vg.setAnimationCacheEnabled(true);
-        assertTrue(vg.isAnimationCacheEnabled());
+        mMockViewGroup.setAnimationCacheEnabled(true);
+        assertTrue(mMockViewGroup.isAnimationCacheEnabled());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetChildrenDrawnWithCacheEnabled() {
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
 
-        assertFalse(vg.isChildrenDrawnWithCacheEnabled());
+        mMockViewGroup.setChildrenDrawnWithCacheEnabled(true);
+        assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
 
-        vg.setChildrenDrawnWithCacheEnabled(true);
-        assertTrue(vg.isChildrenDrawnWithCacheEnabled());
-
-        vg.setChildrenDrawnWithCacheEnabled(false);
-        assertFalse(vg.isChildrenDrawnWithCacheEnabled());
+        mMockViewGroup.setChildrenDrawnWithCacheEnabled(false);
+        assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetClipChildren() {
         Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
 
-        MockViewGroup vg = new MockViewGroup(mContext);
-        MockTextView textView = new MockTextView(mContext);
-        textView.layout(1, 2, 30, 40);
-        vg.layout(1, 1, 100, 200);
-        vg.setClipChildren(true);
+        mMockTextView.layout(1, 2, 30, 40);
+        mMockViewGroup.layout(1, 1, 100, 200);
+        mMockViewGroup.setClipChildren(true);
 
         MockCanvas canvas = new MockCanvas(bitmap);
-        vg.drawChild(canvas, textView, 100);
+        mMockViewGroup.drawChild(canvas, mMockTextView, 100);
         Rect rect = canvas.getClipBounds();
         assertEquals(0, rect.top);
         assertEquals(100, rect.bottom);
@@ -1456,6 +1492,12 @@
         }
 
         @Override
+        public int save(int saveFlags) {
+            mIsSaveCalled = true;
+            return super.save(saveFlags);
+        }
+
+        @Override
         public boolean clipRect(int left, int top, int right, int bottom) {
             mLeft = left;
             mTop = top;
@@ -1465,22 +1507,23 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testSetClipToPadding() {
         final int frameLeft = 1;
         final int frameTop = 2;
         final int frameRight = 100;
         final int frameBottom = 200;
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.layout(frameLeft, frameTop, frameRight, frameBottom);
+        mMockViewGroup.layout(frameLeft, frameTop, frameRight, frameBottom);
 
-        vg.setClipToPadding(true);
+        mMockViewGroup.setClipToPadding(true);
         MockCanvas canvas = new MockCanvas();
         final int paddingLeft = 10;
         final int paddingTop = 20;
         final int paddingRight = 100;
         final int paddingBottom = 200;
-        vg.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
-        vg.dispatchDraw(canvas);
+        mMockViewGroup.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+        mMockViewGroup.dispatchDraw(canvas);
         //check that the clip region does not contain the padding area
         assertTrue(canvas.mIsSaveCalled);
         assertEquals(10, canvas.mLeft);
@@ -1488,9 +1531,9 @@
         assertEquals(-frameLeft, canvas.mRight);
         assertEquals(-frameTop, canvas.mBottom);
 
-        vg.setClipToPadding(false);
+        mMockViewGroup.setClipToPadding(false);
         canvas = new MockCanvas();
-        vg.dispatchDraw(canvas);
+        mMockViewGroup.dispatchDraw(canvas);
         assertFalse(canvas.mIsSaveCalled);
         assertEquals(0, canvas.mLeft);
         assertEquals(0, canvas.mTop);
@@ -1498,139 +1541,147 @@
         assertEquals(0, canvas.mBottom);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetDescendantFocusability() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         final int FLAG_MASK_FOCUSABILITY = 0x60000;
-        assertFalse((vg.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
+        assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
 
-        vg.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        assertFalse((vg.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
+        mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
 
-        vg.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-        assertFalse((vg.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
-        assertFalse((vg.getDescendantFocusability() &
+        mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0);
+        assertFalse((mMockViewGroup.getDescendantFocusability() &
                 ViewGroup.FOCUS_BEFORE_DESCENDANTS) == 0);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetOnHierarchyChangeListener() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
+        ViewGroup.OnHierarchyChangeListener listener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
         parent.setOnHierarchyChangeListener(listener);
         parent.addView(child);
 
         parent.removeDetachedView(child, false);
-        assertSame(parent, listener.sParent);
-        assertSame(child, listener.sChild);
+        InOrder inOrder = inOrder(listener);
+        inOrder.verify(listener, times(1)).onChildViewAdded(parent, child);
+        inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetPadding() {
         final int left = 1;
         final int top = 2;
         final int right = 3;
         final int bottom = 4;
 
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertEquals(0, mMockViewGroup.getPaddingBottom());
+        assertEquals(0, mMockViewGroup.getPaddingTop());
+        assertEquals(0, mMockViewGroup.getPaddingLeft());
+        assertEquals(0, mMockViewGroup.getPaddingRight());
+        assertEquals(0, mMockViewGroup.getPaddingStart());
+        assertEquals(0, mMockViewGroup.getPaddingEnd());
 
-        assertEquals(0, vg.getPaddingBottom());
-        assertEquals(0, vg.getPaddingTop());
-        assertEquals(0, vg.getPaddingLeft());
-        assertEquals(0, vg.getPaddingRight());
-        assertEquals(0, vg.getPaddingStart());
-        assertEquals(0, vg.getPaddingEnd());
+        mMockViewGroup.setPadding(left, top, right, bottom);
 
-        vg.setPadding(left, top, right, bottom);
+        assertEquals(bottom, mMockViewGroup.getPaddingBottom());
+        assertEquals(top, mMockViewGroup.getPaddingTop());
+        assertEquals(left, mMockViewGroup.getPaddingLeft());
+        assertEquals(right, mMockViewGroup.getPaddingRight());
 
-        assertEquals(bottom, vg.getPaddingBottom());
-        assertEquals(top, vg.getPaddingTop());
-        assertEquals(left, vg.getPaddingLeft());
-        assertEquals(right, vg.getPaddingRight());
-
-        assertEquals(left, vg.getPaddingStart());
-        assertEquals(right, vg.getPaddingEnd());
-        assertEquals(false, vg.isPaddingRelative());
+        assertEquals(left, mMockViewGroup.getPaddingStart());
+        assertEquals(right, mMockViewGroup.getPaddingEnd());
+        assertEquals(false, mMockViewGroup.isPaddingRelative());
 
         // force RTL direction
-        vg.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
 
-        assertEquals(bottom, vg.getPaddingBottom());
-        assertEquals(top, vg.getPaddingTop());
-        assertEquals(left, vg.getPaddingLeft());
-        assertEquals(right, vg.getPaddingRight());
+        assertEquals(bottom, mMockViewGroup.getPaddingBottom());
+        assertEquals(top, mMockViewGroup.getPaddingTop());
+        assertEquals(left, mMockViewGroup.getPaddingLeft());
+        assertEquals(right, mMockViewGroup.getPaddingRight());
 
-        assertEquals(right, vg.getPaddingStart());
-        assertEquals(left, vg.getPaddingEnd());
-        assertEquals(false, vg.isPaddingRelative());
+        assertEquals(right, mMockViewGroup.getPaddingStart());
+        assertEquals(left, mMockViewGroup.getPaddingEnd());
+        assertEquals(false, mMockViewGroup.isPaddingRelative());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetPaddingRelative() {
         final int start = 1;
         final int top = 2;
         final int end = 3;
         final int bottom = 4;
 
-        MockViewGroup vg = new MockViewGroup(mContext);
+        assertEquals(0, mMockViewGroup.getPaddingBottom());
+        assertEquals(0, mMockViewGroup.getPaddingTop());
+        assertEquals(0, mMockViewGroup.getPaddingLeft());
+        assertEquals(0, mMockViewGroup.getPaddingRight());
+        assertEquals(0, mMockViewGroup.getPaddingStart());
+        assertEquals(0, mMockViewGroup.getPaddingEnd());
 
-        assertEquals(0, vg.getPaddingBottom());
-        assertEquals(0, vg.getPaddingTop());
-        assertEquals(0, vg.getPaddingLeft());
-        assertEquals(0, vg.getPaddingRight());
-        assertEquals(0, vg.getPaddingStart());
-        assertEquals(0, vg.getPaddingEnd());
+        mMockViewGroup.setPaddingRelative(start, top, end, bottom);
 
-        vg.setPaddingRelative(start, top, end, bottom);
+        assertEquals(bottom, mMockViewGroup.getPaddingBottom());
+        assertEquals(top, mMockViewGroup.getPaddingTop());
+        assertEquals(start, mMockViewGroup.getPaddingLeft());
+        assertEquals(end, mMockViewGroup.getPaddingRight());
 
-        assertEquals(bottom, vg.getPaddingBottom());
-        assertEquals(top, vg.getPaddingTop());
-        assertEquals(start, vg.getPaddingLeft());
-        assertEquals(end, vg.getPaddingRight());
-
-        assertEquals(start, vg.getPaddingStart());
-        assertEquals(end, vg.getPaddingEnd());
-        assertEquals(true, vg.isPaddingRelative());
+        assertEquals(start, mMockViewGroup.getPaddingStart());
+        assertEquals(end, mMockViewGroup.getPaddingEnd());
+        assertEquals(true, mMockViewGroup.isPaddingRelative());
 
         // force RTL direction after setting relative padding
-        vg.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
 
-        assertEquals(bottom, vg.getPaddingBottom());
-        assertEquals(top, vg.getPaddingTop());
-        assertEquals(end, vg.getPaddingLeft());
-        assertEquals(start, vg.getPaddingRight());
+        assertEquals(bottom, mMockViewGroup.getPaddingBottom());
+        assertEquals(top, mMockViewGroup.getPaddingTop());
+        assertEquals(end, mMockViewGroup.getPaddingLeft());
+        assertEquals(start, mMockViewGroup.getPaddingRight());
 
-        assertEquals(start, vg.getPaddingStart());
-        assertEquals(end, vg.getPaddingEnd());
-        assertEquals(true, vg.isPaddingRelative());
+        assertEquals(start, mMockViewGroup.getPaddingStart());
+        assertEquals(end, mMockViewGroup.getPaddingEnd());
+        assertEquals(true, mMockViewGroup.isPaddingRelative());
 
         // force RTL direction before setting relative padding
-        vg = new MockViewGroup(mContext);
-        vg.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        mMockViewGroup = new MockViewGroup(mContext);
+        mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
 
-        assertEquals(0, vg.getPaddingBottom());
-        assertEquals(0, vg.getPaddingTop());
-        assertEquals(0, vg.getPaddingLeft());
-        assertEquals(0, vg.getPaddingRight());
-        assertEquals(0, vg.getPaddingStart());
-        assertEquals(0, vg.getPaddingEnd());
+        assertEquals(0, mMockViewGroup.getPaddingBottom());
+        assertEquals(0, mMockViewGroup.getPaddingTop());
+        assertEquals(0, mMockViewGroup.getPaddingLeft());
+        assertEquals(0, mMockViewGroup.getPaddingRight());
+        assertEquals(0, mMockViewGroup.getPaddingStart());
+        assertEquals(0, mMockViewGroup.getPaddingEnd());
 
-        vg.setPaddingRelative(start, top, end, bottom);
+        mMockViewGroup.setPaddingRelative(start, top, end, bottom);
 
-        assertEquals(bottom, vg.getPaddingBottom());
-        assertEquals(top, vg.getPaddingTop());
-        assertEquals(end, vg.getPaddingLeft());
-        assertEquals(start, vg.getPaddingRight());
+        assertEquals(bottom, mMockViewGroup.getPaddingBottom());
+        assertEquals(top, mMockViewGroup.getPaddingTop());
+        assertEquals(end, mMockViewGroup.getPaddingLeft());
+        assertEquals(start, mMockViewGroup.getPaddingRight());
 
-        assertEquals(start, vg.getPaddingStart());
-        assertEquals(end, vg.getPaddingEnd());
-        assertEquals(true, vg.isPaddingRelative());
+        assertEquals(start, mMockViewGroup.getPaddingStart());
+        assertEquals(end, mMockViewGroup.getPaddingEnd());
+        assertEquals(true, mMockViewGroup.isPaddingRelative());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetPersistentDrawingCache() {
-        MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setPersistentDrawingCache(1);
-        assertEquals(1 & ViewGroup.PERSISTENT_ALL_CACHES, vg
+        mMockViewGroup.setPersistentDrawingCache(1);
+        assertEquals(1 & ViewGroup.PERSISTENT_ALL_CACHES, mMockViewGroup
                 .getPersistentDrawingCache());
     }
 
+    @UiThreadTest
+    @Test
     public void testShowContextMenuForChild() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1640,6 +1691,8 @@
         assertTrue(parent.isShowContextMenuForChildCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testShowContextMenuForChild_WithXYCoords() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1649,18 +1702,21 @@
         assertTrue(parent.isShowContextMenuForChildCalledWithXYCoords);
     }
 
+    @UiThreadTest
+    @Test
     public void testStartLayoutAnimation() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         RotateAnimation animation = new RotateAnimation(0.1f, 0.1f);
         LayoutAnimationController la = new LayoutAnimationController(animation);
-        vg.setLayoutAnimation(la);
+        mMockViewGroup.setLayoutAnimation(la);
 
-        vg.layout(1, 1, 100, 100);
-        assertFalse(vg.isLayoutRequested());
-        vg.startLayoutAnimation();
-        assertTrue(vg.isLayoutRequested());
+        mMockViewGroup.layout(1, 1, 100, 100);
+        assertFalse(mMockViewGroup.isLayoutRequested());
+        mMockViewGroup.startLayoutAnimation();
+        assertTrue(mMockViewGroup.isLayoutRequested());
     }
 
+    @UiThreadTest
+    @Test
     public void testUpdateViewLayout() {
         MockViewGroup parent = new MockViewGroup(mContext);
         MockViewGroup child = new MockViewGroup(mContext);
@@ -1672,6 +1728,8 @@
         assertEquals(param.height, child.getLayoutParams().height);
     }
 
+    @UiThreadTest
+    @Test
     public void testDebug() {
         final int EXPECTED = 100;
         MockViewGroup parent = new MockViewGroup(mContext);
@@ -1682,43 +1740,44 @@
         assertEquals(EXPECTED + 1, child.debugDepth);
     }
 
+    @UiThreadTest
+    @Test
     public void testDispatchKeyEventPreIme() {
-        MockViewGroup vg = new MockViewGroup(mContext);
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
-        assertFalse(vg.dispatchKeyEventPreIme(event));
-        assertFalse(vg.dispatchKeyShortcutEvent(event));
-        MockTextView textView = new MockTextView(mContext);
+        assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event));
+        assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event));
 
-        vg.addView(textView);
-        vg.requestChildFocus(textView, null);
-        vg.layout(0, 0, 100, 200);
-        assertFalse(vg.dispatchKeyEventPreIme(event));
-        assertFalse(vg.dispatchKeyShortcutEvent(event));
+        mMockViewGroup.addView(mMockTextView);
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        mMockViewGroup.layout(0, 0, 100, 200);
+        assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event));
+        assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event));
 
-        vg.requestChildFocus(textView, null);
-        textView.layout(0, 0, 50, 50);
-        assertTrue(vg.dispatchKeyEventPreIme(event));
-        assertTrue(vg.dispatchKeyShortcutEvent(event));
+        mMockViewGroup.requestChildFocus(mMockTextView, null);
+        mMockTextView.layout(0, 0, 50, 50);
+        assertTrue(mMockViewGroup.dispatchKeyEventPreIme(event));
+        assertTrue(mMockViewGroup.dispatchKeyShortcutEvent(event));
 
-        vg.setStaticTransformationsEnabled(true);
+        mMockViewGroup.setStaticTransformationsEnabled(true);
         Canvas canvas = new Canvas();
-        vg.drawChild(canvas, textView, 100);
-        assertTrue(vg.isGetChildStaticTransformationCalled);
-        vg.isGetChildStaticTransformationCalled = false;
-        vg.setStaticTransformationsEnabled(false);
-        vg.drawChild(canvas, textView, 100);
-        assertFalse(vg.isGetChildStaticTransformationCalled);
+        mMockViewGroup.drawChild(canvas, mMockTextView, 100);
+        assertTrue(mMockViewGroup.isGetChildStaticTransformationCalled);
+        mMockViewGroup.isGetChildStaticTransformationCalled = false;
+        mMockViewGroup.setStaticTransformationsEnabled(false);
+        mMockViewGroup.drawChild(canvas, mMockTextView, 100);
+        assertFalse(mMockViewGroup.isGetChildStaticTransformationCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testStartActionModeForChildRespectsSubclassModeOnPrimary() {
         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
         vg.shouldReturnOwnTypelessActionMode = true;
         vgParent.addView(vg);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        vg.addView(mMockTextView);
 
-        textView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_PRIMARY);
+        mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_PRIMARY);
 
         assertTrue(vg.isStartActionModeForChildTypedCalled);
         assertTrue(vg.isStartActionModeForChildTypelessCalled);
@@ -1726,15 +1785,16 @@
         assertFalse(vgParent.isStartActionModeForChildTypedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testStartActionModeForChildIgnoresSubclassModeOnFloating() {
         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
         vg.shouldReturnOwnTypelessActionMode = true;
         vgParent.addView(vg);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        vg.addView(mMockTextView);
 
-        textView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
+        mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
 
         assertTrue(vg.isStartActionModeForChildTypedCalled);
         assertFalse(vg.isStartActionModeForChildTypelessCalled);
@@ -1742,38 +1802,42 @@
         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testStartActionModeForChildTypedBubblesUpToParent() {
         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
         vgParent.addView(vg);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        vg.addView(mMockTextView);
 
-        textView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
+        mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING);
 
         assertTrue(vg.isStartActionModeForChildTypedCalled);
         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testStartActionModeForChildTypelessBubblesUpToParent() {
         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
         MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext);
         vgParent.addView(vg);
-        MockTextView textView = new MockTextView(mContext);
-        vg.addView(textView);
+        vg.addView(mMockTextView);
 
-        textView.startActionMode(NO_OP_ACTION_MODE_CALLBACK);
+        mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK);
 
         assertTrue(vg.isStartActionModeForChildTypedCalled);
         assertTrue(vg.isStartActionModeForChildTypelessCalled);
         assertTrue(vgParent.isStartActionModeForChildTypedCalled);
     }
 
+    @UiThreadTest
+    @Test
     public void testTemporaryDetach() {
         // [vgParent]
         //   - [viewParent1]
         //   - [viewParent1]
-        //   - [vg]
+        //   - [mMockViewGroup]
         //     - [view1]
         //     - [view2]
         MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext);
@@ -1813,7 +1877,7 @@
         // [vgParent]
         //   - [viewParent1]
         //   - [viewParent1]
-        //   - [vg]           <- dispatchStartTemporaryDetach()
+        //   - [mMockViewGroup]           <- dispatchStartTemporaryDetach()
         //     - [view1]
         //     - [view2]
         vg.dispatchStartTemporaryDetach();
@@ -1842,7 +1906,7 @@
         // [vgParent]
         //   - [viewParent1]
         //   - [viewParent1]
-        //   - [vg]           <- dispatchFinishTemporaryDetach()
+        //   - [mMockViewGroup]           <- dispatchFinishTemporaryDetach()
         //     - [view1]
         //     - [view2]
         vg.dispatchFinishTemporaryDetach();
@@ -1871,7 +1935,7 @@
         // [vgParent]         <- dispatchStartTemporaryDetach()
         //   - [viewParent1]
         //   - [viewParent1]
-        //   - [vg]
+        //   - [mMockViewGroup]
         //     - [view1]
         //     - [view2]
         vgParent.dispatchStartTemporaryDetach();
@@ -1900,7 +1964,7 @@
         // [vgParent]         <- dispatchFinishTemporaryDetach()
         //   - [viewParent1]
         //   - [viewParent1]
-        //   - [vg]
+        //   - [mMockViewGroup]
         //     - [view1]
         //     - [view2]
         vgParent.dispatchFinishTemporaryDetach();
@@ -2045,10 +2109,11 @@
         resetResolvedDrawablesCount = 0;
     }
 
+    @UiThreadTest
+    @Test
     public void testResetRtlProperties() {
         clearRtlCounters();
 
-        MockViewGroup vg = new MockViewGroup(mContext);
         MockView2 v1 = new MockView2(mContext);
         MockView2 v2 = new MockView2(mContext);
 
@@ -2064,9 +2129,9 @@
         assertEquals(1, resetResolvedDrawablesCount);
 
         clearRtlCounters();
-        vg.addView(v1);
-        vg.addView(v2);
-        vg.addView(v3);
+        mMockViewGroup.addView(v1);
+        mMockViewGroup.addView(v2);
+        mMockViewGroup.addView(v3);
 
         assertEquals(3, resetRtlPropertiesCount); // for v1 / v2 / v3 only
         assertEquals(4, resetResolvedLayoutDirectionCount); // for v1 / v2 / v3 / v4
@@ -2076,11 +2141,12 @@
         assertEquals(4, resetResolvedDrawablesCount);
 
         clearRtlCounters();
-        vg.resetRtlProperties();
-        assertEquals(1, resetRtlPropertiesCount); // for vg only
+        mMockViewGroup.resetRtlProperties();
+        assertEquals(1, resetRtlPropertiesCount); // for mMockViewGroup only
         assertEquals(5, resetResolvedLayoutDirectionCount); // for all
         assertEquals(5, resetResolvedTextDirectionCount);
-        assertEquals(1, resetResolvedTextAlignmentCount); // for vg only as TextAlignment is not inherited (default is Gravity)
+        // for mMockViewGroup only as TextAlignment is not inherited (default is Gravity)
+        assertEquals(1, resetResolvedTextAlignmentCount);
         assertEquals(5, resetResolvedPaddingCount);
         assertEquals(5, resetResolvedDrawablesCount);
     }
@@ -2170,6 +2236,8 @@
         public boolean isOnCreateDrawableStateCalled;
         public boolean isOnInterceptTouchEventCalled;
         public boolean isOnRequestFocusInDescendantsCalled;
+        public boolean isOnViewAddedCalled;
+        public boolean isOnViewRemovedCalled;
         public boolean isFocusableViewAvailable;
         public boolean isDispatchDrawCalled;
         public boolean isRequestDisallowInterceptTouchEventCalled;
@@ -2408,6 +2476,18 @@
         }
 
         @Override
+        public void onViewAdded(View child) {
+            isOnViewAddedCalled = true;
+            super.onViewAdded(child);
+        }
+
+        @Override
+        public void onViewRemoved(View child) {
+            isOnViewRemovedCalled = true;
+            super.onViewRemoved(child);
+        }
+
+        @Override
         public void recomputeViewAttributes(View child) {
             isRecomputeViewAttributesCalled = true;
             super.recomputeViewAttributes(child);
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
index 7476ba6..1c6810a 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_LayoutParamsTest.java
@@ -16,24 +16,36 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.cts.util.XmlUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-public class ViewGroup_LayoutParamsTest extends AndroidTestCase {
-    private ViewGroup.LayoutParams mLayoutParams;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewGroup_LayoutParamsTest {
+    private Context mContext;
 
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         // new the MarginLayoutParams instance
         XmlResourceParser parser = mContext.getResources().getLayout(
@@ -47,6 +59,7 @@
         new ViewGroup.LayoutParams(temp);
     }
 
+    @Test
     public void testSetBaseAttributes() throws XmlPullParserException, IOException {
         MockLayoutParams mockLayoutParams = new MockLayoutParams(240, 320);
 
@@ -63,18 +76,10 @@
     }
 
     private class MockLayoutParams extends LayoutParams {
-        public MockLayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-        }
-
         public MockLayoutParams(int width, int height) {
             super(width, height);
         }
 
-        public MockLayoutParams(LayoutParams source) {
-            super(source);
-        }
-
         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
             super.setBaseAttributes(a, widthAttr, heightAttr);
         }
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
index 2bf3f8b..34a6020 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
@@ -16,31 +16,39 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.view.cts.util.XmlUtils;
 import android.widget.LinearLayout;
 
-public class ViewGroup_MarginLayoutParamsTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    private ViewGroup.MarginLayoutParams mMarginLayoutParams;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewGroup_MarginLayoutParamsTest {
     private Context mContext;
+    private ViewGroup.MarginLayoutParams mMarginLayoutParams;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mMarginLayoutParams = null;
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
     public void testConstructor() {
-        mMarginLayoutParams = null;
         // create a new MarginLayoutParams instance
         XmlResourceParser p = mContext.getResources().getLayout(
                 R.layout.viewgroup_margin_layout);
@@ -68,9 +76,9 @@
         ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 480);
         mMarginLayoutParams = new ViewGroup.MarginLayoutParams(lp);
         assertNotNull(mMarginLayoutParams);
-
     }
 
+    @Test
     public void testSetMargins() {
         // create a new MarginLayoutParams instance
         mMarginLayoutParams = new ViewGroup.MarginLayoutParams(320, 480);
@@ -86,6 +94,7 @@
         assertEquals(false, mMarginLayoutParams.isMarginRelative());
     }
 
+    @Test
     public void testSetMarginsRelative() {
         // create a new MarginLayoutParams instance
         mMarginLayoutParams = new ViewGroup.MarginLayoutParams(320, 480);
@@ -103,6 +112,7 @@
         assertEquals(true, mMarginLayoutParams.isMarginRelative());
     }
 
+    @Test
     public void testResolveMarginsRelative() {
         ViewGroup vg = new LinearLayout(mContext);
 
@@ -171,6 +181,7 @@
         assertEquals(true, mMarginLayoutParams.isMarginRelative());
     }
 
+    @Test
     public void testResolveMarginsExplicit() {
         // LTR / relative margin case
         mMarginLayoutParams = new ViewGroup.MarginLayoutParams(320, 480);
@@ -206,4 +217,44 @@
 
         assertEquals(true, mMarginLayoutParams.isMarginRelative());
     }
+
+    @Test
+    public void testVerticalHorizontalMargins() {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+
+        LinearLayout viewGroup = (LinearLayout)
+                inflater.inflate(R.layout.viewgroup_margin_layout_verticalhorizontal, null);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY);
+        viewGroup.measure(measureSpec, measureSpec);
+        viewGroup.layout(0, 0, 1000, 1000);
+
+        View view1 = viewGroup.findViewById(R.id.view1);
+        View view2 = viewGroup.findViewById(R.id.view2);
+        View view3 = viewGroup.findViewById(R.id.view3);
+        View view4 = viewGroup.findViewById(R.id.view4);
+        View view5 = viewGroup.findViewById(R.id.view5);
+        View view6 = viewGroup.findViewById(R.id.view6);
+
+        int defaultWidth = view1.getWidth();
+        int defaultHeight = view1.getHeight();
+        int marginPixels = (int) (mContext.getResources().getDisplayMetrics().density * 10 + .5f);
+
+        assertEquals("Width value", defaultWidth, view1.getWidth());
+        assertEquals("Height value", defaultHeight, view1.getHeight());
+
+        assertEquals("Width value", defaultWidth - 2 * marginPixels, view2.getWidth());
+        assertEquals("Height value", defaultHeight, view2.getHeight());
+
+        assertEquals("Width value", defaultWidth, view3.getWidth());
+        assertEquals("Height value", defaultHeight - 2 * marginPixels, view3.getHeight());
+
+        assertEquals("Width value", defaultWidth - 2 * marginPixels, view4.getWidth());
+        assertEquals("Height value", defaultHeight - 2 * marginPixels, view4.getHeight());
+
+        assertEquals("Width value", defaultWidth - 2 * marginPixels, view5.getWidth());
+        assertEquals("Height value", defaultHeight - 2 * marginPixels, view5.getHeight());
+
+        assertEquals("Width value", defaultWidth - 2 * marginPixels, view6.getWidth());
+        assertEquals("Height value", defaultHeight - 2 * marginPixels, view6.getHeight());
+    }
 }
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..e82cf37
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/ViewOutlineProviderTest.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 android.view.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.annotation.NonNull;
+import android.content.Context;
+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.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewOutlineProviderTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @UiThreadTest
+    @Test
+    public void testBackground() {
+        View view = new View(mContext);
+        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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testBounds() {
+        View view = new View(mContext);
+
+        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
+    }
+
+    @UiThreadTest
+    @Test
+    public void testPaddedBounds() {
+        View view = new View(mContext);
+
+        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/ViewOverlayTest.java b/tests/tests/view/src/android/view/cts/ViewOverlayTest.java
index 32477c9..b1f7363 100644
--- a/tests/tests/view/src/android/view/cts/ViewOverlayTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewOverlayTest.java
@@ -16,64 +16,71 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertNotNull;
+
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
 import android.view.View;
 import android.view.ViewOverlay;
 import android.view.cts.util.DrawingUtils;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.List;
 
-@SmallTest
-public class ViewOverlayTest extends ActivityInstrumentationTestCase2<ViewOverlayCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewOverlayTest {
     private View mViewWithOverlay;
     private ViewOverlay mViewOverlay;
 
-    public ViewOverlayTest() {
-        super("android.view.cts", ViewOverlayCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewOverlayCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewOverlayCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mViewWithOverlay = getActivity().findViewById(R.id.view_with_overlay);
+    @Before
+    public void setup() {
+        mViewWithOverlay = mActivityRule.getActivity().findViewById(R.id.view_with_overlay);
         mViewOverlay = mViewWithOverlay.getOverlay();
     }
 
+    @Test
     public void testBasics() {
         DrawingUtils.assertAllPixelsOfColor("Default fill", mViewWithOverlay,
                 Color.WHITE, null);
         assertNotNull("Overlay is not null", mViewOverlay);
     }
 
-    public void testAddNullDrawable() throws Throwable {
-        try {
-            runTestOnUiThread(() -> mViewOverlay.add(null));
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddNullDrawable() {
+         mViewOverlay.add(null);
     }
 
-    public void testRemoveNullDrawable() throws Throwable {
-        try {
-            runTestOnUiThread(() -> mViewOverlay.remove(null));
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testRemoveNullDrawable() {
+        mViewOverlay.remove(null);
     }
 
-    public void testOverlayWithOneDrawable() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithOneDrawable() {
         // Add one colored drawable to the overlay
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(20, 30, 40, 50);
-        runTestOnUiThread(() -> mViewOverlay.add(redDrawable));
+        mViewOverlay.add(redDrawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(20, 30, 40, 50), Color.RED));
@@ -81,20 +88,19 @@
                 Color.WHITE, colorRectangles);
 
         // Now remove that drawable from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewOverlay.remove(redDrawable));
+        mViewOverlay.remove(redDrawable);
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testAddTheSameDrawableTwice() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testAddTheSameDrawableTwice() {
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(20, 30, 40, 50);
-        runTestOnUiThread(
-                () -> {
-                    // Add the same drawable twice
-                    mViewOverlay.add(redDrawable);
-                    mViewOverlay.add(redDrawable);
-                });
+        // Add the same drawable twice
+        mViewOverlay.add(redDrawable);
+        mViewOverlay.add(redDrawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(20, 30, 40, 50), Color.RED));
@@ -102,34 +108,35 @@
                 Color.WHITE, colorRectangles);
 
         // Now remove that drawable from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewOverlay.remove(redDrawable));
+        mViewOverlay.remove(redDrawable);
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testRemoveTheSameDrawableTwice() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testRemoveTheSameDrawableTwice() {
         // Add one colored drawable to the overlay
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(20, 30, 40, 50);
-        runTestOnUiThread(() -> mViewOverlay.add(redDrawable));
+        mViewOverlay.add(redDrawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(20, 30, 40, 50), Color.RED));
         DrawingUtils.assertAllPixelsOfColor("Overlay with one red drawable", mViewWithOverlay,
                 Color.WHITE, colorRectangles);
 
-        // Now remove that drawable from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(
-                () -> {
-                    // Remove the drawable twice. The second should be a no-op
-                    mViewOverlay.remove(redDrawable);
-                    mViewOverlay.remove(redDrawable);
-                });
+        // Now remove that drawable from the overlay and test that we're back to pure white fill.
+        // Remove the drawable twice. The second should be a no-op
+        mViewOverlay.remove(redDrawable);
+        mViewOverlay.remove(redDrawable);
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayWithNonOverlappingDrawables() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithNonOverlappingDrawables() {
         // Add three color drawables to the overlay
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(10, 20, 30, 40);
@@ -138,12 +145,9 @@
         final Drawable blueDrawable = new ColorDrawable(Color.BLUE);
         blueDrawable.setBounds(40, 60, 80, 90);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewOverlay.add(redDrawable);
-                    mViewOverlay.add(greenDrawable);
-                    mViewOverlay.add(blueDrawable);
-                });
+        mViewOverlay.add(redDrawable);
+        mViewOverlay.add(greenDrawable);
+        mViewOverlay.add(blueDrawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
@@ -153,7 +157,7 @@
                 Color.WHITE, colorRectangles);
 
         // Remove one of the drawables from the overlay
-        runTestOnUiThread(() -> mViewOverlay.remove(greenDrawable));
+        mViewOverlay.remove(greenDrawable);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.RED));
         colorRectangles.add(new Pair<>(new Rect(40, 60, 80, 90), Color.BLUE));
@@ -161,23 +165,22 @@
                 Color.WHITE, colorRectangles);
 
         // Clear all drawables from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewOverlay.clear());
+        mViewOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayWithOverlappingDrawables() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayWithOverlappingDrawables() {
         // Add two overlapping color drawables to the overlay
         final Drawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(10, 20, 60, 40);
         final Drawable greenDrawable = new ColorDrawable(Color.GREEN);
         greenDrawable.setBounds(30, 20, 80, 40);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewOverlay.add(redDrawable);
-                    mViewOverlay.add(greenDrawable);
-                });
+        mViewOverlay.add(redDrawable);
+        mViewOverlay.add(greenDrawable);
 
         // Our overlay drawables overlap in horizontal 30-60 range. Here we test that the
         // second drawable is the one that is drawn last in that range.
@@ -188,23 +191,25 @@
                 Color.WHITE, colorRectangles);
 
         // Remove the second from the overlay
-        runTestOnUiThread(() -> mViewOverlay.remove(greenDrawable));
+        mViewOverlay.remove(greenDrawable);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(10, 20, 60, 40), Color.RED));
         DrawingUtils.assertAllPixelsOfColor("Overlay with one drawable", mViewWithOverlay,
                 Color.WHITE, colorRectangles);
 
         // Clear all drawables from the overlay and test that we're back to pure white fill
-        runTestOnUiThread(() -> mViewOverlay.clear());
+        mViewOverlay.clear();
         DrawingUtils.assertAllPixelsOfColor("Back to default fill", mViewWithOverlay,
                 Color.WHITE, null);
     }
 
-    public void testOverlayDynamicChangesToDrawable() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayDynamicChangesToDrawable() {
         // Add one colored drawable to the overlay
         final ColorDrawable drawable = new ColorDrawable(Color.RED);
         drawable.setBounds(20, 30, 40, 50);
-        runTestOnUiThread(() -> mViewOverlay.add(drawable));
+        mViewOverlay.add(drawable);
 
         final List<Pair<Rect, Integer>> colorRectangles = new ArrayList<>();
         colorRectangles.add(new Pair<>(new Rect(20, 30, 40, 50), Color.RED));
@@ -216,32 +221,31 @@
         // off a redraw pass at some point. Here we are testing a subset of that - that the
         // next time a redraw of View / ViewOverlay happens, it catches the new state of our
         // original drawable.
-        runTestOnUiThread(() -> drawable.setBounds(50, 10, 80, 90));
+        drawable.setBounds(50, 10, 80, 90);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(50, 10, 80, 90), Color.RED));
         DrawingUtils.assertAllPixelsOfColor("Red drawable moved", mViewWithOverlay,
                 Color.WHITE, colorRectangles);
 
         // Update the color of our drawable. Same (partial) testing as before.
-        runTestOnUiThread(() -> drawable.setColor(Color.GREEN));
+        drawable.setColor(Color.GREEN);
         colorRectangles.clear();
         colorRectangles.add(new Pair<>(new Rect(50, 10, 80, 90), Color.GREEN));
         DrawingUtils.assertAllPixelsOfColor("Drawable is green now", mViewWithOverlay,
                 Color.WHITE, colorRectangles);
     }
 
-    public void testOverlayDynamicChangesToOverlappingDrawables() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testOverlayDynamicChangesToOverlappingDrawables() {
         // Add two overlapping color drawables to the overlay
         final ColorDrawable redDrawable = new ColorDrawable(Color.RED);
         redDrawable.setBounds(10, 20, 60, 40);
         final ColorDrawable greenDrawable = new ColorDrawable(Color.GREEN);
         greenDrawable.setBounds(30, 20, 80, 40);
 
-        runTestOnUiThread(
-                () -> {
-                    mViewOverlay.add(redDrawable);
-                    mViewOverlay.add(greenDrawable);
-                });
+        mViewOverlay.add(redDrawable);
+        mViewOverlay.add(greenDrawable);
 
         // Our overlay drawables overlap in horizontal 30-60 range. This is the same test as
         // in testOverlayWithOverlappingDrawables
@@ -253,7 +257,7 @@
 
         // Now change the color of the first drawable and verify that it didn't "bump" it up
         // in the drawing order.
-        runTestOnUiThread(() -> redDrawable.setColor(Color.BLUE));
+        redDrawable.setColor(Color.BLUE);
         colorRectangles.add(new Pair<>(new Rect(10, 20, 30, 40), Color.BLUE));
         colorRectangles.add(new Pair<>(new Rect(30, 20, 80, 40), Color.GREEN));
         DrawingUtils.assertAllPixelsOfColor("Overlay with two drawables", mViewWithOverlay,
diff --git a/tests/tests/view/src/android/view/cts/ViewPaddingTest.java b/tests/tests/view/src/android/view/cts/ViewPaddingTest.java
new file mode 100644
index 0000000..b146f9d
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/ViewPaddingTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+package android.view.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewPaddingTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void testPadding() {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+
+        LinearLayout viewGroup = (LinearLayout)
+                inflater.inflate(R.layout.view_padding, null);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY);
+        viewGroup.measure(measureSpec, measureSpec);
+        viewGroup.layout(0, 0, 1000, 1000);
+
+        View view1 = viewGroup.findViewById(R.id.view1);
+        View view2 = viewGroup.findViewById(R.id.view2);
+        View view3 = viewGroup.findViewById(R.id.view3);
+        View view4 = viewGroup.findViewById(R.id.view4);
+        View view5 = viewGroup.findViewById(R.id.view5);
+        View view6 = viewGroup.findViewById(R.id.view6);
+        View view7 = viewGroup.findViewById(R.id.view7);
+        View view8 = viewGroup.findViewById(R.id.view8);
+        View view9 = viewGroup.findViewById(R.id.view9);
+        View view10 = viewGroup.findViewById(R.id.view10);
+
+        Rect defaultBounds = new Rect(view1.getLeft(), view1.getTop(), view1.getRight(),
+                view1.getBottom());
+        int insetLeft = mContext.getResources().getDimensionPixelSize(R.dimen.insetLeft);
+        int insetRight = mContext.getResources().getDimensionPixelSize(R.dimen.insetRight);
+        int insetTop = mContext.getResources().getDimensionPixelSize(R.dimen.insetTop);
+        int insetBottom = mContext.getResources().getDimensionPixelSize(R.dimen.insetBottom);
+        int insetAll = mContext.getResources().getDimensionPixelSize(R.dimen.insetAll);
+        int insetHorizontal =
+                mContext.getResources().getDimensionPixelSize(R.dimen.insetHorizontal);
+        int insetVertical = mContext.getResources().getDimensionPixelSize(R.dimen.insetVertical);
+
+        checkBounds(view2, defaultBounds, insetAll, insetAll, insetAll, insetAll);
+        checkBounds(view3, defaultBounds, insetLeft, insetTop, 0, 0);
+        checkBounds(view4, defaultBounds, 0, 0, insetRight, insetBottom);
+        checkBounds(view5, defaultBounds, insetLeft, insetTop, insetRight, insetBottom);
+        checkBounds(view6, defaultBounds, insetHorizontal, 0, insetHorizontal, 0);
+        checkBounds(view7, defaultBounds, 0, insetVertical, 0, insetVertical);
+        checkBounds(view8, defaultBounds, insetHorizontal, insetVertical, insetHorizontal,
+                insetVertical);
+        checkBounds(view9, defaultBounds, insetHorizontal, insetVertical, insetHorizontal,
+                insetVertical);
+        checkBounds(view10, defaultBounds, insetAll, insetAll, insetAll, insetAll);
+    }
+
+    private void checkBounds(View view, Rect defaultBounds,
+            int insetLeft, int insetTop, int insetRight, int insetBottom) {
+        assertEquals("Left", defaultBounds.left + insetLeft, view.getLeft());
+        assertEquals("Top", defaultBounds.top + insetTop, view.getTop());
+        assertEquals("Right", defaultBounds.right - insetRight, view.getRight());
+        assertEquals("Bottom", defaultBounds.bottom - insetBottom, view.getBottom());
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
index 4268837..e383c37 100644
--- a/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewStubCtsActivity.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.cts.R;
 
 public class ViewStubCtsActivity extends Activity {
     @Override
diff --git a/tests/tests/view/src/android/view/cts/ViewStubTest.java b/tests/tests/view/src/android/view/cts/ViewStubTest.java
index bdb988d..3aef2bb 100644
--- a/tests/tests/view/src/android/view/cts/ViewStubTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewStubTest.java
@@ -16,85 +16,106 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+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.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Activity;
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
 import android.view.ViewParent;
 import android.view.ViewStub;
-import android.view.ViewStub.OnInflateListener;
 import android.widget.LinearLayout;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link ViewStub}.
  */
-public class ViewStubTest extends ActivityInstrumentationTestCase<ViewStubCtsActivity> {
-    private Context mContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewStubTest {
     private Activity mActivity;
 
-    public ViewStubTest() {
-        super("android.view.cts", ViewStubCtsActivity.class);
+    @Rule
+    public ActivityTestRule<ViewStubCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewStubCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getContext();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.viewstub_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
         assertNotNull(attrs);
 
-        new ViewStub(mContext);
+        new ViewStub(mActivity);
 
-        new ViewStub(mContext, 10);
+        new ViewStub(mActivity, 10);
 
-        new ViewStub(mContext, attrs);
+        new ViewStub(mActivity, attrs);
 
-        new ViewStub(mContext, attrs, 30);
+        new ViewStub(mActivity, attrs, 30);
     }
 
+    @Test
     public void testDraw() {
-        ViewStub viewStub = new ViewStub(mContext);
+        ViewStub viewStub = new ViewStub(mActivity);
         // if the function draw() does not throw any exception,
         // we think it is right, because it's an empty method.
         viewStub.draw(null);
     }
 
     @UiThreadTest
+    @Test
     public void testSetVisibility() {
         final ViewStub viewStub1 = (ViewStub) mActivity.findViewById(R.id.viewstub);
-        MockOnInflateListener listener = new MockOnInflateListener();
+        final ViewStub.OnInflateListener listener = mock(ViewStub.OnInflateListener.class);
         viewStub1.setOnInflateListener(listener);
-        assertFalse(listener.hasCalledOnInflate());
+        verifyZeroInteractions(listener);
         assertNotNull(viewStub1.getParent());
 
         // set GONE
         viewStub1.setVisibility(View.GONE);
         assertEquals(View.GONE, viewStub1.getVisibility());
         // does not call inflate
-        assertFalse(listener.hasCalledOnInflate());
+        verifyZeroInteractions(listener);
         assertNotNull(viewStub1.getParent());
 
         // set VISIBLE
         viewStub1.setVisibility(View.VISIBLE);
         assertEquals(View.VISIBLE, viewStub1.getVisibility());
-        //assure the inflate is called
-        assertTrue(listener.hasCalledOnInflate());
+        // assure the inflate is called
+        ArgumentCaptor<View> inflatedViewCaptor = ArgumentCaptor.forClass(View.class);
+        verify(listener, times(1)).onInflate(eq(viewStub1), inflatedViewCaptor.capture());
+        // We're expecting inflatedId attribute on ViewStub to take precedence over the
+        // id attribute defined on the inflated view
+        assertEquals(R.id.inflated_id, inflatedViewCaptor.getValue().getId());
         assertNull(viewStub1.getParent());
 
         // set INVISIBLE when parent is null
-        final ViewStub viewStub2 = new ViewStub(mContext);
+        final ViewStub viewStub2 = new ViewStub(mActivity);
         assertNull(viewStub2.getParent());
         try {
             viewStub2.setVisibility(View.INVISIBLE);
@@ -104,8 +125,9 @@
         assertEquals(View.INVISIBLE, viewStub2.getVisibility());
     }
 
+    @Test
     public void testAccessLayoutResource() {
-        ViewStub viewStub = new ViewStub(mContext);
+        ViewStub viewStub = new ViewStub(mActivity);
 
         viewStub.setLayoutResource(R.layout.viewstub_layout);
         assertEquals(R.layout.viewstub_layout, viewStub.getLayoutResource());
@@ -117,8 +139,9 @@
         assertEquals(-1, viewStub.getLayoutResource());
     }
 
+    @Test
     public void testViewStubHasNoDimensions() {
-        ViewStub viewStub = new ViewStub(mContext);
+        ViewStub viewStub = new ViewStub(mActivity);
 
         viewStub.forceLayout();
         viewStub.measure(200, 300);
@@ -131,30 +154,29 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetOnInflateListener() {
         final ViewStub viewStub = (ViewStub) mActivity.findViewById(R.id.viewstub);
-        final MockOnInflateListener listener = new MockOnInflateListener();
+        final ViewStub.OnInflateListener listener = mock(ViewStub.OnInflateListener.class);
 
         viewStub.setOnInflateListener(listener);
-        assertFalse(listener.hasCalledOnInflate());
-        viewStub.inflate();
-        assertTrue(listener.hasCalledOnInflate());
+        verifyZeroInteractions(listener);
+        final View inflated = viewStub.inflate();
+        verify(listener, times(1)).onInflate(viewStub, inflated);
     }
 
     @UiThreadTest
+    @Test
     public void testSetOnInflateListenerError() {
         final ViewStub viewStub = (ViewStub) mActivity.findViewById(R.id.viewstub);
 
         viewStub.setOnInflateListener(null);
-        try {
-            viewStub.inflate();
-        } catch (NullPointerException e) {
-            fail("should not throw NullPointerException");
-        }
+        viewStub.inflate();
     }
 
+    @Test
     public void testAccessInflatedId() {
-        ViewStub viewStub = new ViewStub(mContext);
+        ViewStub viewStub = new ViewStub(mActivity);
         assertEquals("Default ViewStub inflated ID is View.NO_ID",
                 View.NO_ID, viewStub.getInflatedId());
 
@@ -168,13 +190,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testInflate() {
         final ViewStub viewStub = (ViewStub) mActivity.findViewById(R.id.viewstub);
         final ViewParent vsParent = viewStub.getParent();
-        final MockOnInflateListener listener = new MockOnInflateListener();
+        final ViewStub.OnInflateListener listener = mock(ViewStub.OnInflateListener.class);
 
         viewStub.setOnInflateListener(listener);
-        assertFalse(listener.hasCalledOnInflate());
+        verifyZeroInteractions(listener);
         assertNotNull(vsParent);
 
         View view = viewStub.inflate();
@@ -185,43 +208,23 @@
         assertNull(viewStub.getParent());
         assertSame(vsParent, view.getParent());
         assertEquals(R.id.inflated_id, view.getId());
-        assertTrue(listener.hasCalledOnInflate());
+        verify(listener, times(1)).onInflate(viewStub, view);
     }
 
-    public void testInflateError() {
+    @Test(expected=IllegalArgumentException.class)
+    public void testInflateErrorInvalidLayoutResource() {
         final ViewStub viewStub = (ViewStub) mActivity.findViewById(R.id.viewstub);
 
         // mLayoutResource is 0
         viewStub.setLayoutResource(0);
-        try {
-            viewStub.inflate();
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        // parent is null
-        ViewStub stub = new ViewStub(mContext);
-        assertNull(stub.getParent());
-        try {
-            stub.inflate();
-            fail("should throw IllegalStateException");
-        } catch (IllegalStateException e) {
-        }
+        viewStub.inflate();
     }
 
-    private class MockOnInflateListener implements OnInflateListener {
-        private boolean mCalledOnInflate = false;
-
-        public void onInflate(ViewStub stub, View inflated) {
-            mCalledOnInflate = true;
-        }
-
-        public boolean hasCalledOnInflate() {
-            return mCalledOnInflate;
-        }
-
-        public void reset() {
-            mCalledOnInflate = false;
-        }
+    @Test(expected=IllegalStateException.class)
+    public void testInflateErrorNullParent() {
+        // parent is null
+        ViewStub stub = new ViewStub(mActivity);
+        assertNull(stub.getParent());
+        stub.inflate();
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 19e267d..86decd9 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -16,17 +16,35 @@
 
 package android.view.cts;
 
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+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 static org.mockito.Mockito.when;
 
-import android.graphics.BitmapFactory;
-import com.android.internal.view.menu.ContextMenuBuilder;
-
+import android.app.Instrumentation;
+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.PollingCheck;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -41,9 +59,11 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.Vibrator;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -65,13 +85,7 @@
 import android.view.TouchDelegate;
 import android.view.View;
 import android.view.View.BaseSavedState;
-import android.view.View.OnClickListener;
-import android.view.View.OnContextClickListener;
-import android.view.View.OnCreateContextMenuListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnKeyListener;
 import android.view.View.OnLongClickListener;
-import android.view.View.OnTouchListener;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -85,9 +99,18 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
-import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.view.menu.ContextMenuBuilder;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -99,35 +122,38 @@
 /**
  * Test {@link View}.
  */
-public class ViewTest extends ActivityInstrumentationTestCase2<ViewTestCtsActivity> {
-    public ViewTest() {
-        super(ViewTestCtsActivity.class);
-    }
-
-    private Resources mResources;
-    private MockViewParent mMockParent;
-    private ViewTestCtsActivity mActivity;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewTest {
     /** timeout delta when wait in case the system is sluggish */
     private static final long TIMEOUT_DELTA = 10000;
 
     private static final String LOG_TAG = "ViewTest";
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+    private Instrumentation mInstrumentation;
+    private ViewTestCtsActivity mActivity;
+    private Resources mResources;
+    private MockViewParent mMockParent;
+
+    @Rule
+    public ActivityTestRule<ViewTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewTestCtsActivity.class);
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mCtsActivityRule =
+            new ActivityTestRule<>(CtsActivity.class, false, false);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mResources = mActivity.getResources();
         mMockParent = new MockViewParent(mActivity);
         assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
     }
 
+    @Test
     public void testConstructor() {
         new View(mActivity);
 
@@ -137,26 +163,28 @@
 
         new View(mActivity, null);
 
-        try {
-            new View(null, attrs);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
-
         new View(mActivity, attrs, 0);
 
         new View(mActivity, null, 1);
+    }
 
-        try {
-            new View(null, null, 1);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout);
+        final AttributeSet attrs = Xml.asAttributeSet(parser);
+        new View(null, attrs);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new View(null, null, 1);
     }
 
     // Test that validates that Views can be constructed on a thread that
     // does not have a Looper. Necessary for async inflation
     private Pair<Class<?>, Throwable> sCtorException = null;
+
+    @Test
     public void testConstructor2() throws Exception {
         final Object[] args = new Object[] { mActivity, null };
         final CountDownLatch latch = new CountDownLatch(1);
@@ -172,7 +200,7 @@
                         constructor.setAccessible(true);
                         constructor.newInstance(args);
                     } catch (Throwable t) {
-                        sCtorException = new Pair<Class<?>, Throwable>(clazz, t);
+                        sCtorException = new Pair<>(clazz, t);
                         break;
                     }
                 }
@@ -186,16 +214,19 @@
         }
     }
 
+    @Test
     public void testGetContext() {
         View view = new View(mActivity);
         assertSame(mActivity, view.getContext());
     }
 
+    @Test
     public void testGetResources() {
         View view = new View(mActivity);
         assertSame(mResources, view.getResources());
     }
 
+    @Test
     public void testGetAnimation() {
         Animation animation = new AlphaAnimation(0.0f, 1.0f);
         View view = new View(mActivity);
@@ -208,6 +239,7 @@
         assertNull(view.getAnimation());
     }
 
+    @Test
     public void testSetAnimation() {
         Animation animation = new AlphaAnimation(0.0f, 1.0f);
         View view = new View(mActivity);
@@ -223,6 +255,7 @@
         assertNull(view.getAnimation());
     }
 
+    @Test
     public void testClearAnimation() {
         Animation animation = new AlphaAnimation(0.0f, 1.0f);
         View view = new View(mActivity);
@@ -237,22 +270,24 @@
         assertNull(view.getAnimation());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testStartAnimationNull() {
+        View view = new View(mActivity);
+        view.startAnimation(null);
+    }
+
+    @Test
     public void testStartAnimation() {
         Animation animation = new AlphaAnimation(0.0f, 1.0f);
         View view = new View(mActivity);
 
-        try {
-            view.startAnimation(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
-
         animation.setStartTime(1L);
         assertEquals(1L, animation.getStartTime());
         view.startAnimation(animation);
         assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime());
     }
 
+    @Test
     public void testOnAnimation() throws Throwable {
         final Animation animation = new AlphaAnimation(0.0f, 1.0f);
         long duration = 2000L;
@@ -260,36 +295,24 @@
         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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.startAnimation(animation));
+        mInstrumentation.waitForIdleSync();
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnAnimationStart();
-            }
-        }.run();
+        PollingCheck.waitFor(view::hasCalledOnAnimationStart);
 
         // check whether it has ended after duration, and alpha changed during this time.
-        new PollingCheck(duration + TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnSetAlpha() && view.hasCalledOnAnimationEnd();
-            }
-        }.run();
+        PollingCheck.waitFor(duration + TIMEOUT_DELTA,
+                () -> view.hasCalledOnSetAlpha() && view.hasCalledOnAnimationEnd());
     }
 
+    @Test
     public void testGetParent() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         ViewGroup parent = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         assertSame(parent, view.getParent());
     }
 
+    @Test
     public void testAccessScrollIndicators() {
         View view = mActivity.findViewById(R.id.viewlayout_root);
 
@@ -297,6 +320,7 @@
                 view.getScrollIndicators());
     }
 
+    @Test
     public void testSetScrollIndicators() {
         View view = new View(mActivity);
 
@@ -315,6 +339,7 @@
         assertEquals(0, view.getScrollIndicators());
     }
 
+    @Test
     public void testFindViewById() {
         View parent = mActivity.findViewById(R.id.viewlayout_root);
         assertSame(parent, parent.findViewById(R.id.viewlayout_root));
@@ -323,36 +348,33 @@
         assertTrue(view instanceof MockView);
     }
 
+    @Test
     public void testAccessTouchDelegate() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         Rect rect = new Rect();
         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));
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mActivity.addContentView(button,
+                new LinearLayout.LayoutParams(WRAP_CONTENT, btnHeight)));
+        mInstrumentation.waitForIdleSync();
         button.getHitRect(rect);
-        MockTouchDelegate delegate = new MockTouchDelegate(rect, button);
+        TouchDelegate delegate = spy(new TouchDelegate(rect, button));
 
         assertNull(view.getTouchDelegate());
 
         view.setTouchDelegate(delegate);
         assertSame(delegate, view.getTouchDelegate());
-        assertFalse(delegate.hasCalledOnTouchEvent());
-        TouchUtils.clickView(this, view);
+        verify(delegate, never()).onTouchEvent(any());
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, view);
         assertTrue(view.hasCalledOnTouchEvent());
-        assertTrue(delegate.hasCalledOnTouchEvent());
+        verify(delegate, times(1)).onTouchEvent(any());
 
         view.setTouchDelegate(null);
         assertNull(view.getTouchDelegate());
     }
 
+    @Test
     public void testMouseEventCallsGetPointerIcon() {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -375,8 +397,8 @@
 
         MotionEvent event = MotionEvent.obtain(0, eventTime, MotionEvent.ACTION_HOVER_MOVE,
                 1, pointerIds, pointerCoords, 0, 0, 0, 0, 0, InputDevice.SOURCE_MOUSE, 0);
-        getInstrumentation().sendPointerSync(event);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.sendPointerSync(event);
+        mInstrumentation.waitForIdleSync();
 
         assertTrue(view.hasCalledOnResolvePointerIcon());
 
@@ -384,6 +406,7 @@
         assertFalse(view2.hasCalledOnResolvePointerIcon());
     }
 
+    @Test
     public void testAccessPointerIcon() {
         View view = mActivity.findViewById(R.id.pointer_icon_layout);
         MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
@@ -416,6 +439,7 @@
         event.recycle();
     }
 
+    @Test
     public void testCreatePointerIcons() {
         assertSystemPointerIcon(PointerIcon.TYPE_NULL);
         assertSystemPointerIcon(PointerIcon.TYPE_DEFAULT);
@@ -451,6 +475,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessTag() {
         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
@@ -480,18 +505,14 @@
         assertNull(mockView.getTag());
     }
 
+    @Test
     public void testOnSizeChanged() throws Throwable {
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         final MockView mockView = new MockView(mActivity);
         assertEquals(-1, mockView.getOldWOnSizeChanged());
         assertEquals(-1, mockView.getOldHOnSizeChanged());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.addView(mockView);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.hasCalledOnSizeChanged());
         assertEquals(0, mockView.getOldWOnSizeChanged());
         assertEquals(0, mockView.getOldHOnSizeChanged());
@@ -504,28 +525,23 @@
         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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.hasCalledOnSizeChanged());
         assertEquals(oldw, view.getOldWOnSizeChanged());
         assertEquals(oldh, view.getOldHOnSizeChanged());
     }
 
-    public void testGetHitRect() {
+
+    @Test(expected=NullPointerException.class)
+    public void testGetHitRectNull() {
         MockView view = new MockView(mActivity);
+        view.getHitRect(null);
+    }
+
+    @Test
+    public void testGetHitRect() {
         Rect outRect = new Rect();
-
-        try {
-            view.getHitRect(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
-
         View mockView = mActivity.findViewById(R.id.mock_view);
         mockView.getHitRect(outRect);
         assertEquals(0, outRect.left);
@@ -534,6 +550,7 @@
         assertEquals(mockView.getHeight(), outRect.bottom);
     }
 
+    @Test
     public void testForceLayout() {
         View view = new View(mActivity);
 
@@ -545,6 +562,7 @@
         assertTrue(view.isLayoutRequested());
     }
 
+    @Test
     public void testIsLayoutRequested() {
         View view = new View(mActivity);
 
@@ -556,6 +574,7 @@
         assertFalse(view.isLayoutRequested());
     }
 
+    @Test
     public void testRequestLayout() {
         MockView view = new MockView(mActivity);
         assertFalse(view.isLayoutRequested());
@@ -573,28 +592,26 @@
         assertTrue(mMockParent.hasRequestLayout());
     }
 
+    @Test
     public void testLayout() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         assertTrue(view.hasCalledOnLayout());
 
         view.reset();
         assertFalse(view.hasCalledOnLayout());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::requestLayout);
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.hasCalledOnLayout());
     }
 
+    @Test
     public void testGetBaseline() {
         View view = new View(mActivity);
 
         assertEquals(-1, view.getBaseline());
     }
 
+    @Test
     public void testAccessBackground() {
         View view = new View(mActivity);
         Drawable d1 = mResources.getDrawable(R.drawable.scenery);
@@ -612,6 +629,7 @@
         assertNull(view.getBackground());
     }
 
+    @Test
     public void testSetBackgroundResource() {
         View view = new View(mActivity);
 
@@ -624,6 +642,7 @@
         assertNull(view.getBackground());
     }
 
+    @Test
     public void testAccessDrawingCacheBackgroundColor() {
         View view = new View(mActivity);
 
@@ -636,6 +655,7 @@
         assertEquals(-1, view.getDrawingCacheBackgroundColor());
     }
 
+    @Test
     public void testSetBackgroundColor() {
         View view = new View(mActivity);
         ColorDrawable colorDrawable;
@@ -652,6 +672,7 @@
         assertEquals(0, colorDrawable.getAlpha());
     }
 
+    @Test
     public void testVerifyDrawable() {
         MockView view = new MockView(mActivity);
         Drawable d1 = mResources.getDrawable(R.drawable.scenery);
@@ -666,6 +687,7 @@
         assertFalse(view.verifyDrawable(d2));
     }
 
+    @Test
     public void testGetDrawingRect() {
         MockView view = new MockView(mActivity);
         Rect outRect = new Rect();
@@ -691,6 +713,7 @@
         assertEquals(mockView.getHeight(), outRect.bottom);
     }
 
+    @Test
     public void testGetFocusedRect() {
         MockView view = new MockView(mActivity);
         Rect outRect = new Rect();
@@ -709,6 +732,7 @@
         assertEquals(100, outRect.bottom);
     }
 
+    @Test
     public void testGetGlobalVisibleRectPoint() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
@@ -728,39 +752,24 @@
 
         // width is 0
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
+        mInstrumentation.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect, point));
 
-        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        Display display = mActivity.getWindowManager().getDefaultDisplay();
         int halfWidth = display.getWidth() / 2;
         int halfHeight = display.getHeight() /2;
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3));
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.getGlobalVisibleRect(rect, point));
         assertEquals(rcParent.left, rect.left);
         assertEquals(rcParent.top, rect.top);
@@ -770,6 +779,7 @@
         assertEquals(ptParent.y, point.y);
     }
 
+    @Test
     public void testGetGlobalVisibleRect() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
@@ -785,39 +795,24 @@
 
         // width is 0
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
+        mInstrumentation.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.getGlobalVisibleRect(rect));
 
-        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        Display display = mActivity.getWindowManager().getDefaultDisplay();
         int halfWidth = display.getWidth() / 2;
         int halfHeight = display.getHeight() /2;
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3));
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.getGlobalVisibleRect(rect));
         assertEquals(rcParent.left, rect.left);
         assertEquals(rcParent.top, rect.top);
@@ -825,6 +820,7 @@
         assertEquals(rect.top + halfHeight, rect.bottom);
     }
 
+    @Test
     public void testComputeHorizontalScroll() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -832,43 +828,29 @@
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(12, 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.scrollTo(12, 0));
+        mInstrumentation.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.scrollBy(12, 0));
+        mInstrumentation.waitForIdleSync();
         assertEquals(24, view.computeHorizontalScrollOffset());
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
 
         int newWidth = 200;
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(newWidth, 100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
+        mInstrumentation.waitForIdleSync();
         assertEquals(24, view.computeHorizontalScrollOffset());
         assertEquals(newWidth, view.getWidth());
         assertEquals(view.getWidth(), view.computeHorizontalScrollRange());
         assertEquals(view.getWidth(), view.computeHorizontalScrollExtent());
     }
 
+    @Test
     public void testComputeVerticalScroll() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -877,113 +859,95 @@
         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
 
         final int scrollToY = 34;
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(0, scrollToY);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.scrollTo(0, scrollToY));
+        mInstrumentation.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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.scrollBy(0, scrollByY));
+        mInstrumentation.waitForIdleSync();
         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
 
         int newHeight = 333;
-        final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, newHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        final LinearLayout.LayoutParams layoutParams =
+                new LinearLayout.LayoutParams(200, newHeight);
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
+        mInstrumentation.waitForIdleSync();
         assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset());
         assertEquals(newHeight, view.getHeight());
         assertEquals(view.getHeight(), view.computeVerticalScrollRange());
         assertEquals(view.getHeight(), view.computeVerticalScrollExtent());
     }
 
+    @Test
     public void testGetFadingEdgeStrength() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
-        assertEquals(0f, view.getLeftFadingEdgeStrength());
-        assertEquals(0f, view.getRightFadingEdgeStrength());
-        assertEquals(0f, view.getTopFadingEdgeStrength());
-        assertEquals(0f, view.getBottomFadingEdgeStrength());
+        assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(10, 10);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(1f, view.getLeftFadingEdgeStrength());
-        assertEquals(0f, view.getRightFadingEdgeStrength());
-        assertEquals(1f, view.getTopFadingEdgeStrength());
-        assertEquals(0f, view.getBottomFadingEdgeStrength());
+        mActivityRule.runOnUiThread(() -> view.scrollTo(10, 10));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(1f, view.getLeftFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f);
+        assertEquals(1f, view.getTopFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.scrollTo(-10, -10);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertEquals(0f, view.getLeftFadingEdgeStrength());
-        assertEquals(1f, view.getRightFadingEdgeStrength());
-        assertEquals(0f, view.getTopFadingEdgeStrength());
-        assertEquals(1f, view.getBottomFadingEdgeStrength());
+        mActivityRule.runOnUiThread(() -> view.scrollTo(-10, -10));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f);
+        assertEquals(1f, view.getRightFadingEdgeStrength(), 0.0f);
+        assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f);
+        assertEquals(1f, view.getBottomFadingEdgeStrength(), 0.0f);
     }
 
+    @Test
     public void testGetLeftFadingEdgeStrength() {
         MockView view = new MockView(mActivity);
 
-        assertEquals(0.0f, view.getLeftFadingEdgeStrength());
+        assertEquals(0.0f, view.getLeftFadingEdgeStrength(), 0.0f);
 
         view.scrollTo(1, 0);
-        assertEquals(1.0f, view.getLeftFadingEdgeStrength());
+        assertEquals(1.0f, view.getLeftFadingEdgeStrength(), 0.0f);
     }
 
+    @Test
     public void testGetRightFadingEdgeStrength() {
         MockView view = new MockView(mActivity);
 
-        assertEquals(0.0f, view.getRightFadingEdgeStrength());
+        assertEquals(0.0f, view.getRightFadingEdgeStrength(), 0.0f);
 
         view.scrollTo(-1, 0);
-        assertEquals(1.0f, view.getRightFadingEdgeStrength());
+        assertEquals(1.0f, view.getRightFadingEdgeStrength(), 0.0f);
     }
 
+    @Test
     public void testGetBottomFadingEdgeStrength() {
         MockView view = new MockView(mActivity);
 
-        assertEquals(0.0f, view.getBottomFadingEdgeStrength());
+        assertEquals(0.0f, view.getBottomFadingEdgeStrength(), 0.0f);
 
         view.scrollTo(0, -2);
-        assertEquals(1.0f, view.getBottomFadingEdgeStrength());
+        assertEquals(1.0f, view.getBottomFadingEdgeStrength(), 0.0f);
     }
 
+    @Test
     public void testGetTopFadingEdgeStrength() {
         MockView view = new MockView(mActivity);
 
-        assertEquals(0.0f, view.getTopFadingEdgeStrength());
+        assertEquals(0.0f, view.getTopFadingEdgeStrength(), 0.0f);
 
         view.scrollTo(0, 2);
-        assertEquals(1.0f, view.getTopFadingEdgeStrength());
+        assertEquals(1.0f, view.getTopFadingEdgeStrength(), 0.0f);
     }
 
+    @Test
     public void testResolveSize() {
         assertEquals(50, View.resolveSize(50, View.MeasureSpec.UNSPECIFIED));
 
@@ -994,6 +958,7 @@
         assertEquals(20, View.resolveSize(20, 30 | View.MeasureSpec.AT_MOST));
     }
 
+    @Test
     public void testGetDefaultSize() {
         assertEquals(50, View.getDefaultSize(50, View.MeasureSpec.UNSPECIFIED));
 
@@ -1004,6 +969,7 @@
         assertEquals(30, View.getDefaultSize(20, 30 | View.MeasureSpec.AT_MOST));
     }
 
+    @Test
     public void testAccessId() {
         View view = new View(mActivity);
 
@@ -1016,6 +982,7 @@
         assertEquals(0xFFFFFFFF, view.getId());
     }
 
+    @Test
     public void testAccessLongClickable() {
         View view = new View(mActivity);
 
@@ -1028,6 +995,7 @@
         assertFalse(view.isLongClickable());
     }
 
+    @Test
     public void testAccessClickable() {
         View view = new View(mActivity);
 
@@ -1040,6 +1008,7 @@
         assertFalse(view.isClickable());
     }
 
+    @Test
     public void testAccessContextClickable() {
         View view = new View(mActivity);
 
@@ -1052,12 +1021,14 @@
         assertFalse(view.isContextClickable());
     }
 
+    @Test
     public void testGetContextMenuInfo() {
         MockView view = new MockView(mActivity);
 
         assertNull(view.getContextMenuInfo());
     }
 
+    @Test
     public void testSetOnCreateContextMenuListener() {
         View view = new View(mActivity);
         assertFalse(view.isLongClickable());
@@ -1065,32 +1036,35 @@
         view.setOnCreateContextMenuListener(null);
         assertTrue(view.isLongClickable());
 
-        view.setOnCreateContextMenuListener(new OnCreateContextMenuListenerImpl());
+        view.setOnCreateContextMenuListener(mock(View.OnCreateContextMenuListener.class));
         assertTrue(view.isLongClickable());
     }
 
+    @Test
     public void testCreateContextMenu() {
-        OnCreateContextMenuListenerImpl listener = new OnCreateContextMenuListenerImpl();
+        View.OnCreateContextMenuListener listener = mock(View.OnCreateContextMenuListener.class);
         MockView view = new MockView(mActivity);
         ContextMenu contextMenu = new ContextMenuBuilder(mActivity);
         view.setParent(mMockParent);
         view.setOnCreateContextMenuListener(listener);
         assertFalse(view.hasCalledOnCreateContextMenu());
         assertFalse(mMockParent.hasCreateContextMenu());
-        assertFalse(listener.hasOnCreateContextMenu());
+        verifyZeroInteractions(listener);
 
         view.createContextMenu(contextMenu);
         assertTrue(view.hasCalledOnCreateContextMenu());
         assertTrue(mMockParent.hasCreateContextMenu());
-        assertTrue(listener.hasOnCreateContextMenu());
-
-        try {
-            view.createContextMenu(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        verify(listener, times(1)).onCreateContextMenu(
+                eq(contextMenu), eq(view), any(ContextMenuInfo.class));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testCreateContextMenuNull() {
+        MockView view = new MockView(mActivity);
+        view.createContextMenu(null);
+    }
+
+    @Test
     public void testAddFocusables() {
         View view = new View(mActivity);
         ArrayList<View> viewList = new ArrayList<>();
@@ -1111,6 +1085,7 @@
         view.addFocusables(null, 0);
     }
 
+    @Test
     public void testGetFocusables() {
         View view = new View(mActivity);
         ArrayList<View> viewList;
@@ -1131,12 +1106,14 @@
         assertEquals(view, viewList.get(0));
     }
 
+    @Test
     public void testAddFocusablesWithoutTouchMode() {
         View view = new View(mActivity);
         assertFalse("test sanity", view.isInTouchMode());
         focusableInTouchModeTest(view, false);
     }
 
+    @Test
     public void testAddFocusablesInTouchMode() {
         View view = spy(new View(mActivity));
         when(view.isInTouchMode()).thenReturn(true);
@@ -1144,7 +1121,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);
@@ -1156,7 +1133,6 @@
             assertEquals(Collections.singletonList(view), views);
         }
 
-
         views.clear();
         view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL);
         assertEquals(Collections.singletonList(view), views);
@@ -1194,6 +1170,7 @@
         assertEquals(Collections.emptyList(), views);
     }
 
+    @Test
     public void testGetRootView() {
         MockView view = new MockView(mActivity);
 
@@ -1204,12 +1181,14 @@
         assertEquals(mMockParent, view.getRootView());
     }
 
+    @Test
     public void testGetSolidColor() {
         View view = new View(mActivity);
 
         assertEquals(0, view.getSolidColor());
     }
 
+    @Test
     public void testSetMinimumWidth() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getSuggestedMinimumWidth());
@@ -1221,6 +1200,7 @@
         assertEquals(-100, view.getSuggestedMinimumWidth());
     }
 
+    @Test
     public void testGetSuggestedMinimumWidth() {
         MockView view = new MockView(mActivity);
         Drawable d = mResources.getDrawable(R.drawable.scenery);
@@ -1241,6 +1221,7 @@
         assertEquals(drawableMinimumWidth + 10, view.getSuggestedMinimumWidth());
     }
 
+    @Test
     public void testSetMinimumHeight() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getSuggestedMinimumHeight());
@@ -1252,6 +1233,7 @@
         assertEquals(-100, view.getSuggestedMinimumHeight());
     }
 
+    @Test
     public void testGetSuggestedMinimumHeight() {
         MockView view = new MockView(mActivity);
         Drawable d = mResources.getDrawable(R.drawable.scenery);
@@ -1272,6 +1254,7 @@
         assertEquals(drawableMinimumHeight + 10, view.getSuggestedMinimumHeight());
     }
 
+    @Test
     public void testAccessWillNotCacheDrawing() {
         View view = new View(mActivity);
 
@@ -1281,6 +1264,7 @@
         assertTrue(view.willNotCacheDrawing());
     }
 
+    @Test
     public void testAccessDrawingCacheEnabled() {
         View view = new View(mActivity);
 
@@ -1290,6 +1274,7 @@
         assertTrue(view.isDrawingCacheEnabled());
     }
 
+    @Test
     public void testGetDrawingCache() {
         MockView view = new MockView(mActivity);
 
@@ -1313,6 +1298,7 @@
         assertNotSame(bitmap1, bitmap2);
     }
 
+    @Test
     public void testBuildAndDestroyDrawingCache() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -1328,6 +1314,7 @@
         assertNull(view.getDrawingCache());
     }
 
+    @Test
     public void testAccessWillNotDraw() {
         View view = new View(mActivity);
 
@@ -1337,6 +1324,7 @@
         assertTrue(view.willNotDraw());
     }
 
+    @Test
     public void testAccessDrawingCacheQuality() {
         View view = new View(mActivity);
 
@@ -1356,6 +1344,7 @@
         assertEquals(0x00180000, view.getDrawingCacheQuality());
     }
 
+    @Test
     public void testDispatchSetSelected() {
         MockView mockView1 = new MockView(mActivity);
         MockView mockView2 = new MockView(mActivity);
@@ -1371,6 +1360,7 @@
         assertFalse(mockView2.isSelected());
     }
 
+    @Test
     public void testAccessSelected() {
         View view = new View(mActivity);
 
@@ -1380,6 +1370,7 @@
         assertTrue(view.isSelected());
     }
 
+    @Test
     public void testDispatchSetPressed() {
         MockView mockView1 = new MockView(mActivity);
         MockView mockView2 = new MockView(mActivity);
@@ -1395,6 +1386,7 @@
         assertFalse(mockView2.isPressed());
     }
 
+    @Test
     public void testAccessPressed() {
         View view = new View(mActivity);
 
@@ -1404,6 +1396,7 @@
         assertTrue(view.isPressed());
     }
 
+    @Test
     public void testAccessSoundEffectsEnabled() {
         View view = new View(mActivity);
 
@@ -1413,6 +1406,7 @@
         assertFalse(view.isSoundEffectsEnabled());
     }
 
+    @Test
     public void testAccessKeepScreenOn() {
         View view = new View(mActivity);
 
@@ -1422,6 +1416,7 @@
         assertTrue(view.getKeepScreenOn());
     }
 
+    @Test
     public void testAccessDuplicateParentStateEnabled() {
         View view = new View(mActivity);
 
@@ -1431,6 +1426,7 @@
         assertTrue(view.isDuplicateParentStateEnabled());
     }
 
+    @Test
     public void testAccessEnabled() {
         View view = new View(mActivity);
 
@@ -1440,6 +1436,7 @@
         assertFalse(view.isEnabled());
     }
 
+    @Test
     public void testAccessSaveEnabled() {
         View view = new View(mActivity);
 
@@ -1449,16 +1446,17 @@
         assertFalse(view.isSaveEnabled());
     }
 
-    public void testShowContextMenu() {
+    @Test(expected=NullPointerException.class)
+    public void testShowContextMenuNullParent() {
         MockView view = new MockView(mActivity);
 
         assertNull(view.getParent());
-        try {
-            view.showContextMenu();
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        view.showContextMenu();
+    }
 
+    @Test
+    public void testShowContextMenu() {
+        MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
         assertFalse(mMockParent.hasShowContextMenuForChild());
 
@@ -1466,16 +1464,18 @@
         assertTrue(mMockParent.hasShowContextMenuForChild());
     }
 
-    public void testShowContextMenuXY() {
-        MockViewParent parent = new MockViewParent(mActivity);
+    @Test(expected=NullPointerException.class)
+    public void testShowContextMenuXYNullParent() {
         MockView view = new MockView(mActivity);
 
         assertNull(view.getParent());
-        try {
-            view.showContextMenu(0, 0);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        view.showContextMenu(0, 0);
+    }
+
+    @Test
+    public void testShowContextMenuXY() {
+        MockViewParent parent = new MockViewParent(mActivity);
+        MockView view = new MockView(mActivity);
 
         view.setParent(parent);
         assertFalse(parent.hasShowContextMenuForChildXY());
@@ -1484,6 +1484,7 @@
         assertTrue(parent.hasShowContextMenuForChildXY());
     }
 
+    @Test
     public void testFitSystemWindows() {
         final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout);
         final AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -1498,22 +1499,24 @@
         assertFalse(view.fitSystemWindows(null));
     }
 
+    @Test
     public void testPerformClick() {
         View view = new View(mActivity);
-        OnClickListenerImpl listener = new OnClickListenerImpl();
+        View.OnClickListener listener = mock(View.OnClickListener.class);
 
         assertFalse(view.performClick());
 
-        assertFalse(listener.hasOnClick());
+        verifyZeroInteractions(listener);
         view.setOnClickListener(listener);
 
         assertTrue(view.performClick());
-        assertTrue(listener.hasOnClick());
+        verify(listener,times(1)).onClick(view);
 
         view.setOnClickListener(null);
         assertFalse(view.performClick());
     }
 
+    @Test
     public void testSetOnClickListener() {
         View view = new View(mActivity);
         assertFalse(view.performClick());
@@ -1523,20 +1526,22 @@
         assertFalse(view.performClick());
         assertTrue(view.isClickable());
 
-        view.setOnClickListener(new OnClickListenerImpl());
+        view.setOnClickListener(mock(View.OnClickListener.class));
         assertTrue(view.performClick());
         assertTrue(view.isClickable());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testPerformLongClickNullParent() {
+        MockView view = new MockView(mActivity);
+        view.performLongClick();
+    }
+
+    @Test
     public void testPerformLongClick() {
         MockView view = new MockView(mActivity);
-        OnLongClickListenerImpl listener = new OnLongClickListenerImpl();
-
-        try {
-            view.performLongClick();
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        View.OnLongClickListener listener = mock(View.OnLongClickListener.class);
+        doReturn(true).when(listener).onLongClick(any());
 
         view.setParent(mMockParent);
         assertFalse(mMockParent.hasShowContextMenuForChild());
@@ -1546,22 +1551,23 @@
         view.setOnLongClickListener(listener);
         mMockParent.reset();
         assertFalse(mMockParent.hasShowContextMenuForChild());
-        assertFalse(listener.hasOnLongClick());
+        verifyZeroInteractions(listener);
         assertTrue(view.performLongClick());
         assertFalse(mMockParent.hasShowContextMenuForChild());
-        assertTrue(listener.hasOnLongClick());
+        verify(listener, times(1)).onLongClick(view);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testPerformLongClickXYNullParent() {
+        MockView view = new MockView(mActivity);
+        view.performLongClick(0, 0);
+    }
+
+    @Test
     public void testPerformLongClickXY() {
         MockViewParent parent = new MockViewParent(mActivity);
         MockView view = new MockView(mActivity);
 
-        try {
-            view.performLongClick(0, 0);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
-
         parent.addView(view);
         assertFalse(parent.hasShowContextMenuForChildXY());
 
@@ -1570,6 +1576,7 @@
         assertTrue(parent.hasShowContextMenuForChildXY());
     }
 
+    @Test
     public void testPerformLongClickXY_WithListener() {
         OnLongClickListener listener = mock(OnLongClickListener.class);
         when(listener.onLongClick(any(View.class))).thenReturn(true);
@@ -1589,6 +1596,7 @@
         verify(listener).onLongClick(view);
     }
 
+    @Test
     public void testSetOnLongClickListener() {
         MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
@@ -1599,24 +1607,28 @@
         assertFalse(view.performLongClick());
         assertTrue(view.isLongClickable());
 
-        view.setOnLongClickListener(new OnLongClickListenerImpl());
+        View.OnLongClickListener listener = mock(View.OnLongClickListener.class);
+        doReturn(true).when(listener).onLongClick(any());
+        view.setOnLongClickListener(listener);
         assertTrue(view.performLongClick());
         assertTrue(view.isLongClickable());
     }
 
+    @Test
     public void testPerformContextClick() {
         MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
-        OnContextClickListenerImpl listener = new OnContextClickListenerImpl();
+        View.OnContextClickListener listener = mock(View.OnContextClickListener.class);
+        doReturn(true).when(listener).onContextClick(any());
 
         view.setOnContextClickListener(listener);
-        assertFalse(listener.hasOnContextClick());
+        verifyZeroInteractions(listener);
 
         assertTrue(view.performContextClick());
-        assertTrue(listener.hasOnContextClick());
-        assertSame(view, listener.getLastViewContextClicked());
+        verify(listener, times(1)).onContextClick(view);
     }
 
+    @Test
     public void testSetOnContextClickListener() {
         MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
@@ -1624,14 +1636,17 @@
         assertFalse(view.performContextClick());
         assertFalse(view.isContextClickable());
 
-        view.setOnContextClickListener(new OnContextClickListenerImpl());
+        View.OnContextClickListener listener = mock(View.OnContextClickListener.class);
+        doReturn(true).when(listener).onContextClick(any());
+        view.setOnContextClickListener(listener);
         assertTrue(view.performContextClick());
         assertTrue(view.isContextClickable());
     }
 
+    @Test
     public void testAccessOnFocusChangeListener() {
         View view = new View(mActivity);
-        OnFocusChangeListener listener = new OnFocusChangeListenerImpl();
+        View.OnFocusChangeListener listener = mock(View.OnFocusChangeListener.class);
 
         assertNull(view.getOnFocusChangeListener());
 
@@ -1639,6 +1654,7 @@
         assertSame(listener, view.getOnFocusChangeListener());
     }
 
+    @Test
     public void testAccessNextFocusUpId() {
         View view = new View(mActivity);
 
@@ -1654,6 +1670,7 @@
         assertEquals(Integer.MIN_VALUE, view.getNextFocusUpId());
     }
 
+    @Test
     public void testAccessNextFocusDownId() {
         View view = new View(mActivity);
 
@@ -1669,6 +1686,7 @@
         assertEquals(Integer.MIN_VALUE, view.getNextFocusDownId());
     }
 
+    @Test
     public void testAccessNextFocusLeftId() {
         View view = new View(mActivity);
 
@@ -1684,6 +1702,7 @@
         assertEquals(Integer.MIN_VALUE, view.getNextFocusLeftId());
     }
 
+    @Test
     public void testAccessNextFocusRightId() {
         View view = new View(mActivity);
 
@@ -1699,6 +1718,7 @@
         assertEquals(Integer.MIN_VALUE, view.getNextFocusRightId());
     }
 
+    @Test
     public void testAccessMeasuredDimension() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getMeasuredWidth());
@@ -1709,6 +1729,7 @@
         assertEquals(30, view.getMeasuredHeight());
     }
 
+    @Test
     public void testMeasure() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         assertTrue(view.hasCalledOnMeasure());
@@ -1716,49 +1737,41 @@
         assertEquals(200, view.getMeasuredHeight());
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::requestLayout);
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.hasCalledOnMeasure());
         assertEquals(100, view.getMeasuredWidth());
         assertEquals(200, view.getMeasuredHeight());
 
         view.reset();
         final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams));
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.hasCalledOnMeasure());
         assertEquals(200, view.getMeasuredWidth());
         assertEquals(100, view.getMeasuredHeight());
     }
 
+    @Test(expected=NullPointerException.class)
+    public void setSetLayoutParamsNull() {
+        View view = new View(mActivity);
+        assertNull(view.getLayoutParams());
+
+        view.setLayoutParams(null);
+    }
+
+    @Test
     public void testAccessLayoutParams() {
         View view = new View(mActivity);
         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(10, 20);
 
-        assertNull(view.getLayoutParams());
-
-        try {
-            view.setLayoutParams(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
-
         assertFalse(view.isLayoutRequested());
         view.setLayoutParams(params);
         assertSame(params, view.getLayoutParams());
         assertTrue(view.isLayoutRequested());
     }
 
+    @Test
     public void testIsShown() {
         MockView view = new MockView(mActivity);
 
@@ -1774,6 +1787,7 @@
         assertFalse(view.isShown());
     }
 
+    @Test
     public void testGetDrawingTime() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1784,16 +1798,12 @@
         assertEquals(SystemClock.uptimeMillis(), view.getDrawingTime(), 1000);
     }
 
+    @Test
     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);
 
@@ -1812,14 +1822,12 @@
         view.scheduleDrawable(null, null, -1000);
     }
 
+    @Test
     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
@@ -1842,6 +1850,7 @@
         view.unscheduleDrawable(null, null);
     }
 
+    @Test
     public void testGetWindowVisibility() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1852,6 +1861,7 @@
         assertEquals(View.VISIBLE, view.getWindowVisibility());
     }
 
+    @Test
     public void testGetWindowToken() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1862,6 +1872,7 @@
         assertNotNull(view.getWindowToken());
     }
 
+    @Test
     public void testHasWindowFocus() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1870,37 +1881,35 @@
         // mAttachInfo is not null
         final View view2 = mActivity.findViewById(R.id.fit_windows);
         // Wait until the window has been focused.
-        new PollingCheck(TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return view2.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT_DELTA, view2::hasWindowFocus);
     }
 
+    @Test
     public void testGetHandler() {
         MockView view = new MockView(mActivity);
         // mAttachInfo is null
         assertNull(view.getHandler());
     }
 
+    @Test
     public void testRemoveCallbacks() throws InterruptedException {
         final long delay = 500L;
         View view = mActivity.findViewById(R.id.mock_view);
-        MockRunnable runner = new MockRunnable();
+        Runnable runner = mock(Runnable.class);
         assertTrue(view.postDelayed(runner, delay));
         assertTrue(view.removeCallbacks(runner));
         assertTrue(view.removeCallbacks(null));
-        assertTrue(view.removeCallbacks(new MockRunnable()));
+        assertTrue(view.removeCallbacks(mock(Runnable.class)));
         Thread.sleep(delay * 2);
-        assertFalse(runner.hasRun);
+        verifyZeroInteractions(runner);
         // check that the runner actually works
-        runner = new MockRunnable();
+        runner = mock(Runnable.class);
         assertTrue(view.postDelayed(runner, delay));
         Thread.sleep(delay * 2);
-        assertTrue(runner.hasRun);
+        verify(runner, times(1)).run();
     }
 
+    @Test
     public void testCancelLongPress() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1911,6 +1920,7 @@
         view.cancelLongPress();
     }
 
+    @Test
     public void testGetViewTreeObserver() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -1921,6 +1931,7 @@
         assertNotNull(view.getViewTreeObserver());
     }
 
+    @Test
     public void testGetWindowAttachCount() {
         MockView view = new MockView(mActivity);
         // mAttachInfo is null
@@ -1928,6 +1939,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnAttachedToAndDetachedFromWindow() {
         MockView mockView = new MockView(mActivity);
         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
@@ -1946,11 +1958,12 @@
         assertTrue(mockView.hasCalledOnDetachedFromWindow());
     }
 
+    @Test
     public void testGetLocationInWindow() {
-        int[] location = new int[] { -1, -1 };
+        final int[] location = new int[]{-1, -1};
 
-        View layout = mActivity.findViewById(R.id.viewlayout_root);
-        int[] layoutLocation = new int[] { -1, -1 };
+        final View layout = mActivity.findViewById(R.id.viewlayout_root);
+        int[] layoutLocation = new int[]{-1, -1};
         layout.getLocationInWindow(layoutLocation);
 
         final View mockView = mActivity.findViewById(R.id.mock_view);
@@ -1958,55 +1971,63 @@
         assertEquals(layoutLocation[0], location[0]);
         assertEquals(layoutLocation[1], location[1]);
 
-        View scrollView = mActivity.findViewById(R.id.scroll_view);
+        final View scrollView = mActivity.findViewById(R.id.scroll_view);
         scrollView.getLocationInWindow(location);
         assertEquals(layoutLocation[0], location[0]);
         assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]);
-
-        try {
-            mockView.getLocationInWindow(null);
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            mockView.getLocationInWindow(new int[] { 0 });
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetLocationInWindowNullArray() {
+        final View layout = mActivity.findViewById(R.id.viewlayout_root);
+        final View mockView = mActivity.findViewById(R.id.mock_view);
+
+        mockView.getLocationInWindow(null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetLocationInWindowSmallArray() {
+        final View layout = mActivity.findViewById(R.id.viewlayout_root);
+        final View mockView = mActivity.findViewById(R.id.mock_view);
+
+        mockView.getLocationInWindow(new int[] { 0 });
+    }
+
+    @Test
     public void testGetLocationOnScreen() {
-        int[] location = new int[] { -1, -1 };
+        final int[] location = new int[]{-1, -1};
 
         // mAttachInfo is not null
-        View layout = mActivity.findViewById(R.id.viewlayout_root);
-        int[] layoutLocation = new int[] { -1, -1 };
+        final View layout = mActivity.findViewById(R.id.viewlayout_root);
+        final int[] layoutLocation = new int[]{-1, -1};
         layout.getLocationOnScreen(layoutLocation);
 
-        View mockView = mActivity.findViewById(R.id.mock_view);
+        final View mockView = mActivity.findViewById(R.id.mock_view);
         mockView.getLocationOnScreen(location);
         assertEquals(layoutLocation[0], location[0]);
         assertEquals(layoutLocation[1], location[1]);
 
-        View scrollView = mActivity.findViewById(R.id.scroll_view);
+        final View scrollView = mActivity.findViewById(R.id.scroll_view);
         scrollView.getLocationOnScreen(location);
         assertEquals(layoutLocation[0], location[0]);
         assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]);
-
-        try {
-            scrollView.getLocationOnScreen(null);
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            scrollView.getLocationOnScreen(new int[] { 0 });
-            fail("should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetLocationOnScreenNullArray() {
+        final View scrollView = mActivity.findViewById(R.id.scroll_view);
+
+        scrollView.getLocationOnScreen(null);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testGetLocationOnScreenSmallArray() {
+        final View scrollView = mActivity.findViewById(R.id.scroll_view);
+
+        scrollView.getLocationOnScreen(new int[] { 0 });
+    }
+
+    @Test
     public void testAddTouchables() {
         View view = new View(mActivity);
         ArrayList<View> result = new ArrayList<>();
@@ -2033,6 +2054,7 @@
         assertEquals(0, result.size());
     }
 
+    @Test
     public void testGetTouchables() {
         View view = new View(mActivity);
         ArrayList<View> result;
@@ -2052,6 +2074,7 @@
         assertEquals(0, result.size());
     }
 
+    @Test
     public void testInflate() {
         View view = View.inflate(mActivity, R.layout.view_layout, null);
         assertNotNull(view);
@@ -2062,6 +2085,7 @@
         assertTrue(mockView.hasCalledOnFinishInflate());
     }
 
+    @Test
     public void testIsInTouchMode() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -2072,11 +2096,13 @@
         assertFalse(view.isInTouchMode());
     }
 
+    @Test
     public void testIsInEditMode() {
         View view = new View(mActivity);
         assertFalse(view.isInEditMode());
     }
 
+    @Test
     public void testPostInvalidate1() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -2087,6 +2113,7 @@
         view.postInvalidate();
     }
 
+    @Test
     public void testPostInvalidate2() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -2098,6 +2125,7 @@
         view.postInvalidate(0, -20, -30, -40);
     }
 
+    @Test
     public void testPostInvalidateDelayed() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -2111,9 +2139,10 @@
         view.postInvalidateDelayed(-1);
     }
 
+    @Test
     public void testPost() {
         View view = new View(mActivity);
-        MockRunnable action = new MockRunnable();
+        Runnable action = mock(Runnable.class);
 
         // mAttachInfo is null
         assertTrue(view.post(action));
@@ -2125,9 +2154,10 @@
         assertTrue(view.post(null));
     }
 
+    @Test
     public void testPostDelayed() {
         View view = new View(mActivity);
-        MockRunnable action = new MockRunnable();
+        Runnable action = mock(Runnable.class);
 
         // mAttachInfo is null
         assertTrue(view.postDelayed(action, 1000));
@@ -2140,6 +2170,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testPlaySoundEffect() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         // sound effect enabled
@@ -2152,33 +2183,27 @@
         // no way to assert the soundConstant be really played.
     }
 
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.isFocused());
 
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertTrue(view.hasCalledOnKeyShortcut());
     }
 
+    @Test
     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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> view.setFocusable(true));
 
         assertFalse(view.hasCalledOnKeyMultiple());
         view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER));
@@ -2186,6 +2211,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchKeyShortcutEvent() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         view.setFocusable(true);
@@ -2193,36 +2219,38 @@
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
         view.dispatchKeyShortcutEvent(event);
         assertTrue(view.hasCalledOnKeyShortcut());
-
-        try {
-            view.dispatchKeyShortcutEvent(null);
-            fail("should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testDispatchKeyShortcutEventNull() {
+        MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
+        view.setFocusable(true);
+
+        view.dispatchKeyShortcutEvent(null);
+    }
+
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setFocusable(true);
+            view.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = downTime;
         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
                 1, 2, 0);
-        getInstrumentation().sendTrackballEventSync(event);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.sendTrackballEventSync(event);
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.hasCalledOnTrackballEvent());
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchTrackballMoveEvent() {
         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         MockView mockView1 = new MockView(mActivity);
@@ -2253,69 +2281,49 @@
         assertTrue(mockView2.hasCalledOnTrackballEvent());
     }
 
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
 
         assertTrue(view.hasCalledDispatchUnhandledMove());
     }
 
+    @Test
     public void testWindowVisibilityChanged() throws Throwable {
         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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setVisible(false);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mActivity.setVisible(false));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setVisible(true);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mActivity.setVisible(true));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged());
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
 
         mockView.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                viewGroup.removeView(mockView);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> viewGroup.removeView(mockView));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.hasCalledOnWindowVisibilityChanged());
     }
 
+    @Test
     public void testGetLocalVisibleRect() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
         Rect rect = new Rect();
@@ -2327,39 +2335,26 @@
         assertEquals(200, rect.bottom);
 
         final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams1);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1));
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.getLocalVisibleRect(rect));
 
         final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams2);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2));
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.getLocalVisibleRect(rect));
 
-        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        Display display = mActivity.getWindowManager().getDefaultDisplay();
         int halfWidth = display.getWidth() / 2;
         int halfHeight = display.getHeight() /2;
 
         final LinearLayout.LayoutParams layoutParams3 =
                 new LinearLayout.LayoutParams(halfWidth, halfHeight);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setLayoutParams(layoutParams3);
-                view.scrollTo(20, -30);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setLayoutParams(layoutParams3);
+            view.scrollTo(20, -30);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.getLocalVisibleRect(rect));
         assertEquals(20, rect.left);
         assertEquals(-30, rect.top);
@@ -2373,6 +2368,7 @@
         }
     }
 
+    @Test
     public void testMergeDrawableStates() {
         MockView view = new MockView(mActivity);
 
@@ -2405,10 +2401,7 @@
         }
     }
 
-    public void testOnSaveAndRestoreInstanceState() {
-        // it is hard to simulate operation to make callback be called.
-    }
-
+    @Test
     public void testSaveAndRestoreHierarchyState() {
         int viewId = R.id.mock_view;
         MockView view = (MockView) mActivity.findViewById(viewId);
@@ -2453,24 +2446,22 @@
         }
     }
 
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.isFocused());
 
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertTrue(view.hasCalledOnKeyDown());
 
         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertTrue(view.hasCalledOnKeyUp());
 
         view.reset();
@@ -2478,52 +2469,50 @@
         assertFalse(view.isClickable());
         assertFalse(view.isPressed());
         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertFalse(view.isPressed());
         assertTrue(view.hasCalledOnKeyDown());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setEnabled(true);
-                view.setClickable(true);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setClickable(true);
         });
         view.reset();
-        OnClickListenerImpl listener = new OnClickListenerImpl();
+        View.OnClickListener listener = mock(View.OnClickListener.class);
         view.setOnClickListener(listener);
 
         assertFalse(view.isPressed());
         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertTrue(view.isPressed());
         assertTrue(view.hasCalledOnKeyDown());
         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertFalse(view.isPressed());
         assertTrue(view.hasCalledOnKeyUp());
-        assertTrue(listener.hasOnClick());
+        verify(listener, times(1)).onClick(view);
 
         view.setPressed(false);
-        listener.reset();
+        reset(listener);
         view.reset();
 
         assertFalse(view.isPressed());
         event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertTrue(view.isPressed());
         assertTrue(view.hasCalledOnKeyDown());
         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().sendKeySync(event);
+        mInstrumentation.sendKeySync(event);
         assertFalse(view.isPressed());
         assertTrue(view.hasCalledOnKeyUp());
-        assertTrue(listener.hasOnClick());
+        verify(listener, times(1)).onClick(view);
     }
 
     private void checkBounds(final ViewGroup viewGroup, final View view,
             final CountDownLatch countDownLatch, final int left, final int top,
             final int width, final int height) {
-        viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+        viewGroup.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
                 assertEquals(left, view.getLeft());
@@ -2537,6 +2526,7 @@
         });
     }
 
+    @Test
     public void testAddRemoveAffectsWrapContentLayout() throws Throwable {
         final int childWidth = 100;
         final int childHeight = 200;
@@ -2557,38 +2547,30 @@
         // 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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            parent.removeView(child);
+            checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
         });
         countDownLatch3.await(500, TimeUnit.MILLISECONDS);
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchKeyEvent() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         MockView mockView1 = new MockView(mActivity);
@@ -2642,15 +2624,21 @@
 
         view.reset();
         event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0);
-        OnKeyListenerImpl listener = new OnKeyListenerImpl();
+        View.OnKeyListener listener = mock(View.OnKeyListener.class);
+        doReturn(true).when(listener).onKey(any(), anyInt(), any());
         view.setOnKeyListener(listener);
-        assertFalse(listener.hasOnKey());
+        verifyZeroInteractions(listener);
         assertTrue(view.dispatchKeyEvent(event));
-        assertTrue(listener.hasOnKey());
+        ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class);
+        verify(listener, times(1)).onKey(eq(view), eq(KeyEvent.KEYCODE_0),
+                keyEventCaptor.capture());
+        assertEquals(KeyEvent.ACTION_UP, keyEventCaptor.getValue().getAction());
+        assertEquals(KeyEvent.KEYCODE_0, keyEventCaptor.getValue().getKeyCode());
         assertFalse(view.hasCalledOnKeyUp());
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchTouchEvent() {
         ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
         MockView mockView1 = new MockView(mActivity);
@@ -2682,45 +2670,35 @@
         assertTrue(mockView2.hasCalledOnTouchEvent());
 
         mockView1.reset();
-        OnTouchListenerImpl listener = new OnTouchListenerImpl();
+        View.OnTouchListener listener = mock(View.OnTouchListener.class);
+        doReturn(true).when(listener).onTouch(any(), any());
         mockView1.setOnTouchListener(listener);
-        assertFalse(listener.hasOnTouch());
+        verifyZeroInteractions(listener);
         assertTrue(mockView1.dispatchTouchEvent(event));
-        assertTrue(listener.hasOnTouch());
+        verify(listener, times(1)).onTouch(mockView1, event);
         assertFalse(mockView1.hasCalledOnTouchEvent());
     }
 
+    @Test
     public void testInvalidate1() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         assertTrue(view.hasCalledOnDraw());
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidate();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnDraw();
-            }
-        }.run();
+        mActivityRule.runOnUiThread(view::invalidate);
+        mInstrumentation.waitForIdleSync();
+        PollingCheck.waitFor(view::hasCalledOnDraw);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
     }
 
+    @Test
     public void testInvalidate2() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         assertTrue(view.hasCalledOnDraw());
@@ -2734,32 +2712,20 @@
         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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnDraw();
-            }
-        }.run();
+        mActivityRule.runOnUiThread(() -> view.invalidate(dirty));
+        mInstrumentation.waitForIdleSync();
+        PollingCheck.waitFor(view::hasCalledOnDraw);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate(dirty);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate(dirty);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
     }
 
+    @Test
     public void testInvalidate3() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         assertTrue(view.hasCalledOnDraw());
@@ -2767,61 +2733,37 @@
         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);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnDraw();
-            }
-        }.run();
+        mActivityRule.runOnUiThread(
+                () -> view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom));
+        mInstrumentation.waitForIdleSync();
+        PollingCheck.waitFor(view::hasCalledOnDraw);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(View.INVISIBLE);
-                view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setVisibility(View.INVISIBLE);
+            view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
     }
 
+    @Test
     public void testInvalidateDrawable() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         final Drawable d1 = mResources.getDrawable(R.drawable.scenery);
         final Drawable d2 = mResources.getDrawable(R.drawable.pass);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setBackgroundDrawable(d1);
-                view.invalidateDrawable(d1);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setBackgroundDrawable(d1);
+            view.invalidateDrawable(d1);
         });
-        getInstrumentation().waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnDraw();
-            }
-        }.run();
+        mInstrumentation.waitForIdleSync();
+        PollingCheck.waitFor(view::hasCalledOnDraw);
 
         view.reset();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.invalidateDrawable(d2);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> view.invalidateDrawable(d2));
+        mInstrumentation.waitForIdleSync();
         assertFalse(view.hasCalledOnDraw());
 
         MockView viewTestNull = new MockView(mActivity);
@@ -2833,6 +2775,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnFocusChanged() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -2848,6 +2791,7 @@
         assertTrue(view.hasCalledOnFocusChanged());
     }
 
+    @Test
     public void testDrawableState() {
         MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
@@ -2879,23 +2823,14 @@
         assertTrue(view.hasCalledOnCreateDrawableState());
     }
 
+    @Test
     public void testWindowFocusChanged() {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
         // Wait until the window has been focused.
-        new PollingCheck(TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return view.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT_DELTA, view::hasWindowFocus);
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return view.hasCalledOnWindowFocusChanged();
-            }
-        }.run();
+        PollingCheck.waitFor(view::hasCalledOnWindowFocusChanged);
 
         assertTrue(view.hasCalledOnWindowFocusChanged());
         assertTrue(view.hasCalledDispatchWindowFocusChanged());
@@ -2904,15 +2839,10 @@
         assertFalse(view.hasCalledOnWindowFocusChanged());
         assertFalse(view.hasCalledDispatchWindowFocusChanged());
 
-        CtsActivity activity = launchActivity("android.view.cts", CtsActivity.class, null);
+        CtsActivity activity = mCtsActivityRule.launchActivity(null);
 
         // Wait until the window lost focus.
-        new PollingCheck(TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return !view.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT_DELTA, () -> !view.hasWindowFocus());
 
         assertTrue(view.hasCalledOnWindowFocusChanged());
         assertTrue(view.hasCalledDispatchWindowFocusChanged());
@@ -2920,20 +2850,17 @@
         activity.finish();
     }
 
+    @Test
     public void testDraw() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::requestLayout);
+        mInstrumentation.waitForIdleSync();
 
         assertTrue(view.hasCalledOnDraw());
         assertTrue(view.hasCalledDispatchDraw());
     }
 
+    @Test
     public void testRequestFocusFromTouch() {
         View view = new View(mActivity);
         view.setFocusable(true);
@@ -2946,6 +2873,7 @@
         assertTrue(view.isFocused());
     }
 
+    @Test
     public void testRequestRectangleOnScreen1() {
         MockView view = new MockView(mActivity);
         Rect rectangle = new Rect(10, 10, 20, 30);
@@ -2977,6 +2905,7 @@
         }
     }
 
+    @Test
     public void testRequestRectangleOnScreen2() {
         MockView view = new MockView(mActivity);
         Rect rectangle = new Rect();
@@ -3018,14 +2947,17 @@
         }
     }
 
+    @Test
     public void testRequestRectangleOnScreen3() {
         requestRectangleOnScreenTest(false);
     }
 
+    @Test
     public void testRequestRectangleOnScreen4() {
         requestRectangleOnScreenTest(true);
     }
 
+    @Test
     public void testRequestRectangleOnScreen5() {
         MockView child = new MockView(mActivity);
 
@@ -3068,6 +3000,7 @@
         assertEquals(new Rect(9, 8, 11, 11), grandParent.getLastRequestedChildRectOnScreen());
     }
 
+    @Test
     public void testRequestRectangleOnScreenWithScale() {
         // scale should not affect the rectangle
         MockView child = new MockView(mActivity);
@@ -3094,9 +3027,10 @@
         } catch (InterruptedException e) {
             Log.e(LOG_TAG, "waitPrepressedTimeout() interrupted! Test may fail!", e);
         }
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testOnTouchEvent() throws Throwable {
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
@@ -3104,18 +3038,15 @@
         assertFalse(view.isClickable());
         assertFalse(view.isLongClickable());
 
-        TouchUtils.clickView(this, view);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, view);
         assertTrue(view.hasCalledOnTouchEvent());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setEnabled(true);
-                view.setClickable(true);
-                view.setLongClickable(true);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setEnabled(true);
+            view.setClickable(true);
+            view.setLongClickable(true);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.isEnabled());
         assertTrue(view.isClickable());
         assertTrue(view.isLongClickable());
@@ -3134,7 +3065,7 @@
         MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN,
                 x, y, 0);
         assertFalse(view.isPressed());
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         waitPrepressedTimeout();
         assertTrue(view.hasCalledOnTouchEvent());
         assertTrue(view.isPressed());
@@ -3148,7 +3079,7 @@
         x = xy[0] + viewWidth + slop;
         y = xy[1] + viewHeight + slop;
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         assertTrue(view.hasCalledOnTouchEvent());
         assertFalse(view.isPressed());
 
@@ -3159,21 +3090,21 @@
         x = xy[0] + viewWidth - 1;
         y = xy[1] + viewHeight - 1;
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         waitPrepressedTimeout();
         assertTrue(view.hasCalledOnTouchEvent());
         assertFalse(view.isPressed());
 
         // MotionEvent.ACTION_UP
-        OnClickListenerImpl listener = new OnClickListenerImpl();
+        View.OnClickListener listener = mock(View.OnClickListener.class);
         view.setOnClickListener(listener);
         view.reset();
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         assertTrue(view.hasCalledOnTouchEvent());
-        assertFalse(listener.hasOnClick());
+        verifyZeroInteractions(listener);
 
         view.reset();
         x = xy[0] + viewWidth / 2.0f;
@@ -3181,21 +3112,22 @@
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         assertTrue(view.hasCalledOnTouchEvent());
 
         // MotionEvent.ACTION_CANCEL
         view.reset();
-        listener.reset();
+        reset(listener);
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         assertTrue(view.hasCalledOnTouchEvent());
         assertFalse(view.isPressed());
-        assertFalse(listener.hasOnClick());
+        verifyZeroInteractions(listener);
     }
 
+    @Test
     public void testBringToFront() {
         MockView view = new MockView(mActivity);
         view.setParent(mMockParent);
@@ -3205,6 +3137,7 @@
         assertTrue(mMockParent.hasBroughtChildToFront());
     }
 
+    @Test
     public void testGetApplicationWindowToken() {
         View view = new View(mActivity);
         // mAttachInfo is null
@@ -3215,32 +3148,38 @@
         assertNotNull(view.getApplicationWindowToken());
     }
 
+    @Test
     public void testGetBottomPaddingOffset() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getBottomPaddingOffset());
     }
 
+    @Test
     public void testGetLeftPaddingOffset() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getLeftPaddingOffset());
     }
 
+    @Test
     public void testGetRightPaddingOffset() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getRightPaddingOffset());
     }
 
+    @Test
     public void testGetTopPaddingOffset() {
         MockView view = new MockView(mActivity);
         assertEquals(0, view.getTopPaddingOffset());
     }
 
+    @Test
     public void testIsPaddingOffsetRequired() {
         MockView view = new MockView(mActivity);
         assertFalse(view.isPaddingOffsetRequired());
     }
 
     @UiThreadTest
+    @Test
     public void testPadding() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view_padding_full);
         Drawable background = view.getBackground();
@@ -3370,6 +3309,7 @@
         assertEquals(0, view.getPaddingBottom());
     }
 
+    @Test
     public void testGetWindowVisibleDisplayFrame() {
         Rect outRect = new Rect();
         View view = new View(mActivity);
@@ -3389,55 +3329,47 @@
         view.getWindowVisibleDisplayFrame(outRect);
     }
 
+    @Test
     public void testSetScrollContainer() throws Throwable {
         final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view);
         final MockView scrollView = (MockView) mActivity.findViewById(R.id.scroll_view);
         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
         final BitmapDrawable d = new BitmapDrawable(bitmap);
-        final InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(
+        final InputMethodManager imm = (InputMethodManager) mActivity.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);
+        mActivityRule.runOnUiThread(() -> {
+            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();
+        mInstrumentation.waitForIdleSync();
 
         // FIXME: why the size of view doesn't change?
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0));
+        mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mockView.setFocusableInTouchMode(true);
+            fitWindowsView.setFocusable(true);
+            fitWindowsView.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.isFocusableInTouchMode());
         assertFalse(fitWindowsView.isFocusableInTouchMode());
         assertTrue(mockView.isFocusable());
@@ -3447,39 +3379,24 @@
         assertFalse(mockView.isInTouchMode());
         assertFalse(fitWindowsView.isInTouchMode());
 
-        TouchUtils.tapView(this, mockView);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mockView);
         assertFalse(fitWindowsView.isFocused());
         assertFalse(mockView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mockView.requestFocus();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(mockView::requestFocus);
+        mInstrumentation.waitForIdleSync();
         assertTrue(mockView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fitWindowsView.requestFocus();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(fitWindowsView::requestFocus);
+        mInstrumentation.waitForIdleSync();
         assertFalse(fitWindowsView.isFocused());
         assertTrue(mockView.isInTouchMode());
         assertTrue(fitWindowsView.isInTouchMode());
 
         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
-        getInstrumentation().sendKeySync(keyEvent);
+        mInstrumentation.sendKeySync(keyEvent);
         assertTrue(mockView.isFocused());
         assertFalse(fitWindowsView.isFocused());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fitWindowsView.requestFocus();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(fitWindowsView::requestFocus);
+        mInstrumentation.waitForIdleSync();
         assertFalse(mockView.isFocused());
         assertTrue(fitWindowsView.isFocused());
         assertFalse(mockView.isInTouchMode());
@@ -3487,6 +3404,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testScrollbarStyle() {
         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
@@ -3523,6 +3441,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testScrollFading() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
@@ -3548,6 +3467,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testScrolling() {
         MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         view.reset();
@@ -3585,6 +3505,7 @@
         assertTrue(view.hasCalledOnScrollChanged());
     }
 
+    @Test
     public void testInitializeScrollbarsAndFadingEdge() {
         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
 
@@ -3605,6 +3526,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testScrollIndicators() {
         MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
 
@@ -3622,6 +3544,7 @@
 
     }
 
+    @Test
     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
         final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false);
         final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false);
@@ -3718,48 +3641,37 @@
 
         assertFalse(view.isTemporarilyDetached());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.dispatchStartTemporaryDetach();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::dispatchStartTemporaryDetach);
+        mInstrumentation.waitForIdleSync();
 
         assertTrue(view.isTemporarilyDetached());
         assertTrue(exitedDispatchStartTemporaryDetach.get());
         assertFalse(exitedDispatchFinishTemporaryDetach.get());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.dispatchFinishTemporaryDetach();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::dispatchFinishTemporaryDetach);
+        mInstrumentation.waitForIdleSync();
 
         assertFalse(view.isTemporarilyDetached());
         assertTrue(exitedDispatchStartTemporaryDetach.get());
         assertTrue(exitedDispatchFinishTemporaryDetach.get());
     }
 
+    @Test
     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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.setFocusable(true);
+            view.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
-        getInstrumentation().sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
+        mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
         assertTrue(view.hasCalledDispatchKeyEventPreIme());
         assertTrue(view.hasCalledOnKeyPreIme());
     }
 
+    @Test
     public void testHapticFeedback() {
         Vibrator vib = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE);
         boolean hasVibrator = vib.hasVibrator();
@@ -3778,56 +3690,44 @@
 
         view.setHapticFeedbackEnabled(true);
         assertTrue(view.isHapticFeedbackEnabled());
-        assertEquals(hasVibrator, view.performHapticFeedback(LONG_PRESS, FLAG_IGNORE_GLOBAL_SETTING));
+        assertEquals(hasVibrator, view.performHapticFeedback(LONG_PRESS,
+                FLAG_IGNORE_GLOBAL_SETTING));
     }
 
+    @Test
     public void testInputConnection() throws Throwable {
-        final InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(
+        final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
                 Context.INPUT_METHOD_SERVICE);
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
         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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            viewGroup.addView(editText);
+            editText.requestFocus();
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
         assertTrue(editText.isFocused());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                imm.showSoftInput(editText, 0);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> imm.showSoftInput(editText, 0));
+        mInstrumentation.waitForIdleSync();
 
-        new PollingCheck(TIMEOUT_DELTA) {
-            @Override
-            protected boolean check() {
-                return editText.hasCalledOnCreateInputConnection();
-            }
-        }.run();
+        PollingCheck.waitFor(TIMEOUT_DELTA, editText::hasCalledOnCreateInputConnection);
 
         assertTrue(editText.hasCalledOnCheckIsTextEditor());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue(imm.isActive(editText));
-                assertFalse(editText.hasCalledCheckInputConnectionProxy());
-                imm.isActive(view);
-                assertTrue(editText.hasCalledCheckInputConnectionProxy());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(imm.isActive(editText));
+            assertFalse(editText.hasCalledCheckInputConnectionProxy());
+            imm.isActive(view);
+            assertTrue(editText.hasCalledCheckInputConnectionProxy());
         });
     }
 
+    @Test
     public void testFilterTouchesWhenObscured() throws Throwable {
-        OnTouchListenerImpl touchListener = new OnTouchListenerImpl();
+        View.OnTouchListener touchListener = mock(View.OnTouchListener.class);
+        doReturn(true).when(touchListener).onTouch(any(), any());
         View view = new View(mActivity);
         view.setOnTouchListener(touchListener);
 
@@ -3848,35 +3748,36 @@
         assertFalse(view.getFilterTouchesWhenObscured());
 
         view.dispatchTouchEvent(unobscuredTouch);
-        assertTrue(touchListener.hasOnTouch());
-        touchListener.reset();
+        verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
+        reset(touchListener);
         view.dispatchTouchEvent(obscuredTouch);
-        assertTrue(touchListener.hasOnTouch());
-        touchListener.reset();
+        verify(touchListener, times(1)).onTouch(view, obscuredTouch);
+        reset(touchListener);
 
         // Set filter touches to true so only unobscured touches are dispatched.
         view.setFilterTouchesWhenObscured(true);
         assertTrue(view.getFilterTouchesWhenObscured());
 
         view.dispatchTouchEvent(unobscuredTouch);
-        assertTrue(touchListener.hasOnTouch());
-        touchListener.reset();
+        verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
+        reset(touchListener);
         view.dispatchTouchEvent(obscuredTouch);
-        assertFalse(touchListener.hasOnTouch());
-        touchListener.reset();
+        verifyZeroInteractions(touchListener);
+        reset(touchListener);
 
         // Set filter touches to false so all touches are dispatched.
         view.setFilterTouchesWhenObscured(false);
         assertFalse(view.getFilterTouchesWhenObscured());
 
         view.dispatchTouchEvent(unobscuredTouch);
-        assertTrue(touchListener.hasOnTouch());
-        touchListener.reset();
+        verify(touchListener, times(1)).onTouch(view, unobscuredTouch);
+        reset(touchListener);
         view.dispatchTouchEvent(obscuredTouch);
-        assertTrue(touchListener.hasOnTouch());
-        touchListener.reset();
+        verify(touchListener, times(1)).onTouch(view, obscuredTouch);
+        reset(touchListener);
     }
 
+    @Test
     public void testBackgroundTint() {
         View inflatedView = mActivity.findViewById(R.id.background_tint);
 
@@ -3902,6 +3803,7 @@
                 bg.hasCalledSetTint());
     }
 
+    @Test
     public void testStartActionModeWithParent() {
         View view = new View(mActivity);
         MockViewGroup parent = new MockViewGroup(mActivity);
@@ -3915,6 +3817,7 @@
         assertEquals(ActionMode.TYPE_PRIMARY, parent.startActionModeForChildType);
     }
 
+    @Test
     public void testStartActionModeWithoutParent() {
         View view = new View(mActivity);
 
@@ -3923,6 +3826,7 @@
         assertNull(mode);
     }
 
+    @Test
     public void testStartActionModeTypedWithParent() {
         View view = new View(mActivity);
         MockViewGroup parent = new MockViewGroup(mActivity);
@@ -3936,6 +3840,7 @@
         assertEquals(ActionMode.TYPE_FLOATING, parent.startActionModeForChildType);
     }
 
+    @Test
     public void testStartActionModeTypedWithoutParent() {
         View view = new View(mActivity);
 
@@ -3944,6 +3849,7 @@
         assertNull(mode);
     }
 
+    @Test
     public void testVisibilityAggregated() throws Throwable {
         final View grandparent = mActivity.findViewById(R.id.viewlayout_root);
         final View parent = mActivity.findViewById(R.id.aggregate_visibility_parent);
@@ -3955,69 +3861,56 @@
         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);
+        mActivityRule.runOnUiThread(reset);
 
         setVisibilityOnUiThread(parent, View.GONE);
 
         assertTrue(mv.hasCalledOnVisibilityAggregated());
         assertFalse(mv.getLastAggregatedVisibility());
 
-        runTestOnUiThread(reset);
+        mActivityRule.runOnUiThread(reset);
 
         setVisibilityOnUiThread(grandparent, View.GONE);
 
         assertTrue(mv.hasCalledOnVisibilityAggregated());
         assertFalse(mv.getLastAggregatedVisibility());
 
-        runTestOnUiThread(reset);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                grandparent.setVisibility(View.GONE);
-                parent.setVisibility(View.GONE);
-                mv.setVisibility(View.VISIBLE);
+        mActivityRule.runOnUiThread(reset);
+        mActivityRule.runOnUiThread(() -> {
+            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);
+        mActivityRule.runOnUiThread(reset);
+        mActivityRule.runOnUiThread(() -> {
+            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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> parent.setVisibility(View.VISIBLE));
 
         assertTrue(mv.getLastAggregatedVisibility());
     }
 
+    @Test
     public void testOverlappingRendering() {
         View overlappingUnsetView = mActivity.findViewById(R.id.overlapping_rendering_unset);
         View overlappingFalseView = mActivity.findViewById(R.id.overlapping_rendering_false);
@@ -4051,13 +3944,45 @@
         assertTrue(overridingView.hasOverlappingRendering());
     }
 
+    @Test
+    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));
+    }
+
+    @Test
+    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));
+    }
+
+    @Test
+    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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> view.setVisibility(visibility));
     }
 
     private static class MockOverlappingRenderingSubclass extends View {
@@ -4152,6 +4077,7 @@
                 }
             };
 
+    @Test
     public void testTranslationSetter() {
         View view = new View(mActivity);
         float offset = 10.0f;
@@ -4160,12 +4086,13 @@
         view.setTranslationZ(offset);
         view.setElevation(offset);
 
-        assertEquals("Incorrect translationX", offset, view.getTranslationX());
-        assertEquals("Incorrect translationY", offset, view.getTranslationY());
-        assertEquals("Incorrect translationZ", offset, view.getTranslationZ());
-        assertEquals("Incorrect elevation", offset, view.getElevation());
+        assertEquals("Incorrect translationX", offset, view.getTranslationX(), 0.0f);
+        assertEquals("Incorrect translationY", offset, view.getTranslationY(), 0.0f);
+        assertEquals("Incorrect translationZ", offset, view.getTranslationZ(), 0.0f);
+        assertEquals("Incorrect elevation", offset, view.getElevation(), 0.0f);
     }
 
+    @Test
     public void testXYZ() {
         View view = new View(mActivity);
         float offset = 10.0f;
@@ -4177,9 +4104,9 @@
         view.setTranslationZ(offset);
         view.setElevation(start);
 
-        assertEquals("Incorrect X value", offset + start, view.getX());
-        assertEquals("Incorrect Y value", offset + start, view.getY());
-        assertEquals("Incorrect Z value", offset + start, view.getZ());
+        assertEquals("Incorrect X value", offset + start, view.getX(), 0.0f);
+        assertEquals("Incorrect Y value", offset + start, view.getY(), 0.0f);
+        assertEquals("Incorrect Z value", offset + start, view.getZ(), 0.0f);
     }
 
     private static class MockDrawable extends Drawable {
@@ -4487,23 +4414,6 @@
         }
     }
 
-    private final class OnCreateContextMenuListenerImpl implements OnCreateContextMenuListener {
-        private boolean mHasOnCreateContextMenu = false;
-
-        @Override
-        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-            mHasOnCreateContextMenu = true;
-        }
-
-        public boolean hasOnCreateContextMenu() {
-            return mHasOnCreateContextMenu;
-        }
-
-        public void reset() {
-            mHasOnCreateContextMenu = false;
-        }
-    }
-
     private static class MockViewGroupParent extends ViewGroup implements ViewParent {
         private boolean mHasRequestChildRectangleOnScreen = false;
         private Rect mLastRequestedChildRectOnScreen = new Rect(
@@ -4544,156 +4454,12 @@
         }
     }
 
-    private static final class OnClickListenerImpl implements OnClickListener {
-        private boolean mHasOnClick = false;
-
-        @Override
-        public void onClick(View v) {
-            mHasOnClick = true;
-        }
-
-        public boolean hasOnClick() {
-            return mHasOnClick;
-        }
-
-        public void reset() {
-            mHasOnClick = false;
-        }
-    }
-
-    private static final class OnLongClickListenerImpl implements OnLongClickListener {
-        private boolean mHasOnLongClick = false;
-
-        public boolean hasOnLongClick() {
-            return mHasOnLongClick;
-        }
-
-        public void reset() {
-            mHasOnLongClick = false;
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            mHasOnLongClick = true;
-            return true;
-        }
-    }
-
-    private static final class OnContextClickListenerImpl implements OnContextClickListener {
-        private boolean mHasContextClick = false;
-        private View mLastViewContextClicked;
-
-        public boolean hasOnContextClick() {
-            return mHasContextClick;
-        }
-
-        public void reset() {
-            mHasContextClick = false;
-            mLastViewContextClicked = null;
-        }
-
-        @Override
-        public boolean onContextClick(View v) {
-            mHasContextClick = true;
-            mLastViewContextClicked = v;
-            return true;
-        }
-
-        public View getLastViewContextClicked() {
-            return mLastViewContextClicked;
-        }
-    }
-
-    private static final class OnFocusChangeListenerImpl implements OnFocusChangeListener {
-        private boolean mHasOnFocusChange = false;
-
-        @Override
-        public void onFocusChange(View v, boolean hasFocus) {
-            mHasOnFocusChange = true;
-        }
-
-        public boolean hasOnFocusChange() {
-            return mHasOnFocusChange;
-        }
-
-        public void reset() {
-            mHasOnFocusChange = false;
-        }
-    }
-
-    private static final class OnKeyListenerImpl implements OnKeyListener {
-        private boolean mHasOnKey = false;
-
-        @Override
-        public boolean onKey(View v, int keyCode, KeyEvent event) {
-            mHasOnKey = true;
-            return true;
-        }
-
-        public void reset() {
-            mHasOnKey = false;
-        }
-
-        public boolean hasOnKey() {
-            return mHasOnKey;
-        }
-    }
-
-    private static final class OnTouchListenerImpl implements OnTouchListener {
-        private boolean mHasOnTouch = false;
-
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            mHasOnTouch = true;
-            return true;
-        }
-
-        public void reset() {
-            mHasOnTouch = false;
-        }
-
-        public boolean hasOnTouch() {
-            return mHasOnTouch;
-        }
-    }
-
-    private static final class MockTouchDelegate extends TouchDelegate {
-        public MockTouchDelegate(Rect bounds, View delegateView) {
-            super(bounds, delegateView);
-        }
-
-        private boolean mCalledOnTouchEvent = false;
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            mCalledOnTouchEvent = true;
-            return super.onTouchEvent(event);
-        }
-
-        public boolean hasCalledOnTouchEvent() {
-            return mCalledOnTouchEvent;
-        }
-
-        public void reset() {
-            mCalledOnTouchEvent = false;
-        }
-    }
-
     private static final class ViewData {
         public int childCount;
         public String tag;
         public View firstChild;
     }
 
-    private static final class MockRunnable implements Runnable {
-        public boolean hasRun = false;
-
-        @Override
-        public void run() {
-            hasRun = true;
-        }
-    }
-
     private static final Class<?> ASYNC_INFLATE_VIEWS[] = {
         android.app.FragmentBreadCrumbs.class,
 // DISABLED because it doesn't have a AppWidgetHostView(Context, AttributeSet)
diff --git a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
index bbe6ccc..9766fa2 100644
--- a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
@@ -24,7 +24,7 @@
 
 public class ViewTestCtsActivity extends Activity {
     private boolean mHasWindowFocus = false;
-    private Object mHasWindowFocusLock = new Object();
+    private final Object mHasWindowFocusLock = new Object();
 
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
index b799e76..4aa7377 100644
--- a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
@@ -16,420 +16,295 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+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.Activity;
 import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+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.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-import android.view.ViewTreeObserver.OnScrollChangedListener;
-import android.view.ViewTreeObserver.OnTouchModeChangeListener;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
-public class ViewTreeObserverTest extends ActivityInstrumentationTestCase2<MockActivity> {
-    ViewTreeObserver mViewTreeObserver;
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
 
-    private Activity mActivity;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewTreeObserverTest {
+    private static int TIMEOUT_MS = 2000;
+
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private ViewTreeObserver mViewTreeObserver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mViewTreeObserver = null;
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
+    private LinearLayout mLinearLayout;
+    private Button mButton;
+
+    @Rule
+    public ActivityTestRule<MockActivity> mActivityRule =
+            new ActivityTestRule<>(MockActivity.class);
+
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         layout(R.layout.viewtreeobserver_layout);
+
+        mLinearLayout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
+        mButton = (Button) mActivity.findViewById(R.id.button1);
     }
 
-    public ViewTreeObserverTest() {
-        super(MockActivity.class);
-    }
-
-    private void layout(final int layoutId) {
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(layoutId);
-            }
-        });
+    private void layout(final int layoutId) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layoutId));
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testAddOnGlobalFocusChangeListener() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
+    @Test
+    public void testAddOnGlobalFocusChangeListener() throws Throwable {
         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();
-            }
-        });
+        mActivityRule.runOnUiThread(view1::requestFocus);
 
-        mViewTreeObserver = layout.getViewTreeObserver();
-        final MockOnGlobalFocusChangeListener listener = new MockOnGlobalFocusChangeListener();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
+        final ViewTreeObserver.OnGlobalFocusChangeListener listener =
+                mock(ViewTreeObserver.OnGlobalFocusChangeListener.class);
         mViewTreeObserver.addOnGlobalFocusChangeListener(listener);
-        assertFalse(listener.hasCalledOnGlobalFocusChanged());
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view2.requestFocus();
-            }
-        });
+        mActivityRule.runOnUiThread(view2::requestFocus);
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return listener.hasCalledOnGlobalFocusChanged()
-                        && listener.oldFocus == view1 && listener.newFocus == view2;
-            }
-        }.run();
+        verify(listener, within(TIMEOUT_MS)).onGlobalFocusChanged(view1, view2);
     }
 
+    @Test
     public void testAddOnGlobalLayoutListener() {
-        final LinearLayout layout =
-            (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
 
-        MockOnGlobalLayoutListener listener = new MockOnGlobalLayoutListener();
-        assertFalse(listener.hasCalledOnGlobalLayout());
+        final ViewTreeObserver.OnGlobalLayoutListener listener =
+                mock(ViewTreeObserver.OnGlobalLayoutListener.class);
         mViewTreeObserver.addOnGlobalLayoutListener(listener);
         mViewTreeObserver.dispatchOnGlobalLayout();
-        assertTrue(listener.hasCalledOnGlobalLayout());
+        verify(listener, times(1)).onGlobalLayout();
     }
 
+    @Test
     public void testAddOnPreDrawListener() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
 
-        MockOnPreDrawListener listener = new MockOnPreDrawListener();
-        assertFalse(listener.hasCalledOnPreDraw());
+        final ViewTreeObserver.OnPreDrawListener listener =
+                mock(ViewTreeObserver.OnPreDrawListener.class);
         mViewTreeObserver.addOnPreDrawListener(listener);
         mViewTreeObserver.dispatchOnPreDraw();
-        assertTrue(listener.hasCalledOnPreDraw());
+        verify(listener, times(1)).onPreDraw();
     }
 
-    public void testAddOnTouchModeChangeListener() {
-        final Button b = (Button) mActivity.findViewById(R.id.button1);
+    @Test
+    public void testAddOnDrawListener() {
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
 
+        final ViewTreeObserver.OnDrawListener listener =
+                mock(ViewTreeObserver.OnDrawListener.class);
+        mViewTreeObserver.addOnDrawListener(listener);
+        mViewTreeObserver.dispatchOnDraw();
+        verify(listener, times(1)).onDraw();
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testRemoveOnDrawListenerInDispatch() {
+        final View view = new View(mActivity);
+        mViewTreeObserver = view.getViewTreeObserver();
+
+        final ViewTreeObserver.OnDrawListener listener =
+                new ViewTreeObserver.OnDrawListener() {
+                    @Override
+                    public void onDraw() {
+                        mViewTreeObserver.removeOnDrawListener(this);
+                    }
+                };
+        mViewTreeObserver.addOnDrawListener(listener);
+        mViewTreeObserver.dispatchOnDraw();
+    }
+
+    @Test
+    public void testAddOnTouchModeChangeListener() throws Throwable {
         // let the button be touch mode.
-        TouchUtils.tapView(this, b);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButton);
 
-        mViewTreeObserver = b.getViewTreeObserver();
+        mViewTreeObserver = mButton.getViewTreeObserver();
 
-        final MockOnTouchModeChangeListener listener = new MockOnTouchModeChangeListener();
-        assertFalse(listener.hasCalledOnTouchModeChanged());
+        final ViewTreeObserver.OnTouchModeChangeListener listener =
+                mock(ViewTreeObserver.OnTouchModeChangeListener.class);
         mViewTreeObserver.addOnTouchModeChangeListener(listener);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        mActivityRule.runOnUiThread(mButton::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return listener.hasCalledOnTouchModeChanged();
-            }
-        }.run();
+        verify(listener, within(TIMEOUT_MS)).onTouchModeChanged(anyBoolean());
     }
 
-    public void testDispatchOnGlobalLayout() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
-
-        MockOnGlobalLayoutListener listener = new MockOnGlobalLayoutListener();
-        assertFalse(listener.hasCalledOnGlobalLayout());
-        mViewTreeObserver.addOnGlobalLayoutListener(listener);
-        mViewTreeObserver.dispatchOnGlobalLayout();
-        assertTrue(listener.hasCalledOnGlobalLayout());
-    }
-
-    public void testDispatchOnPreDraw() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
-
-        MockOnPreDrawListener listener = new MockOnPreDrawListener();
-        assertFalse(listener.hasCalledOnPreDraw());
-        mViewTreeObserver.addOnPreDrawListener(listener);
-        mViewTreeObserver.dispatchOnPreDraw();
-        assertTrue(listener.hasCalledOnPreDraw());
-    }
-
+    @Test
     public void testIsAlive() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-
-        mViewTreeObserver = layout.getViewTreeObserver();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
         assertTrue(mViewTreeObserver.isAlive());
     }
 
+    @LargeTest
+    @Test
     public void testRemoveGlobalOnLayoutListener() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
 
-        MockOnGlobalLayoutListener listener = new MockOnGlobalLayoutListener();
-        assertFalse(listener.hasCalledOnGlobalLayout());
+        final ViewTreeObserver.OnGlobalLayoutListener listener =
+                mock(ViewTreeObserver.OnGlobalLayoutListener.class);
         mViewTreeObserver.addOnGlobalLayoutListener(listener);
         mViewTreeObserver.dispatchOnGlobalLayout();
-        assertTrue(listener.hasCalledOnGlobalLayout());
+        verify(listener, times(1)).onGlobalLayout();
 
-        listener.reset();
-        assertFalse(listener.hasCalledOnGlobalLayout());
+        reset(listener);
         mViewTreeObserver.removeGlobalOnLayoutListener(listener);
         mViewTreeObserver.dispatchOnGlobalLayout();
-        assertFalse(listener.hasCalledOnGlobalLayout());
+        // Since we've unregistered our listener, we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
     }
 
-    public void testRemoveOnGlobalFocusChangeListener() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
+    @LargeTest
+    @Test
+    public void testRemoveOnGlobalLayoutListener() {
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
+
+        final ViewTreeObserver.OnGlobalLayoutListener listener =
+                mock(ViewTreeObserver.OnGlobalLayoutListener.class);
+        mViewTreeObserver.addOnGlobalLayoutListener(listener);
+        mViewTreeObserver.dispatchOnGlobalLayout();
+        verify(listener, times(1)).onGlobalLayout();
+
+        reset(listener);
+        mViewTreeObserver.removeOnGlobalLayoutListener(listener);
+        mViewTreeObserver.dispatchOnGlobalLayout();
+        // Since we've unregistered our listener, we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
+    }
+
+    @LargeTest
+    @Test
+    public void testRemoveOnGlobalFocusChangeListener() throws Throwable {
         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();
-            }
-        });
+        mActivityRule.runOnUiThread(view1::requestFocus);
 
-        mViewTreeObserver = layout.getViewTreeObserver();
-        final MockOnGlobalFocusChangeListener listener = new MockOnGlobalFocusChangeListener();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
+        final ViewTreeObserver.OnGlobalFocusChangeListener listener =
+                mock(ViewTreeObserver.OnGlobalFocusChangeListener.class);
         mViewTreeObserver.addOnGlobalFocusChangeListener(listener);
-        assertFalse(listener.hasCalledOnGlobalFocusChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view2.requestFocus();
-            }
-        });
+        mActivityRule.runOnUiThread(view2::requestFocus);
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return listener.hasCalledOnGlobalFocusChanged()
-                        && listener.oldFocus == view1 && listener.newFocus == view2;
-            }
-        }.run();
+        verify(listener, within(TIMEOUT_MS)).onGlobalFocusChanged(view1, view2);
 
-        listener.reset();
+        reset(listener);
         mViewTreeObserver.removeOnGlobalFocusChangeListener(listener);
-        assertFalse(listener.hasCalledOnGlobalFocusChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                view1.requestFocus();
-            }
-        });
+        mActivityRule.runOnUiThread(view1::requestFocus);
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !listener.hasCalledOnGlobalFocusChanged();
-            }
-        }.run();
+        // Since we've unregistered our listener, we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
     }
 
+    @LargeTest
+    @Test
     public void testRemoveOnPreDrawListener() {
-        final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
-        mViewTreeObserver = layout.getViewTreeObserver();
+        mViewTreeObserver = mLinearLayout.getViewTreeObserver();
 
-        MockOnPreDrawListener listener = new MockOnPreDrawListener();
-        assertFalse(listener.hasCalledOnPreDraw());
+        final ViewTreeObserver.OnPreDrawListener listener =
+                mock(ViewTreeObserver.OnPreDrawListener.class);
         mViewTreeObserver.addOnPreDrawListener(listener);
         mViewTreeObserver.dispatchOnPreDraw();
-        assertTrue(listener.hasCalledOnPreDraw());
+        verify(listener, times(1)).onPreDraw();
 
-        listener.reset();
-        assertFalse(listener.hasCalledOnPreDraw());
+        reset(listener);
         mViewTreeObserver.removeOnPreDrawListener(listener);
         mViewTreeObserver.dispatchOnPreDraw();
-        assertFalse(listener.hasCalledOnPreDraw());
+        // Since we've unregistered our listener, we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
     }
 
-    public void testRemoveOnTouchModeChangeListener() {
-        final Button b = (Button) mActivity.findViewById(R.id.button1);
+    @LargeTest
+    @Test
+    public void testRemoveOnTouchModeChangeListener() throws Throwable {
         // let the button be touch mode.
-        TouchUtils.tapView(this, b);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButton);
 
-        mViewTreeObserver = b.getViewTreeObserver();
+        mViewTreeObserver = mButton.getViewTreeObserver();
 
-        MockOnTouchModeChangeListener listener = new MockOnTouchModeChangeListener();
+        final ViewTreeObserver.OnTouchModeChangeListener listener =
+                mock(ViewTreeObserver.OnTouchModeChangeListener.class);
         mViewTreeObserver.addOnTouchModeChangeListener(listener);
-        assertFalse(listener.hasCalledOnTouchModeChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        mActivityRule.runOnUiThread(mButton::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
-        final MockOnTouchModeChangeListener l = listener;
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return l.hasCalledOnTouchModeChanged();
-            }
-        }.run();
 
-        listener = new MockOnTouchModeChangeListener();
-        assertFalse(listener.hasCalledOnTouchModeChanged());
-        mInstrumentation.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                b.requestFocusFromTouch();
-            }
-        });
+        verify(listener, within(TIMEOUT_MS)).onTouchModeChanged(anyBoolean());
+
+        reset(listener);
+        mViewTreeObserver.removeOnTouchModeChangeListener(listener);
+        mActivityRule.runOnUiThread(mButton::requestFocusFromTouch);
         mInstrumentation.waitForIdleSync();
-        final MockOnTouchModeChangeListener l2 = listener;
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !l2.hasCalledOnTouchModeChanged();
-            }
-        }.run();
+
+        // Since we've unregistered our listener we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
     }
 
+    @LargeTest
+    @Test
     public void testAccessOnScrollChangedListener() throws Throwable {
         layout(R.layout.scrollview_layout);
         final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
 
         mViewTreeObserver = scrollView.getViewTreeObserver();
 
-        final MockOnScrollChangedListener listener = new MockOnScrollChangedListener();
-        assertFalse(listener.hasCalledOnScrollChanged());
+        final ViewTreeObserver.OnScrollChangedListener listener =
+                mock(ViewTreeObserver.OnScrollChangedListener.class);
         mViewTreeObserver.addOnScrollChangedListener(listener);
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fullScroll(View.FOCUS_DOWN);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> scrollView.fullScroll(View.FOCUS_DOWN));
         mInstrumentation.waitForIdleSync();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return listener.hasCalledOnScrollChanged();
-            }
-        }.run();
+        verify(listener, within(TIMEOUT_MS)).onScrollChanged();
 
-        listener.reset();
-        assertFalse(listener.hasCalledOnScrollChanged());
+        reset(listener);
 
         mViewTreeObserver.removeOnScrollChangedListener(listener);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                scrollView.fullScroll(View.FOCUS_UP);
-            }
-        });
-        assertFalse(listener.hasCalledOnScrollChanged());
-    }
-
-    private class MockOnGlobalFocusChangeListener implements OnGlobalFocusChangeListener {
-        private boolean mCalledOnGlobalFocusChanged = false;
-        View oldFocus;
-        View newFocus;
-
-        @Override
-        public void onGlobalFocusChanged(View oldFocus, View newFocus) {
-            mCalledOnGlobalFocusChanged = true;
-            this.oldFocus = oldFocus;
-            this.newFocus = newFocus;
-        }
-
-        public boolean hasCalledOnGlobalFocusChanged() {
-            return mCalledOnGlobalFocusChanged;
-        }
-
-        public void reset() {
-            mCalledOnGlobalFocusChanged = false;
-            oldFocus = null;
-            newFocus = null;
-        }
-    }
-
-    private class MockOnGlobalLayoutListener implements OnGlobalLayoutListener {
-        private boolean mCalledOnGlobalLayout = false;
-
-        @Override
-        public void onGlobalLayout() {
-            mCalledOnGlobalLayout = true;
-        }
-
-        public boolean hasCalledOnGlobalLayout() {
-            return mCalledOnGlobalLayout;
-        }
-
-        public void reset() {
-            mCalledOnGlobalLayout = false;
-        }
-    }
-
-    private class MockOnPreDrawListener implements OnPreDrawListener {
-        private boolean mCalledOnPreDraw = false;
-
-        @Override
-        public boolean onPreDraw() {
-            mCalledOnPreDraw = true;
-            return true;
-        }
-
-        public boolean hasCalledOnPreDraw() {
-            return mCalledOnPreDraw;
-        }
-
-        public void reset() {
-            mCalledOnPreDraw = false;
-        }
-    }
-
-    private class MockOnTouchModeChangeListener implements OnTouchModeChangeListener {
-        private boolean mCalledOnTouchModeChanged = false;
-
-        @Override
-        public void onTouchModeChanged(boolean isInTouchMode) {
-            mCalledOnTouchModeChanged = true;
-        }
-
-        public boolean hasCalledOnTouchModeChanged() {
-            return mCalledOnTouchModeChanged;
-        }
-    }
-
-    private static class MockOnScrollChangedListener implements OnScrollChangedListener {
-        private boolean mCalledOnScrollChanged = false;
-
-        public boolean hasCalledOnScrollChanged() {
-            return mCalledOnScrollChanged;
-        }
-
-        @Override
-        public void onScrollChanged() {
-            mCalledOnScrollChanged = true;
-        }
-
-        public void reset() {
-            mCalledOnScrollChanged = false;
-        }
+        mActivityRule.runOnUiThread(() -> scrollView.fullScroll(View.FOCUS_UP));
+        // Since we've unregistered our listener, we expect it to not be called even after
+        // we've waited for a couple of seconds
+        SystemClock.sleep(TIMEOUT_MS);
+        verifyZeroInteractions(listener);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/View_AnimationTest.java b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
index 07abb6f..81250ac 100644
--- a/tests/tests/view/src/android/view/cts/View_AnimationTest.java
+++ b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
@@ -16,41 +16,58 @@
 
 package android.view.cts;
 
+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 android.app.Activity;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
-import android.view.animation.Animation;
 import android.view.animation.TranslateAnimation;
 import android.view.animation.cts.AnimationTestUtils;
 
-import android.view.cts.R;
+import com.android.compatibility.common.util.PollingCheck;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link View}.
  */
-public class View_AnimationTest extends ActivityInstrumentationTestCase2<ViewTestCtsActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class View_AnimationTest {
 
     private static final int TIME_OUT = 5000;
     private static final int DURATION = 2000;
 
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
     private TranslateAnimation mAnimation;
 
-    public View_AnimationTest() {
-        super("android.view.cts", ViewTestCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewTestCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mAnimation =  new TranslateAnimation(0.0f, 10.0f, 0.0f, 10.0f);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mAnimation = new TranslateAnimation(0.0f, 10.0f, 0.0f, 10.0f);
         mAnimation.setDuration(DURATION);
     }
 
+    @Test
     public void testAnimation() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
         // set null animation
@@ -58,34 +75,29 @@
         assertNull(view.getAnimation());
 
         view.setAnimation(mAnimation);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                view.invalidate();
-            }
-        });
+        mActivityRule.runOnUiThread(view::invalidate);
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), view, mAnimation, TIME_OUT);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, view, mAnimation,
+                TIME_OUT);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testStartAnimationNull() {
+        final View view = mActivity.findViewById(R.id.mock_view);
+        view.startAnimation(null);
+    }
+
+    @Test
     public void testStartAnimation() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
-        // start null animation
-        try {
-            view.startAnimation(null);
-            fail("did not throw NullPointerException when start null animation");
-        } catch (NullPointerException e) {
-            // expected
-        }
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                view.startAnimation(mAnimation);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> view.startAnimation(mAnimation));
 
-        AnimationTestUtils.assertRunAnimation(getInstrumentation(), view, mAnimation, TIME_OUT);
+        AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, view, mAnimation,
+                TIME_OUT);
     }
 
+    @Test
     public void testClearBeforeAnimation() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
         assertFalse(mAnimation.hasStarted());
@@ -94,39 +106,28 @@
 
         assertSame(mAnimation, view.getAnimation());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                view.clearAnimation();
-                view.invalidate();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.clearAnimation();
+            view.invalidate();
         });
 
-        Thread.sleep(TIME_OUT);
+        SystemClock.sleep(TIME_OUT);
         assertFalse(mAnimation.hasStarted());
         assertNull(view.getAnimation());
     }
 
+    @Test
     public void testClearDuringAnimation() throws Throwable {
         final View view = mActivity.findViewById(R.id.mock_view);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                view.startAnimation(mAnimation);
-                assertNotNull(view.getAnimation());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            view.startAnimation(mAnimation);
+            assertNotNull(view.getAnimation());
         });
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mAnimation.hasStarted();
-            }
-        }.run();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                view.clearAnimation();
-            }
-        });
-        Thread.sleep(TIME_OUT);
+        PollingCheck.waitFor(TIME_OUT, mAnimation::hasStarted);
+
+        mActivityRule.runOnUiThread(view::clearAnimation);
+        SystemClock.sleep(TIME_OUT);
         assertTrue(mAnimation.hasStarted());
         assertTrue(mAnimation.hasEnded());
         assertNull(view.getAnimation());
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..74c240b 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,90 @@
 
 package android.view.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import android.os.Parcel;
-import android.test.InstrumentationTestCase;
+import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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 org.junit.Test;
+import org.junit.runner.RunWith;
 
-        new BaseSavedState(state);
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class View_BaseSavedStateTest {
+    @Test(expected=IllegalArgumentException.class)
+    public void testConstructorNullParcelable() {
+        new BaseSavedState((Parcelable) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullParcel() {
+        new BaseSavedState((Parcel) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullParcelAndLoader() {
+        new BaseSavedState(null, null);
+    }
+
+    @Test
+    public void testConstructors() {
+        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);
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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_FocusHandlingTest.java b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
index 564620e..c6e7d1f 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -16,24 +16,35 @@
 
 package android.view.cts;
 
-import android.view.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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
-public class View_FocusHandlingTest
-        extends ActivityInstrumentationTestCase2<FocusHandlingCtsActivity> {
-    public View_FocusHandlingTest() {
-        super("android.view.cts", FocusHandlingCtsActivity.class);
-    }
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_FocusHandlingTest {
+    @Rule
+    public ActivityTestRule<FocusHandlingCtsActivity> mActivityRule =
+            new ActivityTestRule<>(FocusHandlingCtsActivity.class);
 
     @UiThreadTest
+    @Test
     public void testFocusHandling() {
-        Activity activity = getActivity();
+        Activity activity = mActivityRule.getActivity();
 
         View v1 = activity.findViewById(R.id.view1);
         View v2 = activity.findViewById(R.id.view2);
diff --git a/tests/tests/view/src/android/view/cts/View_IdsTest.java b/tests/tests/view/src/android/view/cts/View_IdsTest.java
index 4dd00d6..200966b 100644
--- a/tests/tests/view/src/android/view/cts/View_IdsTest.java
+++ b/tests/tests/view/src/android/view/cts/View_IdsTest.java
@@ -16,25 +16,35 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 
 import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.View;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
 
-public class View_IdsTest extends ActivityInstrumentationTestCase2<UsingViewsCtsActivity> {
-    public View_IdsTest() {
-        super("android.view.cts", UsingViewsCtsActivity.class);
-    }
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_IdsTest {
+    @Rule
+    public ActivityTestRule<UsingViewsCtsActivity> mActivityRule =
+            new ActivityTestRule<>(UsingViewsCtsActivity.class);
 
     @UiThreadTest
+    @Test
     public void testIds() {
-        Activity activity = getActivity();
+        Activity activity;
+        activity = mActivityRule.getActivity();
 
         EditText editText = (EditText) activity.findViewById(R.id.entry);
         Button buttonOk = (Button) activity.findViewById(R.id.ok);
diff --git a/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java b/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
index 53514dc..833504e 100644
--- a/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
+++ b/tests/tests/view/src/android/view/cts/View_LayoutPositionTest.java
@@ -16,36 +16,41 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
+import static org.junit.Assert.assertEquals;
 
 import android.app.Activity;
-import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * For the view test is too big, we divide the test cases into several parts.
  * This part contains size, padding, margin, layout and drawing
  */
-public class View_LayoutPositionTest
-        extends ActivityInstrumentationTestCase2<ViewLayoutPositionTestCtsActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_LayoutPositionTest {
     private Activity mActivity;
 
-    public View_LayoutPositionTest() {
-        super("android.view.cts", ViewLayoutPositionTestCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewLayoutPositionTestCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewLayoutPositionTestCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testPositionInParent() {
         View parent = mActivity.findViewById(R.id.testparent);
         View view = mActivity.findViewById(R.id.testview);
@@ -101,6 +106,7 @@
         assertEquals(bottom + v_offset, nbottom);
     }
 
+    @Test
     public void testPadding() {
         View view = new View(mActivity);
 
diff --git a/tests/tests/view/src/android/view/cts/View_MeasureSpecTest.java b/tests/tests/view/src/android/view/cts/View_MeasureSpecTest.java
index ca29992..cf97e37 100644
--- a/tests/tests/view/src/android/view/cts/View_MeasureSpecTest.java
+++ b/tests/tests/view/src/android/view/cts/View_MeasureSpecTest.java
@@ -16,23 +16,31 @@
 
 package android.view.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.View.MeasureSpec;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link MeasureSpec}.
  */
-public class View_MeasureSpecTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class View_MeasureSpecTest {
     private static final int MEASURE_SPEC_SIZE = 1;
 
     private int mUnspecifiedMeasureSpec;
     private int mExactlyMeasureSpec;
     private int mAtMostMeasureSpec;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
         mUnspecifiedMeasureSpec = View.MeasureSpec.makeMeasureSpec(MEASURE_SPEC_SIZE,
                 View.MeasureSpec.UNSPECIFIED);
         mExactlyMeasureSpec = View.MeasureSpec.makeMeasureSpec(MEASURE_SPEC_SIZE,
@@ -41,9 +49,7 @@
                 View.MeasureSpec.AT_MOST);
     }
 
-    public void testConstructor() {
-    }
-
+    @Test
     public void testGetSize() {
         assertEquals(MEASURE_SPEC_SIZE,
                 View.MeasureSpec.getSize(mUnspecifiedMeasureSpec));
@@ -53,6 +59,7 @@
                 View.MeasureSpec.getSize(mAtMostMeasureSpec));
     }
 
+    @Test
     public void testToString() {
         assertEquals("MeasureSpec: UNSPECIFIED " + MEASURE_SPEC_SIZE,
                 View.MeasureSpec.toString(mUnspecifiedMeasureSpec));
@@ -62,6 +69,7 @@
                 View.MeasureSpec.toString(mAtMostMeasureSpec));
     }
 
+    @Test
     public void testGetMode() {
         assertEquals(View.MeasureSpec.UNSPECIFIED,
                 View.MeasureSpec.getMode(mUnspecifiedMeasureSpec));
@@ -71,6 +79,7 @@
                 View.MeasureSpec.getMode(mAtMostMeasureSpec));
     }
 
+    @Test
     public void testMakeMeasureSpec() {
         assertEquals(MEASURE_SPEC_SIZE + View.MeasureSpec.UNSPECIFIED,
                 mUnspecifiedMeasureSpec);
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..dd731cc 100644
--- a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
+++ b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java
@@ -16,28 +16,50 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+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.app.Activity;
 import android.app.Instrumentation;
-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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+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.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnLongClickListener;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.compatibility.common.util.CtsTouchUtils;
 
-public class View_UsingViewsTest extends ActivityInstrumentationTestCase2<UsingViewsCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_UsingViewsTest {
     /**
      * country of Argentina
      */
@@ -68,8 +90,8 @@
      */
     private static final String CHINA_SYMBOL = "table tennis";
 
-    private Activity mActivity;
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
 
     private EditText mEditText;
     private Button mButtonOk;
@@ -77,16 +99,14 @@
     private TextView mSymbolTextView;
     private TextView mWarningTextView;
 
-    public View_UsingViewsTest() {
-        super("android.view.cts", UsingViewsCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<UsingViewsCtsActivity> mActivityRule =
+            new ActivityTestRule<>(UsingViewsCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
 
         mEditText = (EditText) mActivity.findViewById(R.id.entry);
         mButtonOk = (Button) mActivity.findViewById(R.id.ok);
@@ -96,34 +116,33 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetProperties() {
-        /**
-         * setClickable, setOnClickListener
-         */
+        // setClickable, setOnClickListener
         mButtonOk.setClickable(true);
         assertTrue(mButtonOk.isClickable());
 
-        MockOnClickOkListener okButtonListener = new MockOnClickOkListener();
+        View.OnClickListener okButtonListener = spy(new MockOnClickOkListener());
         mButtonOk.setOnClickListener(okButtonListener);
-        assertFalse(okButtonListener.hasOnClickCalled());
 
         mButtonOk.performClick();
-        assertTrue(okButtonListener.hasOnClickCalled());
+        verify(okButtonListener, times(1)).onClick(mButtonOk);
 
         mButtonCancel.setClickable(false);
         assertFalse(mButtonCancel.isClickable());
 
-        MockOnClickCancelListener cancelButtonListener = new MockOnClickCancelListener();
+        View.OnClickListener cancelButtonListener = mock(View.OnClickListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            mEditText.setText(null);
+            return null;
+        }).when(cancelButtonListener).onClick(any(View.class));
         mButtonCancel.setOnClickListener(cancelButtonListener);
-        assertFalse(cancelButtonListener.hasOnClickCalled());
         assertTrue(mButtonCancel.isClickable());
 
         mButtonCancel.performClick();
-        assertTrue(cancelButtonListener.hasOnClickCalled());
+        verify(cancelButtonListener, times(1)).onClick(mButtonCancel);
 
-        /**
-         * setDrawingCacheEnabled, setDrawingCacheQuality, setDrawingCacheBackgroundColor,
-         */
+        // setDrawingCacheEnabled, setDrawingCacheQuality, setDrawingCacheBackgroundColor,
         mEditText.setDrawingCacheEnabled(true);
         assertTrue(mEditText.isDrawingCacheEnabled());
 
@@ -160,9 +179,7 @@
         assertEquals(Color.YELLOW, b.getPixel(0, 0));
         mEditText.destroyDrawingCache();
 
-        /**
-         * setDuplicateParentStateEnabled
-         */
+        // setDuplicateParentStateEnabled
         TextView v = new TextView(mActivity);
         v.setSingleLine(); // otherwise the multiline state interferes with theses tests
         v.setEnabled(false);
@@ -183,23 +200,18 @@
         parent.addView(v);
         v.refreshDrawableState();
 
-        assertEquals(parent.getDrawableState().length, v.getDrawableState().length);
-        assertEquals(parent.getDrawableState().toString(), v.getDrawableState().toString());
+        assertArrayEquals(parent.getDrawableState(), v.getDrawableState());
         parent.removeView(v);
 
-        /**
-         * setEnabled
-         */
+        // setEnabled
         mWarningTextView.setEnabled(false);
         assertFalse(mWarningTextView.isEnabled());
 
         mWarningTextView.setEnabled(true);
         assertTrue(mWarningTextView.isEnabled());
 
-        /**
-         * setFadingEdgeLength, setVerticalFadingEdgeEnabled and
-         * setHorizontalFadingEdgeEnabled(boolean)
-         */
+        // setFadingEdgeLength, setVerticalFadingEdgeEnabled and
+        // setHorizontalFadingEdgeEnabled(boolean)
         mWarningTextView.setVerticalFadingEdgeEnabled(true);
         assertTrue(mWarningTextView.isVerticalFadingEdgeEnabled());
         mWarningTextView.setFadingEdgeLength(10);
@@ -208,9 +220,7 @@
         assertTrue(mSymbolTextView.isHorizontalFadingEdgeEnabled());
         mSymbolTextView.setFadingEdgeLength(100);
 
-        /**
-         * setFocusable and setFocusableInTouchMode
-         */
+        // setFocusable and setFocusableInTouchMode
         mButtonCancel.setFocusable(false);
         assertFalse(mButtonCancel.isFocusable());
         assertFalse(mButtonCancel.isFocusableInTouchMode());
@@ -231,9 +241,7 @@
         assertTrue(mButtonOk.isFocusable());
         assertTrue(mButtonOk.isFocusableInTouchMode());
 
-        /**
-         * setHorizontalScrollBarEnabled and setVerticalScrollBarEnabled
-         */
+        // setHorizontalScrollBarEnabled and setVerticalScrollBarEnabled
         // both two bar is not drawn by default
         assertFalse(parent.isHorizontalScrollBarEnabled());
         assertFalse(parent.isVerticalScrollBarEnabled());
@@ -244,9 +252,7 @@
         parent.setVerticalScrollBarEnabled(true);
         assertTrue(parent.isVerticalScrollBarEnabled());
 
-        /**
-         * setId
-         */
+        // setId
         assertEquals(View.NO_ID, parent.getId());
         assertEquals(R.id.entry, mEditText.getId());
         assertEquals(R.id.symbolball, mSymbolTextView.getId());
@@ -261,14 +267,15 @@
     }
 
     @UiThreadTest
-    public void testSetFocus() throws Throwable {
+    @Test
+    public void testSetFocus() {
         boolean focusWasOnEditText = mEditText.hasFocus();
 
-        MockOnFocusChangeListener editListener = new MockOnFocusChangeListener();
-        MockOnFocusChangeListener okListener = new MockOnFocusChangeListener();
-        MockOnFocusChangeListener cancelListener = new MockOnFocusChangeListener();
-        MockOnFocusChangeListener symbolListener = new MockOnFocusChangeListener();
-        MockOnFocusChangeListener warningListener = new MockOnFocusChangeListener();
+        View.OnFocusChangeListener editListener = mock(View.OnFocusChangeListener.class);
+        View.OnFocusChangeListener okListener = mock(View.OnFocusChangeListener.class);
+        View.OnFocusChangeListener cancelListener = mock(View.OnFocusChangeListener.class);
+        View.OnFocusChangeListener symbolListener = mock(View.OnFocusChangeListener.class);
+        View.OnFocusChangeListener warningListener = mock(View.OnFocusChangeListener.class);
 
         mEditText.setOnFocusChangeListener(editListener);
         mButtonOk.setOnFocusChangeListener(okListener);
@@ -286,141 +293,139 @@
         assertFalse(mSymbolTextView.hasFocus());
         assertFalse(mWarningTextView.hasFocus());
 
-        assertTrue(editListener.hasFocus() || focusWasOnEditText);
-        assertFalse(okListener.hasFocus());
-        assertFalse(cancelListener.hasFocus());
-        assertFalse(symbolListener.hasFocus());
-        assertFalse(warningListener.hasFocus());
+        if (!focusWasOnEditText) {
+            verify(editListener, times(1)).onFocusChange(mEditText, true);
+        }
+        verifyZeroInteractions(okListener);
+        verifyZeroInteractions(cancelListener);
+        verifyZeroInteractions(symbolListener);
+        verifyZeroInteractions(warningListener);
 
         // set ok button to focus
+        reset(editListener);
         assertTrue(mButtonOk.requestFocus());
         assertTrue(mButtonOk.hasFocus());
-        assertTrue(okListener.hasFocus());
+        verify(okListener, times(1)).onFocusChange(mButtonOk, true);
         assertFalse(mEditText.hasFocus());
-        assertFalse(editListener.hasFocus());
+        verify(editListener, times(1)).onFocusChange(mEditText, false);
+        verifyZeroInteractions(cancelListener);
+        verifyZeroInteractions(symbolListener);
+        verifyZeroInteractions(warningListener);
 
         // set cancel button to focus
+        reset(okListener);
+        reset(editListener);
         assertTrue(mButtonCancel.requestFocus());
         assertTrue(mButtonCancel.hasFocus());
-        assertTrue(cancelListener.hasFocus());
+        verify(cancelListener, times(1)).onFocusChange(mButtonCancel, true);
         assertFalse(mButtonOk.hasFocus());
-        assertFalse(okListener.hasFocus());
+        verify(okListener, times(1)).onFocusChange(mButtonOk, false);
+        verifyZeroInteractions(editListener);
+        verifyZeroInteractions(symbolListener);
+        verifyZeroInteractions(warningListener);
 
         // set symbol text to focus
         mSymbolTextView.setFocusable(true);
         assertTrue(mSymbolTextView.requestFocus());
         assertTrue(mSymbolTextView.hasFocus());
-        assertTrue(symbolListener.hasFocus());
+        verify(symbolListener, times(1)).onFocusChange(mSymbolTextView, true);
         assertFalse(mButtonCancel.hasFocus());
-        assertFalse(cancelListener.hasFocus());
+        verify(cancelListener, times(1)).onFocusChange(mButtonCancel, false);
+        verifyZeroInteractions(okListener);
+        verifyZeroInteractions(editListener);
+        verifyZeroInteractions(warningListener);
 
         // set warning text to focus
         mWarningTextView.setFocusable(true);
         assertTrue(mWarningTextView.requestFocus());
         assertTrue(mWarningTextView.hasFocus());
-        assertTrue(warningListener.hasFocus());
+        verify(warningListener, times(1)).onFocusChange(mWarningTextView, true);
         assertFalse(mSymbolTextView.hasFocus());
-        assertFalse(symbolListener.hasFocus());
+        verify(symbolListener, times(1)).onFocusChange(mSymbolTextView, false);
+        verifyZeroInteractions(editListener);
+        verifyZeroInteractions(okListener);
+        verifyZeroInteractions(cancelListener);
 
         // set edit text to focus
         assertTrue(mEditText.requestFocus());
         assertTrue(mEditText.hasFocus());
-        assertTrue(editListener.hasFocus());
+        verify(editListener, times(1)).onFocusChange(mEditText, true);
         assertFalse(mWarningTextView.hasFocus());
-        assertFalse(warningListener.hasFocus());
+        verify(warningListener, times(1)).onFocusChange(mWarningTextView, false);
+        verifyZeroInteractions(cancelListener);
+        verifyZeroInteractions(symbolListener);
+        verifyZeroInteractions(okListener);
     }
 
+    @Test
     public void testSetupListeners() throws Throwable {
         // set ok button OnClick listener
         mButtonOk.setClickable(true);
         assertTrue(mButtonOk.isClickable());
 
-        MockOnClickOkListener okButtonListener = new MockOnClickOkListener();
+        View.OnClickListener okButtonListener = spy(new MockOnClickOkListener());
         mButtonOk.setOnClickListener(okButtonListener);
 
         // set cancel button OnClick listener
         mButtonCancel.setClickable(true);
         assertTrue(mButtonCancel.isClickable());
 
-        MockOnClickCancelListener cancelButtonListener = new MockOnClickCancelListener();
+        View.OnClickListener cancelButtonListener = mock(View.OnClickListener.class);
+        doAnswer((InvocationOnMock invocation) -> {
+            mEditText.setText(null);
+            return null;
+        }).when(cancelButtonListener).onClick(any(View.class));
         mButtonCancel.setOnClickListener(cancelButtonListener);
 
         // set edit text OnLongClick listener
         mEditText.setLongClickable(true);
         assertTrue(mEditText.isLongClickable());
 
-        final MockOnLongClickListener onLongClickListener = new MockOnLongClickListener();
+        final View.OnLongClickListener onLongClickListener =
+                mock(View.OnLongClickListener.class);
         mEditText.setOnLongClickListener(onLongClickListener);
 
         // long click the edit text
-        assertFalse(onLongClickListener.isOnLongClickCalled());
-        assertNull(onLongClickListener.getView());
-
         mInstrumentation.waitForIdleSync();
-        TouchUtils.longClickView(this, mEditText);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return onLongClickListener.isOnLongClickCalled();
-            }
-        }.run();
-        assertSame(mEditText, onLongClickListener.getView());
+        CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, mEditText);
+        verify(onLongClickListener, within(1000)).onLongClick(mEditText);
 
         // click the Cancel button
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mEditText.setText("Germany");
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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");
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mEditText.setText("Unknown"));
         mInstrumentation.waitForIdleSync();
 
-        TouchUtils.clickView(this, mButtonOk);
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mButtonOk);
         assertEquals(View.VISIBLE, mWarningTextView.getVisibility());
     }
 
     @UiThreadTest
-    public void testSetVisibility() throws Throwable {
+    @Test
+    public void testSetVisibility() {
         mActivity.setContentView(R.layout.view_visibility_layout);
 
         View v1 = mActivity.findViewById(R.id.textview1);
@@ -445,21 +450,7 @@
         assertEquals(View.INVISIBLE, v3.getVisibility());
     }
 
-    private static class MockOnFocusChangeListener implements OnFocusChangeListener {
-        private boolean mHasFocus;
-
-        public void onFocusChange(View v, boolean hasFocus) {
-            mHasFocus = hasFocus;
-        }
-
-        public boolean hasFocus() {
-            return mHasFocus;
-        }
-    }
-
-    private class MockOnClickOkListener implements OnClickListener {
-        private boolean mHasOnClickCalled = false;
-
+    protected class MockOnClickOkListener implements OnClickListener {
         private boolean showPicture(String country) {
             if (ARGENTINA.equals(country)) {
                 mSymbolTextView.setText(ARGENTINA_SYMBOL);
@@ -476,8 +467,6 @@
         }
 
         public void onClick(View v) {
-            mHasOnClickCalled = true;
-
             String country = mEditText.getText().toString();
             if (!showPicture(country)) {
                 mWarningTextView.setVisibility(View.VISIBLE);
@@ -485,50 +474,5 @@
                 mWarningTextView.setVisibility(View.INVISIBLE);
             }
         }
-
-        public boolean hasOnClickCalled() {
-            return mHasOnClickCalled;
-        }
-
-        public void reset() {
-            mHasOnClickCalled = false;
-        }
-    }
-
-    private class MockOnClickCancelListener implements OnClickListener {
-        private boolean mHasOnClickCalled = false;
-
-        public void onClick(View v) {
-            mHasOnClickCalled = true;
-
-            mEditText.setText(null);
-        }
-
-        public boolean hasOnClickCalled() {
-            return mHasOnClickCalled;
-        }
-
-        public void reset() {
-            mHasOnClickCalled = false;
-        }
-    }
-
-    private static class MockOnLongClickListener implements OnLongClickListener {
-        private boolean mIsOnLongClickCalled;
-        private View mView;
-
-        public boolean onLongClick(View v) {
-            mIsOnLongClickCalled = true;
-            mView = v;
-            return true;
-        }
-
-        public boolean isOnLongClickCalled() {
-            return mIsOnLongClickCalled;
-        }
-
-        public View getView() {
-            return mView;
-        }
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/WindowCtsActivity.java b/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
index 3cfcc96..0d8e14c 100644
--- a/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/WindowCtsActivity.java
@@ -16,8 +16,6 @@
 
 package android.view.cts;
 
-import android.view.cts.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.KeyEvent;
diff --git a/tests/tests/view/src/android/view/cts/WindowManager_BadTokenExceptionTest.java b/tests/tests/view/src/android/view/cts/WindowManager_BadTokenExceptionTest.java
index db5607c..1e31b11 100644
--- a/tests/tests/view/src/android/view/cts/WindowManager_BadTokenExceptionTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowManager_BadTokenExceptionTest.java
@@ -15,11 +15,20 @@
  */
 package android.view.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager.BadTokenException;
 
-public class WindowManager_BadTokenExceptionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowManager_BadTokenExceptionTest {
+    @Test
     public void testBadTokenException(){
         BadTokenException badTokenException = new BadTokenException();
         try {
diff --git a/tests/tests/view/src/android/view/cts/WindowManager_LayoutParamsTest.java b/tests/tests/view/src/android/view/cts/WindowManager_LayoutParamsTest.java
index 7586ed3..b829470 100644
--- a/tests/tests/view/src/android/view/cts/WindowManager_LayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowManager_LayoutParamsTest.java
@@ -16,17 +16,28 @@
 
 package android.view.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.junit.Assert.fail;
 
 import android.graphics.PixelFormat;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannedString;
 import android.view.Gravity;
 import android.view.WindowManager;
 
-public class WindowManager_LayoutParamsTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowManager_LayoutParamsTest {
     private static final int WINDOW_WIDTH = 320;
     private static final int WINDOW_HEIGHT = 480;
     private static final int XPOS = 10;
@@ -45,6 +56,7 @@
 
     private WindowManager.LayoutParams mLayoutParams;
 
+    @Test
     public void testConstructor() {
         new WindowManager.LayoutParams();
 
@@ -87,6 +99,7 @@
                 .mayUseInputMethod(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM));
     }
 
+    @Test
     public void testCopyFrom() {
         mLayoutParams = new WindowManager.LayoutParams();
         WindowManager.LayoutParams params = new WindowManager.LayoutParams(
@@ -125,8 +138,8 @@
                 | WindowManager.LayoutParams.ACCESSIBILITY_TITLE_CHANGED,
                 mLayoutParams.copyFrom(params));
         assertEquals(params.getTitle(), mLayoutParams.getTitle());
-        assertEquals(params.alpha, mLayoutParams.alpha);
-        assertEquals(params.dimAmount, mLayoutParams.dimAmount);
+        assertEquals(params.alpha, mLayoutParams.alpha, 0.0f);
+        assertEquals(params.dimAmount, mLayoutParams.dimAmount, 0.0f);
 
         params = new WindowManager.LayoutParams();
         params.gravity = Gravity.TOP;
@@ -140,36 +153,38 @@
         mLayoutParams = new WindowManager.LayoutParams();
         assertEquals(WindowManager.LayoutParams.LAYOUT_CHANGED,
                 mLayoutParams.copyFrom(params));
-        assertEquals(params.horizontalMargin, mLayoutParams.horizontalMargin);
+        assertEquals(params.horizontalMargin, mLayoutParams.horizontalMargin, 0.0f);
 
         params = new WindowManager.LayoutParams();
         params.horizontalWeight = HORIZONTAL_WEIGHT;
         mLayoutParams = new WindowManager.LayoutParams();
         assertEquals(WindowManager.LayoutParams.LAYOUT_CHANGED,
                 mLayoutParams.copyFrom(params));
-        assertEquals(params.horizontalWeight, mLayoutParams.horizontalWeight);
+        assertEquals(params.horizontalWeight, mLayoutParams.horizontalWeight, 0.0f);
 
         params = new WindowManager.LayoutParams();
         params.verticalMargin = MARGIN;
         mLayoutParams = new WindowManager.LayoutParams();
         assertEquals(WindowManager.LayoutParams.LAYOUT_CHANGED,
                 mLayoutParams.copyFrom(params));
-        assertEquals(params.verticalMargin, mLayoutParams.verticalMargin);
+        assertEquals(params.verticalMargin, mLayoutParams.verticalMargin, 0.0f);
 
         params = new WindowManager.LayoutParams();
         params.verticalWeight = VERTICAL_WEIGHT;
         mLayoutParams = new WindowManager.LayoutParams();
         assertEquals(WindowManager.LayoutParams.LAYOUT_CHANGED,
                 mLayoutParams.copyFrom(params));
-        assertEquals(params.verticalWeight, mLayoutParams.verticalWeight);
+        assertEquals(params.verticalWeight, mLayoutParams.verticalWeight, 0.0f);
     }
 
+    @Test
     public void testDescribeContents() {
         mLayoutParams = new WindowManager.LayoutParams();
 
         assertEquals(0, mLayoutParams.describeContents());
     }
 
+    @Test
     public void testAccessTitle() {
         String title = "";
         mLayoutParams = new WindowManager.LayoutParams();
@@ -186,6 +201,7 @@
         assertEquals(spannedTitle, mLayoutParams.getTitle());
     }
 
+    @Test
     public void testToString() {
         mLayoutParams = new WindowManager.LayoutParams();
         assertNotNull(mLayoutParams.toString());
@@ -196,6 +212,7 @@
         assertNotNull(mLayoutParams.toString());
     }
 
+    @Test
     public void testWriteToParcel() {
         IBinder binder = new Binder();
         mLayoutParams = new WindowManager.LayoutParams(WINDOW_WIDTH, WINDOW_HEIGHT, XPOS, YPOS,
@@ -224,7 +241,4 @@
             // expected
         }
     }
-
-    public void testDebug() {
-    }
 }
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index 439eda5..b1bf50e 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -16,15 +16,26 @@
 
 package android.view.cts;
 
-import android.view.ContextThemeWrapper;
-import android.view.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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+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 android.app.Instrumentation;
 import android.app.Presentation;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.cts.util.PollingCheck;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
@@ -36,22 +47,21 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.ActionMode;
+import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
-import android.view.KeyboardShortcutGroup;
 import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.MotionEvent;
-import android.view.SearchEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
@@ -59,54 +69,69 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.Button;
 import android.widget.TextView;
 
-import java.util.List;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-public class WindowTest extends ActivityInstrumentationTestCase2<WindowCtsActivity> {
-    static final String TAG = "WindowTest";
-    private Window mWindow;
-    private Context mContext;
-    private Instrumentation mInstrumentation;
-    private WindowCtsActivity mActivity;
-    private SurfaceView surfaceView;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WindowTest {
+    private static final String TAG = "WindowTest";
     private static final int VIEWGROUP_LAYOUT_HEIGHT = 100;
     private static final int VIEWGROUP_LAYOUT_WIDTH = 200;
 
+    private Instrumentation mInstrumentation;
+    private WindowCtsActivity mActivity;
+    private Window mWindow;
+    private Window.Callback mWindowCallback;
+    private SurfaceView mSurfaceView;
+
     // for testing setLocalFocus
     private ProjectedPresentation mPresentation;
     private VirtualDisplay mVirtualDisplay;
 
-    public WindowTest() {
-        super("android.view.cts", WindowCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<WindowCtsActivity> mActivityRule =
+            new ActivityTestRule<>(WindowCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getContext();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mWindow = mActivity.getWindow();
+
+
+        mWindowCallback = mock(Window.Callback.class);
+        doReturn(true).when(mWindowCallback).dispatchKeyEvent(any());
+        doReturn(true).when(mWindowCallback).dispatchTouchEvent(any());
+        doReturn(true).when(mWindowCallback).dispatchTrackballEvent(any());
+        doReturn(true).when(mWindowCallback).dispatchGenericMotionEvent(any());
+        doReturn(true).when(mWindowCallback).dispatchPopulateAccessibilityEvent(any());
+        doReturn(true).when(mWindowCallback).onMenuItemSelected(anyInt(), any());
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         if (mActivity != null) {
             mActivity.setFlagFalse();
         }
-        super.tearDown();
     }
 
     @UiThreadTest
-    public void testConstructor() throws Exception {
-        mWindow = new MockWindow(mContext);
-        assertSame(mContext, mWindow.getContext());
+    @Test
+    public void testConstructor() {
+        mWindow = new MockWindow(mActivity);
+        assertSame(mActivity, mWindow.getContext());
     }
 
     /**
@@ -117,8 +142,9 @@
      *              _2. test invocation of Window.Callback#onWindowAttributesChanged.
      * 3. clearFlags: clear the flag bits as specified in flags.
      */
-   public void testOpFlags() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testOpFlags() {
+        mWindow = new MockWindow(mActivity);
         final WindowManager.LayoutParams attrs = mWindow.getAttributes();
         assertEquals(0, attrs.flags);
 
@@ -134,21 +160,21 @@
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DITHER);
         assertEquals(0, attrs.flags);
 
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         // mask == flag, no bit of flag need to be modified.
         mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
         assertEquals(WindowManager.LayoutParams.FLAG_FULLSCREEN, attrs.flags);
 
         // Test if the callback method is called by system
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attrs);
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DITHER);
     }
 
-    public void testFindViewById() throws Exception {
+    @Test
+    public void testFindViewById() {
         TextView v = (TextView) mWindow.findViewById(R.id.listview_window);
         assertNotNull(v);
         assertEquals(R.id.listview_window, v.getId());
@@ -165,8 +191,9 @@
      *    there is just one method, onWindowAttributesChanged, used.
      * getCallback: Return the current Callback interface for this window.
      */
-    public void testAccessAttributes() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testAccessAttributes() {
+        mWindow = new MockWindow(mActivity);
 
         // default attributes
         WindowManager.LayoutParams attr = mWindow.getAttributes();
@@ -180,10 +207,9 @@
         WindowManager.LayoutParams param = new WindowManager.LayoutParams(width, height,
                 WindowManager.LayoutParams.TYPE_BASE_APPLICATION,
                 WindowManager.LayoutParams.FLAG_DITHER, PixelFormat.RGBA_8888);
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertSame(callback, mWindow.getCallback());
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        assertSame(mWindowCallback, mWindow.getCallback());
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         mWindow.setAttributes(param);
         attr = mWindow.getAttributes();
         assertEquals(width, attr.width);
@@ -191,7 +217,7 @@
         assertEquals(WindowManager.LayoutParams.TYPE_BASE_APPLICATION, attr.type);
         assertEquals(PixelFormat.RGBA_8888, attr.format);
         assertEquals(WindowManager.LayoutParams.FLAG_DITHER, attr.flags);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attr);
     }
 
     /**
@@ -199,12 +225,13 @@
      * container is false;
      * Otherwise, it will display itself meanwhile container's mHasChildren is true.
      */
-    public void testAccessContainer() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testAccessContainer() {
+        mWindow = new MockWindow(mActivity);
         assertNull(mWindow.getContainer());
         assertFalse(mWindow.hasChildren());
 
-        MockWindow container = new MockWindow(mContext);
+        MockWindow container = new MockWindow(mActivity);
         mWindow.setContainer(container);
         assertSame(container, mWindow.getContainer());
         assertTrue(container.hasChildren());
@@ -217,30 +244,24 @@
      * getLayoutInflater: Quick access to the {@link LayoutInflater} instance that this Window
      *    retrieved from its Context.
      */
-    public void testAddContentView() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testAddContentView() {
         final ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(VIEWGROUP_LAYOUT_WIDTH,
                 VIEWGROUP_LAYOUT_HEIGHT);
         // The LayoutInflater instance will be inflated to a view and used by
         // addContentView,
         // id of this view should be same with inflated id.
         final LayoutInflater inflater = mActivity.getLayoutInflater();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                TextView addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
-                assertNull(addedView);
-                mWindow.addContentView(inflater.inflate(R.layout.windowstub_addlayout, null), lp);
-                TextView view = (TextView) mWindow.findViewById(R.id.listview_window);
-                addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
-                assertNotNull(view);
-                assertNotNull(addedView);
-                assertEquals(R.id.listview_window, view.getId());
-                assertEquals(R.id.listview_addwindow, addedView.getId());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
-    public void testCloseAllPanels() throws Throwable {
+        TextView addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
+        assertNull(addedView);
+        mWindow.addContentView(inflater.inflate(R.layout.windowstub_addlayout, null), lp);
+        TextView view = (TextView) mWindow.findViewById(R.id.listview_window);
+        addedView = (TextView) mWindow.findViewById(R.id.listview_addwindow);
+        assertNotNull(view);
+        assertNotNull(addedView);
+        assertEquals(R.id.listview_window, view.getId());
+        assertEquals(R.id.listview_addwindow, addedView.getId());
     }
 
     /**
@@ -250,22 +271,19 @@
      * 1. Set focus view to null, get current focus, it should be null
      * 2. Set listview_window as focus view, get it and compare.
      */
-    public void testGetCurrentFocus() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                TextView v = (TextView) mWindow.findViewById(R.id.listview_window);
-                v.clearFocus();
-                assertNull(mWindow.getCurrentFocus());
+    @UiThreadTest
+    @Test
+    public void testGetCurrentFocus() {
+        TextView v = (TextView) mWindow.findViewById(R.id.listview_window);
+        v.clearFocus();
+        assertNull(mWindow.getCurrentFocus());
 
-                v.setFocusable(true);
-                assertTrue(v.isFocusable());
-                assertTrue(v.requestFocus());
-                View focus = mWindow.getCurrentFocus();
-                assertNotNull(focus);
-                assertEquals(R.id.listview_window, focus.getId());
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        v.setFocusable(true);
+        assertTrue(v.isFocusable());
+        assertTrue(v.requestFocus());
+        View focus = mWindow.getCurrentFocus();
+        assertNotNull(focus);
+        assertEquals(R.id.listview_window, focus.getId());
     }
 
     /**
@@ -276,19 +294,20 @@
      *    ontext is same as Window's context.
      * 2. Return null if decor view is not created, else the same with detDecorView.
      */
-    public void testDecorView() throws Exception {
+    @Test
+    public void testDecorView() {
         mInstrumentation.waitForIdleSync();
         View decor = mWindow.getDecorView();
         assertNotNull(decor);
-        checkDecorView(decor);
+        verifyDecorView(decor);
 
         decor = mWindow.peekDecorView();
         if (decor != null) {
-            checkDecorView(decor);
+            verifyDecorView(decor);
         }
     }
 
-    private void checkDecorView(View decor) {
+    private void verifyDecorView(View decor) {
         DisplayMetrics dm = new DisplayMetrics();
         mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
         int screenWidth = dm.widthPixels;
@@ -304,7 +323,8 @@
      * getVolumeControlStream: Gets the suggested audio stream whose volume should be changed by
      *    the harwdare volume controls.
      */
-    public void testAccessVolumeControlStream() throws Exception {
+    @Test
+    public void testAccessVolumeControlStream() {
         // Default value is AudioManager.USE_DEFAULT_STREAM_TYPE, see javadoc of
         // {@link Activity#setVolumeControlStream}.
         assertEquals(AudioManager.USE_DEFAULT_STREAM_TYPE, mWindow.getVolumeControlStream());
@@ -317,12 +337,14 @@
      * getWindowManager: Return the window manager allowing this Window to display its own
      *    windows.
      */
-    public void testAccessWindowManager() throws Exception {
-        mWindow = new MockWindow(getActivity());
-        WindowManager expected = (WindowManager) getActivity().getSystemService(
+    @Test
+    public void testAccessWindowManager() {
+        mWindow = new MockWindow(mActivity);
+        WindowManager expected = (WindowManager) mActivity.getSystemService(
                 Context.WINDOW_SERVICE);
         assertNull(mWindow.getWindowManager());
-        mWindow.setWindowManager(expected, null, getName());
+        mWindow.setWindowManager(expected, null,
+                mActivity.getApplicationInfo().loadLabel(mActivity.getPackageManager()).toString());
         // No way to compare the expected and actual directly, they are
         // different object
         assertNotNull(mWindow.getWindowManager());
@@ -332,8 +354,9 @@
      * Return the {@link android.R.styleable#Window} attributes from this
      * window's theme. It's invisible.
      */
-    public void testGetWindowStyle() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testGetWindowStyle() {
+        mWindow = new MockWindow(mActivity);
         final TypedArray windowStyle = mWindow.getWindowStyle();
         // the windowStyle is obtained from
         // com.android.internal.R.styleable.Window whose details
@@ -341,8 +364,9 @@
         assertNotNull(windowStyle);
     }
 
-    public void testIsActive() throws Exception {
-        MockWindow window = new MockWindow(mContext);
+    @Test
+    public void testIsActive() {
+        MockWindow window = new MockWindow(mActivity);
         assertFalse(window.isActive());
 
         window.makeActive();
@@ -354,64 +378,46 @@
      * isFloating: Return whether this window is being displayed with a floating style
      * (based on the {@link android.R.attr#windowIsFloating} attribute in the style/theme).
      */
-    public void testIsFloating() throws Exception {
+    @Test
+    public void testIsFloating() {
         // Default system theme defined by themes.xml, the windowIsFloating is set false.
         assertFalse(mWindow.isFloating());
     }
 
-    public void testPerformMethods() throws Exception {
-    }
-
-    public void testKeepHierarchyState() throws Exception {
-    }
-
     /**
      * Change the background of this window to a custom Drawable.
      * Setting the background to null will make the window be opaque(No way to get the window
      *  attribute of PixelFormat to check if the window is opaque). To make the window
      * transparent, you can use an empty drawable(eg. ColorDrawable with the color 0).
      */
+    @Test
     public void testSetBackgroundDrawable() throws Throwable {
         // DecorView holds the background
         View decor = mWindow.getDecorView();
         if (!mWindow.hasFeature(Window.FEATURE_SWIPE_TO_DISMISS)) {
             assertEquals(PixelFormat.OPAQUE, decor.getBackground().getOpacity());
         }
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                // setBackgroundDrawableResource(int resId) has the same
-                // functionality with
-                // setBackgroundDrawable(Drawable drawable), just different in
-                // parameter.
-                mWindow.setBackgroundDrawableResource(R.drawable.faces);
-            }
-        });
+        // setBackgroundDrawableResource(int resId) has the same
+        // functionality with setBackgroundDrawable(Drawable drawable), just different in
+        // parameter.
+        mActivityRule.runOnUiThread(() -> mWindow.setBackgroundDrawableResource(R.drawable.faces));
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ColorDrawable drawable = new ColorDrawable(0);
-                mWindow.setBackgroundDrawable(drawable);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            ColorDrawable drawable = new ColorDrawable(0);
+            mWindow.setBackgroundDrawable(drawable);
         });
         mInstrumentation.waitForIdleSync();
         decor = mWindow.getDecorView();
         // Color 0 with one alpha bit
         assertEquals(PixelFormat.TRANSPARENT, decor.getBackground().getOpacity());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mWindow.setBackgroundDrawable(null);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mWindow.setBackgroundDrawable(null));
         mInstrumentation.waitForIdleSync();
         decor = mWindow.getDecorView();
         assertNull(decor.getBackground());
     }
 
-    public void testSetChild() throws Exception {
-    }
-
     /**
      * setContentView(int): set the screen content from a layout resource.
      * setContentView(View): set the screen content to an explicit view.
@@ -425,105 +431,64 @@
      *   1. can't get the features requested because the getter is protected final.
      *   2. certain window flags are not clear to concrete one.
      */
+    @Test
     public void testSetContentView() throws Throwable {
         final ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(VIEWGROUP_LAYOUT_WIDTH,
                 VIEWGROUP_LAYOUT_HEIGHT);
         final LayoutInflater inflate = mActivity.getLayoutInflater();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                TextView view;
-                View setView;
-                // Test setContentView(int layoutResID)
-                mWindow.setContentView(R.layout.windowstub_layout);
-                view = (TextView) mWindow.findViewById(R.id.listview_window);
-                assertNotNull(view);
-                assertEquals(R.id.listview_window, view.getId());
+        mActivityRule.runOnUiThread(() -> {
+            TextView view;
+            View setView;
+            // Test setContentView(int layoutResID)
+            mWindow.setContentView(R.layout.windowstub_layout);
+            view = (TextView) mWindow.findViewById(R.id.listview_window);
+            assertNotNull(view);
+            assertEquals(R.id.listview_window, view.getId());
 
-                // Test setContentView(View view)
-                setView = inflate.inflate(R.layout.windowstub_addlayout, null);
-                mWindow.setContentView(setView);
-                view = (TextView) mWindow.findViewById(R.id.listview_addwindow);
-                assertNotNull(view);
-                assertEquals(R.id.listview_addwindow, view.getId());
+            // Test setContentView(View view)
+            setView = inflate.inflate(R.layout.windowstub_addlayout, null);
+            mWindow.setContentView(setView);
+            view = (TextView) mWindow.findViewById(R.id.listview_addwindow);
+            assertNotNull(view);
+            assertEquals(R.id.listview_addwindow, view.getId());
 
-                // Test setContentView(View view, ViewGroup.LayoutParams params)
-                setView = inflate.inflate(R.layout.windowstub_layout, null);
-                mWindow.setContentView(setView, lp);
-                assertEquals(VIEWGROUP_LAYOUT_WIDTH, setView.getLayoutParams().width);
-                assertEquals(VIEWGROUP_LAYOUT_HEIGHT, setView.getLayoutParams().height);
-                view = (TextView) mWindow.findViewById(R.id.listview_window);
-                assertNotNull(view);
-                assertEquals(R.id.listview_window, view.getId());
-            }
+            // Test setContentView(View view, ViewGroup.LayoutParams params)
+            setView = inflate.inflate(R.layout.windowstub_layout, null);
+            mWindow.setContentView(setView, lp);
+            assertEquals(VIEWGROUP_LAYOUT_WIDTH, setView.getLayoutParams().width);
+            assertEquals(VIEWGROUP_LAYOUT_HEIGHT, setView.getLayoutParams().height);
+            view = (TextView) mWindow.findViewById(R.id.listview_window);
+            assertNotNull(view);
+            assertEquals(R.id.listview_window, view.getId());
         });
         mInstrumentation.waitForIdleSync();
     }
 
-    /**
-     * setFeatureDrawable: Set an explicit Drawable value for feature of this window.
-     * setFeatureDrawableAlpha: Set a custom alpha value for the given drawale feature,
-     *    controlling how much the background is visible through it.
-     * setFeatureDrawableResource: Set the value for a drawable feature of this window, from
-     *    a resource identifier.
-     * setFeatureDrawableUri: Set the value for a drawable feature of this window, from a URI.
-     * setFeatureInt: Set the integer value for a feature.  The range of the value depends on
-     *    the feature being set.  For FEATURE_PROGRESSS, it should go from 0 to
-     *    10000. At 10000 the progress is complete and the indicator hidden
-     *
-     * the set views exist, and no getter way to check.
-     */
-    public void testSetFeature() throws Throwable {
-    }
-
+    @Test
     public void testSetTitle() throws Throwable {
         final String title = "Android Window Test";
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mWindow.setTitle(title);
-                mWindow.setTitleColor(Color.BLUE);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mWindow.setTitle(title);
+            mWindow.setTitleColor(Color.BLUE);
         });
         mInstrumentation.waitForIdleSync();
         // No way to get title and title color
     }
 
     /**
-     * These 3 methods: Used by custom windows, such as Dialog, to pass the key press event
-     * further down the view hierarchy. Application developers should not need to implement or
-     * call this.
-     */
-    public void testSuperDispatchEvent() throws Exception {
-    }
-
-    /**
      * takeKeyEvents: Request that key events come to this activity. Use this if your activity
      * has no views with focus, but the activity still wants a chance to process key events.
      */
+    @Test
     public void testTakeKeyEvents() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                View v = mWindow.findViewById(R.id.listview_window);
-                v.clearFocus();
-                assertNull(mWindow.getCurrentFocus());
-                mWindow.takeKeyEvents(false);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            View v = mWindow.findViewById(R.id.listview_window);
+            v.clearFocus();
+            assertNull(mWindow.getCurrentFocus());
+            mWindow.takeKeyEvents(false);
         });
         mInstrumentation.waitForIdleSync();
-        // sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        // assertFalse(mActivity.isOnKeyDownCalled());
-    }
-
-    /**
-     * onConfigurationChanged: Should be called when the configuration is changed.
-     */
-    public void testOnConfigurationChanged() throws Exception {
-    }
-
-    /**
-     * requestFeature: Enable extended screen features.
-     */
-    public void testRequestFeature() throws Exception {
     }
 
     /**
@@ -535,46 +500,43 @@
      *                          PixelFormat.UNKNOWN to allow the Window to select
      *                          the format.
      */
-    public void testSetDefaultWindowFormat() throws Exception {
-        MockWindowCallback callback;
-        MockWindow window = new MockWindow(mContext);
+    @Test
+    public void testSetDefaultWindowFormat() {
+        MockWindow window = new MockWindow(mActivity);
 
         // mHaveWindowFormat will be true after set PixelFormat.OPAQUE and
         // setDefaultWindowFormat is invalid
         window.setFormat(PixelFormat.OPAQUE);
-        callback = new MockWindowCallback();
-        window.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        window.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         window.setDefaultWindowFormat(PixelFormat.JPEG);
         assertEquals(PixelFormat.OPAQUE, window.getAttributes().format);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
 
         // mHaveWindowFormat will be false after set PixelFormat.UNKNOWN and
         // setDefaultWindowFormat is valid
         window.setFormat(PixelFormat.UNKNOWN);
-        callback = new MockWindowCallback();
-        window.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        reset(mWindowCallback);
         window.setDefaultWindowFormat(PixelFormat.JPEG);
         assertEquals(PixelFormat.JPEG, window.getAttributes().format);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(window.getAttributes());
     }
 
     /**
      * Set the gravity of the window
      */
-    public void testSetGravity() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testSetGravity() {
+        mWindow = new MockWindow(mActivity);
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         assertEquals(0, attrs.gravity);
 
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         mWindow.setGravity(Gravity.TOP);
         attrs = mWindow.getAttributes();
         assertEquals(Gravity.TOP, attrs.gravity);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attrs);
     }
 
     /**
@@ -582,38 +544,38 @@
      *    1.The default for both of these is MATCH_PARENT;
      *    2.You can change them to WRAP_CONTENT to make a window that is not full-screen.
      */
-    public void testSetLayout() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testSetLayout() {
+        mWindow = new MockWindow(mActivity);
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attrs.width);
         assertEquals(WindowManager.LayoutParams.MATCH_PARENT, attrs.height);
 
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         mWindow.setLayout(WindowManager.LayoutParams.WRAP_CONTENT,
                 WindowManager.LayoutParams.WRAP_CONTENT);
         attrs = mWindow.getAttributes();
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, attrs.width);
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, attrs.height);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attrs);
     }
 
     /**
      * Set the type of the window, as per the WindowManager.LayoutParams types.
      */
-    public void testSetType() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testSetType() {
+        mWindow = new MockWindow(mActivity);
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION, attrs.type);
 
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         mWindow.setType(WindowManager.LayoutParams.TYPE_BASE_APPLICATION);
         attrs = mWindow.getAttributes();
-        assertEquals(WindowManager.LayoutParams.TYPE_BASE_APPLICATION, mWindow.getAttributes().type);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
+        assertEquals(WindowManager.LayoutParams.TYPE_BASE_APPLICATION, attrs.type);
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attrs);
     }
 
     /**
@@ -622,8 +584,9 @@
      *    1.Providing "unspecified" here will NOT override the input mode the window.
      *    2.Providing "unspecified" here will override the input mode the window.
      */
-    public void testSetSoftInputMode() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testSetSoftInputMode() {
+        mWindow = new MockWindow(mActivity);
         assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED,
                 mWindow.getAttributes().softInputMode);
         mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@@ -641,35 +604,28 @@
      *    it because the getter is in WindowManagerService and is private)
      *    2.Providing 0 here will override the animations the window.
      */
-    public void testSetWindowAnimations() throws Exception {
-        mWindow = new MockWindow(mContext);
+    @Test
+    public void testSetWindowAnimations() {
+        mWindow = new MockWindow(mActivity);
 
-        MockWindowCallback callback = new MockWindowCallback();
-        mWindow.setCallback(callback);
-        assertFalse(callback.isOnWindowAttributesChangedCalled());
+        mWindow.setCallback(mWindowCallback);
+        verify(mWindowCallback, never()).onWindowAttributesChanged(any());
         mWindow.setWindowAnimations(R.anim.alpha);
         WindowManager.LayoutParams attrs = mWindow.getAttributes();
         assertEquals(R.anim.alpha, attrs.windowAnimations);
-        assertTrue(callback.isOnWindowAttributesChangedCalled());
-    }
-
-    public void testFinalMethod() throws Exception {
-        // No way to test protected final method
+        verify(mWindowCallback, times(1)).onWindowAttributesChanged(attrs);
     }
 
     /**
      * Test setLocalFocus together with injectInputEvent.
      */
+    @Test
     public void testSetLocalFocus() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                surfaceView = new SurfaceView(mContext);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mSurfaceView = new SurfaceView(mActivity));
         mInstrumentation.waitForIdleSync();
 
         final Semaphore waitingSemaphore = new Semaphore(0);
-        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+        mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
             @Override
             public void surfaceCreated(SurfaceHolder holder) {
             }
@@ -685,32 +641,21 @@
             public void surfaceDestroyed(SurfaceHolder holder) {
                 destroyPresentation();
             }
-          });
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mWindow.setContentView(surfaceView);
-            }
         });
+        mActivityRule.runOnUiThread(() -> mWindow.setContentView(mSurfaceView));
         mInstrumentation.waitForIdleSync();
         assertTrue(waitingSemaphore.tryAcquire(5, TimeUnit.SECONDS));
         assertNotNull(mVirtualDisplay);
         assertNotNull(mPresentation);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return (mPresentation.button1 != null) && (mPresentation.button2 != null) &&
-                        (mPresentation.button3 != null) && mPresentation.ready;
-            }
-        }.run();
+
+        PollingCheck.waitFor(() -> (mPresentation.button1 != null)
+                && (mPresentation.button2 != null) && (mPresentation.button3 != null)
+                && mPresentation.ready);
         assertTrue(mPresentation.button1.isFocusable() && mPresentation.button2.isFocusable() &&
                 mPresentation.button3.isFocusable());
         // currently it is only for debugging
-        View.OnFocusChangeListener listener = new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
+        View.OnFocusChangeListener listener = (View v, boolean hasFocus) ->
                 Log.d(TAG, "view " + v + " focus " + hasFocus);
-            }
-        };
 
         // check key event focus
         mPresentation.button1.setOnFocusChangeListener(listener);
@@ -718,12 +663,7 @@
         mPresentation.button3.setOnFocusChangeListener(listener);
         final Window presentationWindow = mPresentation.getWindow();
         presentationWindow.setLocalFocus(true, false);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mPresentation.button1.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> mPresentation.button1.hasWindowFocus());
         checkPresentationButtonFocus(true, false, false);
         assertFalse(mPresentation.button1.isInTouchMode());
         injectKeyEvent(presentationWindow, KeyEvent.KEYCODE_TAB);
@@ -733,19 +673,11 @@
 
         // check touch input injection
         presentationWindow.setLocalFocus(true, true);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mPresentation.button1.isInTouchMode();
-            }
-        }.run();
-        View.OnClickListener clickListener = new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                Log.d(TAG, "onClick " + v);
-                if (v == mPresentation.button1) {
-                    waitingSemaphore.release();
-                }
+        PollingCheck.waitFor(() -> mPresentation.button1.isInTouchMode());
+        View.OnClickListener clickListener = (View v) -> {
+            Log.d(TAG, "onClick " + v);
+            if (v == mPresentation.button1) {
+                waitingSemaphore.release();
             }
         };
         mPresentation.button1.setOnClickListener(clickListener);
@@ -761,14 +693,9 @@
 
     private void checkPresentationButtonFocus(final boolean button1Focused,
             final boolean button2Focused, final boolean button3Focused) {
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return (mPresentation.button1.isFocused() == button1Focused) &&
+        PollingCheck.waitFor(() -> (mPresentation.button1.isFocused() == button1Focused) &&
                         (mPresentation.button2.isFocused() == button2Focused) &&
-                        (mPresentation.button3.isFocused() == button3Focused);
-            }
-        }.run();
+                        (mPresentation.button3.isFocused() == button3Focused));
     }
 
     private void injectKeyEvent(Window window, int keyCode) {
@@ -794,13 +721,11 @@
 
     private void createPresentation(final Surface surface, final int width,
             final int height) {
-        Context context = getInstrumentation().getTargetContext();
         DisplayManager displayManager =
-                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+                (DisplayManager) mActivity.getSystemService(Context.DISPLAY_SERVICE);
         mVirtualDisplay = displayManager.createVirtualDisplay("localFocusTest",
                 width, height, 300, surface, 0);
-        mPresentation = new ProjectedPresentation(
-                context, mVirtualDisplay.getDisplay());
+        mPresentation = new ProjectedPresentation(mActivity, mVirtualDisplay.getDisplay());
         mPresentation.show();
     }
 
@@ -837,13 +762,7 @@
         @Override
         public void show() {
             super.show();
-            new Handler().post(new Runnable() {
-
-                @Override
-                public void run() {
-                    ready = true;
-                }
-            });
+            new Handler().post(() -> ready = true);
         }
     }
 
@@ -1053,107 +972,4 @@
         public void reportActivityRelaunched() {
         }
     }
-
-    private class MockWindowCallback implements Window.Callback {
-        private boolean mIsOnWindowAttributesChangedCalled;
-        private boolean mIsOnPanelClosedCalled;
-
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            return true;
-        }
-
-        public boolean dispatchKeyShortcutEvent(KeyEvent event) {
-            return false;
-        }
-
-        public boolean dispatchTouchEvent(MotionEvent event) {
-            return true;
-        }
-
-        public boolean dispatchTrackballEvent(MotionEvent event) {
-            return true;
-        }
-
-        public boolean dispatchGenericMotionEvent(MotionEvent event) {
-            return true;
-        }
-
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            return true;
-        }
-
-        public View onCreatePanelView(int featureId) {
-            return null;
-        }
-
-        public boolean onCreatePanelMenu(int featureId, Menu menu) {
-            return false;
-        }
-
-        public boolean onPreparePanel(int featureId, View view, Menu menu) {
-            return false;
-        }
-
-        public boolean onMenuOpened(int featureId, Menu menu) {
-            return false;
-        }
-
-        public boolean onMenuItemSelected(int featureId, MenuItem item) {
-            return true;
-        }
-
-        public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
-            mIsOnWindowAttributesChangedCalled = true;
-        }
-
-        public boolean isOnWindowAttributesChangedCalled() {
-            return mIsOnWindowAttributesChangedCalled;
-        }
-
-        public void onContentChanged() {
-        }
-
-        public void onWindowFocusChanged(boolean hasFocus) {
-        }
-
-        public void onDetachedFromWindow() {
-        }
-
-        public void onAttachedToWindow() {
-        }
-
-        public void onPanelClosed(int featureId, Menu menu) {
-            mIsOnPanelClosedCalled = true;
-        }
-
-        public boolean isOnPanelClosedCalled() {
-            return mIsOnPanelClosedCalled;
-        }
-
-        public boolean onSearchRequested(SearchEvent searchEvent) {
-            return onSearchRequested();
-        }
-
-        public boolean onSearchRequested() {
-            return false;
-        }
-
-        public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
-            return null;
-        }
-
-        public ActionMode onWindowStartingActionMode(
-                ActionMode.Callback callback, int type) {
-            return null;
-        }
-
-        public void onActionModeStarted(ActionMode mode) {
-        }
-
-        public void onActionModeFinished(ActionMode mode) {
-        }
-
-        public void onWindowDismissed() {
-        }
-    }
 }
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/AnimationTestCase.java b/tests/tests/view/src/android/view/cts/surfacevalidator/AnimationTestCase.java
index 6b455e2..74ee5ee 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/AnimationTestCase.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/AnimationTestCase.java
@@ -16,7 +16,6 @@
 package android.view.cts.surfacevalidator;
 
 import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
 import android.content.Context;
 import android.view.View;
 import android.widget.FrameLayout;
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 7d08fcd..237ab7c 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -15,6 +15,8 @@
  */
 package android.view.cts.surfacevalidator;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -29,23 +31,16 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.View;
-import android.widget.FrameLayout;
-
 import android.view.cts.R;
+import android.widget.FrameLayout;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.*;
 
 
 public class CapturedActivity extends Activity {
@@ -63,11 +58,8 @@
     private VirtualDisplay mVirtualDisplay;
 
     private SurfacePixelValidator mSurfacePixelValidator;
-    private final Object mLock = new Object();
 
     public static final long CAPTURE_DURATION_MS = 10000;
-    private static final int PERMISSION_DIALOG_WAIT_MS = 1000;
-    private static final int RETRY_COUNT = 2;
 
     private static final long START_CAPTURE_DELAY_MS = 4000;
     private static final long END_CAPTURE_DELAY_MS = START_CAPTURE_DELAY_MS + CAPTURE_DURATION_MS;
@@ -101,17 +93,6 @@
         mMediaPlayer.setLooping(true);
     }
 
-    public void dismissPermissionDialog() throws UiObjectNotFoundException {
-        // The permission dialog will be auto-opened by the activity - find it and accept
-        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        UiSelector acceptButtonSelector = new UiSelector().resourceId("android:id/button1");
-        UiObject acceptButton = uiDevice.findObject(acceptButtonSelector);
-            if (acceptButton.waitForExists(PERMISSION_DIALOG_WAIT_MS)) {
-            boolean success = acceptButton.click();
-            Log.d(TAG, "found permission dialog, click attempt success = " + success);
-        }
-    }
-
     /**
      * MediaPlayer pre-loaded with a video with no black pixels. Be kind, rewind.
      */
@@ -147,7 +128,7 @@
         mCountDownLatch.countDown();
     }
 
-    public TestResult runTest(AnimationTestCase animationTestCase) throws Throwable {
+    public TestResult runTest(AnimationTestCase animationTestCase) throws InterruptedException {
         TestResult testResult = new TestResult();
         if (mOnWatch) {
             /**
@@ -162,17 +143,8 @@
             return testResult;
         }
 
-        int count = 0;
-        // Sometimes system decides to rotate the permission activity to another orientation
-        // right after showing it. This results in: uiautomation thinks that accept button appears,
-        // we successfully click it in terms of uiautomation, but nothing happens,
-        // because permission activity is already recreated.
-        // Thus, we try to click that button multiple times.
-        do {
-            assertTrue("Can't get the permission", count <= RETRY_COUNT);
-            dismissPermissionDialog();
-            count++;
-        } while (!mCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue("Can't initialize mediaProjection",
+                mCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
 
         mHandler.post(() -> {
             Log.d(TAG, "Setting up test case");
@@ -214,18 +186,19 @@
             mVirtualDisplay = null;
         }, END_CAPTURE_DELAY_MS);
 
+        final CountDownLatch latch = new CountDownLatch(1);
         mHandler.postDelayed(() -> {
             Log.d(TAG, "Ending test case");
             animationTestCase.end();
-            synchronized (mLock) {
-                mSurfacePixelValidator.finish(testResult);
-                mLock.notify();
-            }
+            mSurfacePixelValidator.finish(testResult);
+            latch.countDown();
             mSurfacePixelValidator = null;
         }, END_DELAY_MS);
 
-        synchronized (mLock) {
-            mLock.wait(TIME_OUT_MS);
+        boolean latchResult = latch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS);
+        if (!latchResult) {
+            testResult.passFrames = 0;
+            testResult.failFrames = 1000;
         }
         Log.d(TAG, "Test finished, passFrames " + testResult.passFrames
                 + ", failFrames " + testResult.failFrames);
@@ -242,4 +215,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
index 5a30b77..3d9f66b 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
@@ -28,11 +28,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Surface;
-import android.view.cts.surfacevalidator.PixelChecker;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
 
 public class SurfacePixelValidator {
     private static final String TAG = "SurfacePixelValidator";
diff --git a/tests/tests/view/src/android/view/cts/util/DrawingUtils.java b/tests/tests/view/src/android/view/cts/util/DrawingUtils.java
index 3be7447..ce8a0f7 100644
--- a/tests/tests/view/src/android/view/cts/util/DrawingUtils.java
+++ b/tests/tests/view/src/android/view/cts/util/DrawingUtils.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.util.Pair;
 import android.view.View;
+
 import junit.framework.Assert;
 
 import java.util.List;
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/view/src/android/view/cts/util/XmlUtils.java b/tests/tests/view/src/android/view/cts/util/XmlUtils.java
index f1df4ff..77d53e6 100644
--- a/tests/tests/view/src/android/view/cts/util/XmlUtils.java
+++ b/tests/tests/view/src/android/view/cts/util/XmlUtils.java
@@ -16,10 +16,6 @@
 
 package android.view.cts.util;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.BitmapFactory;
@@ -28,6 +24,10 @@
 import android.util.Base64;
 import android.util.Xml;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
index ba239af..de1a202 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
@@ -16,13 +16,21 @@
 
 package android.view.inputmethod.cts;
 
+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.assertTrue;
+
 import android.app.Instrumentation;
 import android.content.ClipDescription;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.net.Uri;
 import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
+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.Editable;
 import android.text.Selection;
 import android.text.Spannable;
@@ -41,35 +49,37 @@
 import android.view.inputmethod.cts.util.InputConnectionTestUtils;
 import android.widget.EditText;
 
-public class BaseInputConnectionTest extends
-        ActivityInstrumentationTestCase2<InputMethodCtsActivity> {
+import com.android.compatibility.common.util.PollingCheck;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BaseInputConnectionTest {
+    private Instrumentation mInstrumentation;
     private InputMethodCtsActivity mActivity;
     private Window mWindow;
     private EditText mView;
     private BaseInputConnection mConnection;
-    private Instrumentation mInstrumentation;
 
-    public BaseInputConnectionTest() {
-        super("android.view.cts", InputMethodCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<InputMethodCtsActivity> mActivityRule =
+            new ActivityTestRule<>(InputMethodCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mWindow = mActivity.getWindow();
         mView = (EditText) mWindow.findViewById(R.id.entry);
         mConnection = new BaseInputConnection(mView, true);
     }
 
+    @Test
     public void testDefaultMethods() {
         // These methods are default to return fixed result.
 
@@ -93,6 +103,7 @@
         assertFalse(mConnection.performPrivateCommand(action, new Bundle()));
     }
 
+    @Test
     public void testOpComposingSpans() {
         Spannable text = new SpannableString("Test ComposingSpans");
         BaseInputConnection.setComposingSpans(text);
@@ -123,6 +134,7 @@
      *                          around the current selection position of the editable text.
      * setSelection: changes the selection position in the current editable text.
      */
+    @Test
     public void testOpTextMethods() throws Throwable {
         // return is an default Editable instance with empty source
         final Editable text = mConnection.getEditable();
@@ -148,22 +160,15 @@
         assertEquals(expected.toString(), mConnection.getTextAfterCursor(offLength,
                 BaseInputConnection.GET_TEXT_WITH_STYLES).toString());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mView.requestFocus());
-                assertTrue(mView.isFocused());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(mView.requestFocus());
+            assertTrue(mView.isFocused());
         });
 
         // dummy mode
         BaseInputConnection dummyConnection = new BaseInputConnection(mView, false);
         dummyConnection.commitText(inputText, inputText.length());
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return text2.toString().equals(mView.getText().toString());
-            }
-        }.run();
+        PollingCheck.waitFor(() -> text2.toString().equals(mView.getText().toString()));
         assertEquals(0, dummyConnection.getCursorCapsMode(TextUtils.CAP_MODE_WORDS));
 
         // Test deleteSurroundingText
@@ -185,6 +190,7 @@
      * setComposingText: The default implementation places the given text into the editable,
      *                  replacing any existing composing text
      */
+    @Test
     public void testFinishComposingText() throws Throwable {
         CharSequence str = "TestFinish";
         Editable inputText = Editable.Factory.getInstance().newEditable(str);
@@ -198,35 +204,27 @@
         assertTrue(BaseInputConnection.getComposingSpanStart(text) == -1);
         assertTrue(BaseInputConnection.getComposingSpanEnd(text) == -1);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mView.requestFocus());
-                assertTrue(mView.isFocused());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(mView.requestFocus());
+            assertTrue(mView.isFocused());
         });
 
         // dummy mode
         BaseInputConnection dummyConnection = new BaseInputConnection(mView, false);
         dummyConnection.setComposingText(str, str.length());
         dummyConnection.finishComposingText();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return text.toString().equals(mView.getText().toString());
-            }
-        }.run();
+        PollingCheck.waitFor(() -> text.toString().equals(mView.getText().toString()));
     }
 
     /**
      * Provides standard implementation for sending a key event to the window
      * attached to the input connection's view
      */
+    @Test
     public void testSendKeyEvent() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mView.requestFocus());
-                assertTrue(mView.isFocused());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertTrue(mView.requestFocus());
+            assertTrue(mView.isFocused());
         });
 
         // 12-key support
@@ -240,17 +238,13 @@
             mInstrumentation.sendStringSync("q");
             mInstrumentation.waitForIdleSync();
         }
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return "q".equals(mView.getText().toString());
-            }
-        }.run();
+        PollingCheck.waitFor(() -> "q".equals(mView.getText().toString()));
     }
 
     /**
      * Updates InputMethodManager with the current fullscreen mode.
      */
+    @Test
     public void testReportFullscreenMode() {
         InputMethodManager imManager = (InputMethodManager) mInstrumentation.getTargetContext()
                 .getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -284,7 +278,7 @@
         };
     }
 
-    private void testDeleteSurroundingTextMain(final String initialState,
+    private void verifyDeleteSurroundingTextMain(final String initialState,
             final int deleteBefore, final int deleteAfter, final String expectedState) {
         final CharSequence source = InputConnectionTestUtils.formatString(initialState);
         final BaseInputConnection ic = createDummyConnectionWithSelection(mView, source);
@@ -321,47 +315,48 @@
     /**
      * Tests {@link BaseInputConnection#deleteSurroundingText(int, int)} comprehensively.
      */
+    @Test
     public void testDeleteSurroundingText() throws Throwable {
-        testDeleteSurroundingTextMain("012[]3456789", 0, 0, "012[]3456789");
-        testDeleteSurroundingTextMain("012[]3456789", -1, -1, "012[]3456789");
-        testDeleteSurroundingTextMain("012[]3456789", 1, 2, "01[]56789");
-        testDeleteSurroundingTextMain("012[]3456789", 10, 1, "[]456789");
-        testDeleteSurroundingTextMain("012[]3456789", 1, 10, "01[]");
-        testDeleteSurroundingTextMain("[]0123456789", 3, 3, "[]3456789");
-        testDeleteSurroundingTextMain("0123456789[]", 3, 3, "0123456[]");
-        testDeleteSurroundingTextMain("012[345]6789", 0, 0, "012[345]6789");
-        testDeleteSurroundingTextMain("012[345]6789", -1, -1, "012[345]6789");
-        testDeleteSurroundingTextMain("012[345]6789", 1, 2, "01[345]89");
-        testDeleteSurroundingTextMain("012[345]6789", 10, 1, "[345]789");
-        testDeleteSurroundingTextMain("012[345]6789", 1, 10, "01[345]");
-        testDeleteSurroundingTextMain("[012]3456789", 3, 3, "[012]6789");
-        testDeleteSurroundingTextMain("0123456[789]", 3, 3, "0123[789]");
-        testDeleteSurroundingTextMain("[0123456789]", 0, 0, "[0123456789]");
-        testDeleteSurroundingTextMain("[0123456789]", 1, 1, "[0123456789]");
+        verifyDeleteSurroundingTextMain("012[]3456789", 0, 0, "012[]3456789");
+        verifyDeleteSurroundingTextMain("012[]3456789", -1, -1, "012[]3456789");
+        verifyDeleteSurroundingTextMain("012[]3456789", 1, 2, "01[]56789");
+        verifyDeleteSurroundingTextMain("012[]3456789", 10, 1, "[]456789");
+        verifyDeleteSurroundingTextMain("012[]3456789", 1, 10, "01[]");
+        verifyDeleteSurroundingTextMain("[]0123456789", 3, 3, "[]3456789");
+        verifyDeleteSurroundingTextMain("0123456789[]", 3, 3, "0123456[]");
+        verifyDeleteSurroundingTextMain("012[345]6789", 0, 0, "012[345]6789");
+        verifyDeleteSurroundingTextMain("012[345]6789", -1, -1, "012[345]6789");
+        verifyDeleteSurroundingTextMain("012[345]6789", 1, 2, "01[345]89");
+        verifyDeleteSurroundingTextMain("012[345]6789", 10, 1, "[345]789");
+        verifyDeleteSurroundingTextMain("012[345]6789", 1, 10, "01[345]");
+        verifyDeleteSurroundingTextMain("[012]3456789", 3, 3, "[012]6789");
+        verifyDeleteSurroundingTextMain("0123456[789]", 3, 3, "0123[789]");
+        verifyDeleteSurroundingTextMain("[0123456789]", 0, 0, "[0123456789]");
+        verifyDeleteSurroundingTextMain("[0123456789]", 1, 1, "[0123456789]");
 
         // Surrogate characters do not have any special meanings.  Validating the character sequence
         // is beyond the goal of this API.
-        testDeleteSurroundingTextMain("0<>[]3456789", 1, 0, "0<[]3456789");
-        testDeleteSurroundingTextMain("0<>[]3456789", 2, 0, "0[]3456789");
-        testDeleteSurroundingTextMain("0<>[]3456789", 3, 0, "[]3456789");
-        testDeleteSurroundingTextMain("012[]<>56789", 0, 1, "012[]>56789");
-        testDeleteSurroundingTextMain("012[]<>56789", 0, 2, "012[]56789");
-        testDeleteSurroundingTextMain("012[]<>56789", 0, 3, "012[]6789");
-        testDeleteSurroundingTextMain("0<<[]3456789", 1, 0, "0<[]3456789");
-        testDeleteSurroundingTextMain("0<<[]3456789", 2, 0, "0[]3456789");
-        testDeleteSurroundingTextMain("0<<[]3456789", 3, 0, "[]3456789");
-        testDeleteSurroundingTextMain("012[]<<56789", 0, 1, "012[]<56789");
-        testDeleteSurroundingTextMain("012[]<<56789", 0, 2, "012[]56789");
-        testDeleteSurroundingTextMain("012[]<<56789", 0, 3, "012[]6789");
-        testDeleteSurroundingTextMain("0>>[]3456789", 1, 0, "0>[]3456789");
-        testDeleteSurroundingTextMain("0>>[]3456789", 2, 0, "0[]3456789");
-        testDeleteSurroundingTextMain("0>>[]3456789", 3, 0, "[]3456789");
-        testDeleteSurroundingTextMain("012[]>>56789", 0, 1, "012[]>56789");
-        testDeleteSurroundingTextMain("012[]>>56789", 0, 2, "012[]56789");
-        testDeleteSurroundingTextMain("012[]>>56789", 0, 3, "012[]6789");
+        verifyDeleteSurroundingTextMain("0<>[]3456789", 1, 0, "0<[]3456789");
+        verifyDeleteSurroundingTextMain("0<>[]3456789", 2, 0, "0[]3456789");
+        verifyDeleteSurroundingTextMain("0<>[]3456789", 3, 0, "[]3456789");
+        verifyDeleteSurroundingTextMain("012[]<>56789", 0, 1, "012[]>56789");
+        verifyDeleteSurroundingTextMain("012[]<>56789", 0, 2, "012[]56789");
+        verifyDeleteSurroundingTextMain("012[]<>56789", 0, 3, "012[]6789");
+        verifyDeleteSurroundingTextMain("0<<[]3456789", 1, 0, "0<[]3456789");
+        verifyDeleteSurroundingTextMain("0<<[]3456789", 2, 0, "0[]3456789");
+        verifyDeleteSurroundingTextMain("0<<[]3456789", 3, 0, "[]3456789");
+        verifyDeleteSurroundingTextMain("012[]<<56789", 0, 1, "012[]<56789");
+        verifyDeleteSurroundingTextMain("012[]<<56789", 0, 2, "012[]56789");
+        verifyDeleteSurroundingTextMain("012[]<<56789", 0, 3, "012[]6789");
+        verifyDeleteSurroundingTextMain("0>>[]3456789", 1, 0, "0>[]3456789");
+        verifyDeleteSurroundingTextMain("0>>[]3456789", 2, 0, "0[]3456789");
+        verifyDeleteSurroundingTextMain("0>>[]3456789", 3, 0, "[]3456789");
+        verifyDeleteSurroundingTextMain("012[]>>56789", 0, 1, "012[]>56789");
+        verifyDeleteSurroundingTextMain("012[]>>56789", 0, 2, "012[]56789");
+        verifyDeleteSurroundingTextMain("012[]>>56789", 0, 3, "012[]6789");
     }
 
-    private void testDeleteSurroundingTextInCodePointsMain(final String initialState,
+    private void verifyDeleteSurroundingTextInCodePointsMain(final String initialState,
             final int deleteBeforeInCodePoints, final int deleteAfterInCodePoints,
             final String expectedState) {
         final CharSequence source = InputConnectionTestUtils.formatString(initialState);
@@ -401,96 +396,98 @@
      * Tests {@link BaseInputConnection#deleteSurroundingTextInCodePoints(int, int)}
      * comprehensively.
      */
+    @Test
     public void testDeleteSurroundingTextInCodePoints() throws Throwable {
-        testDeleteSurroundingTextInCodePointsMain("012[]3456789", 0, 0, "012[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]3456789", -1, -1, "012[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 2, "01[]56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]3456789", 10, 1, "[]456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 10, "01[]");
-        testDeleteSurroundingTextInCodePointsMain("[]0123456789", 3, 3, "[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0123456789[]", 3, 3, "0123456[]");
-        testDeleteSurroundingTextInCodePointsMain("012[345]6789", 0, 0, "012[345]6789");
-        testDeleteSurroundingTextInCodePointsMain("012[345]6789", -1, -1, "012[345]6789");
-        testDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 2, "01[345]89");
-        testDeleteSurroundingTextInCodePointsMain("012[345]6789", 10, 1, "[345]789");
-        testDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 10, "01[345]");
-        testDeleteSurroundingTextInCodePointsMain("[012]3456789", 3, 3, "[012]6789");
-        testDeleteSurroundingTextInCodePointsMain("0123456[789]", 3, 3, "0123[789]");
-        testDeleteSurroundingTextInCodePointsMain("[0123456789]", 0, 0, "[0123456789]");
-        testDeleteSurroundingTextInCodePointsMain("[0123456789]", 1, 1, "[0123456789]");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 0, 0, "012[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", -1, -1, "012[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 2, "01[]56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 10, 1, "[]456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]3456789", 1, 10, "01[]");
+        verifyDeleteSurroundingTextInCodePointsMain("[]0123456789", 3, 3, "[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0123456789[]", 3, 3, "0123456[]");
+        verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 0, 0, "012[345]6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", -1, -1, "012[345]6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 2, "01[345]89");
+        verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 10, 1, "[345]789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[345]6789", 1, 10, "01[345]");
+        verifyDeleteSurroundingTextInCodePointsMain("[012]3456789", 3, 3, "[012]6789");
+        verifyDeleteSurroundingTextInCodePointsMain("0123456[789]", 3, 3, "0123[789]");
+        verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 0, 0, "[0123456789]");
+        verifyDeleteSurroundingTextInCodePointsMain("[0123456789]", 1, 1, "[0123456789]");
 
-        testDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 1, 0, "0[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 2, 0, "[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 3, 0, "[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 1, "012[]56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 2, "012[]6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 3, "012[]789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 1, 0, "0[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 2, 0, "[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<>[]3456789", 3, 0, "[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 1, "012[]56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 2, "012[]6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>56789", 0, 3, "012[]789");
 
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 0, "[]<><><><><>");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1, "[]<><><><>");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 2, "[]<><><>");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 3, "[]<><>");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 4, "[]<>");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 5, "[]");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 6, "[]");
-        testDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1000, "[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 0, 0, "<><><><><>[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1, 0, "<><><><>[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 2, 0, "<><><>[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 3, 0, "<><>[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 4, 0, "<>[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 5, 0, "[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 6, 0, "[]");
-        testDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1000, 0, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 0, "[]<><><><><>");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1, "[]<><><><>");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 2, "[]<><><>");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 3, "[]<><>");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 4, "[]<>");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 5, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 6, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("[]<><><><><>", 0, 1000, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 0, 0, "<><><><><>[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1, 0, "<><><><>[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 2, 0, "<><><>[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 3, 0, "<><>[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 4, 0, "<>[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 5, 0, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 6, 0, "[]");
+        verifyDeleteSurroundingTextInCodePointsMain("<><><><><>[]", 1000, 0, "[]");
 
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 0, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 0, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 0, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 1, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 2, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 3, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 0, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 0, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 0, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 1, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 2, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 3, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 0, "01<[]>456789");
-        testDeleteSurroundingTextInCodePointsMain("01<[]>456789", 0, 1, "01<[]>456789");
-        testDeleteSurroundingTextInCodePointsMain("<12[]3456789", 1, 0, "<1[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("<12[]3456789", 2, 0, "<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("<12[]3456789", 3, 0, "<12[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 1, 0, "<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 2, 0, "<<>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 3, 0, "<<>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 1, "012[]4>6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 2, "012[]>6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 3, "012[]34>6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 1, "012[]>6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 2, "012[]<>>6789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 3, "012[]<>>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 0, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 0, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 0, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 1, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 2, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 0, 3, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 0, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 0, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 0, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 1, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 2, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 0, 3, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 0, "01<[]>456789");
+        verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 0, 1, "01<[]>456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 1, 0, "<1[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 2, 0, "<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<12[]3456789", 3, 0, "<12[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 1, 0, "<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 2, 0, "<<>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("<<>[]3456789", 3, 0, "<<>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 1, "012[]4>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 2, "012[]>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]34>6789", 0, 3, "012[]34>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 1, "012[]>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 2, "012[]<>>6789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<>>6789", 0, 3, "012[]<>>6789");
 
         // Atomicity test.
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 1, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 1, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 1, "0<<[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 1, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 2, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 3, "012[]<<56789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 1, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 1, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 1, "0>>[]3456789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 1, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 2, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 3, "012[]>>56789");
-        testDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 1, "01<[]>456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 1, 1, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 2, 1, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0<<[]3456789", 3, 1, "0<<[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 1, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 2, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]<<56789", 1, 3, "012[]<<56789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 1, 1, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 2, 1, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("0>>[]3456789", 3, 1, "0>>[]3456789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 1, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 2, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("012[]>>56789", 1, 3, "012[]>>56789");
+        verifyDeleteSurroundingTextInCodePointsMain("01<[]>456789", 1, 1, "01<[]>456789");
 
         // Do not verify the character sequences in the selected region.
-        testDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 0, "0[><]456789");
-        testDeleteSurroundingTextInCodePointsMain("01[><]456789", 0, 1, "01[><]56789");
-        testDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 1, "0[><]56789");
+        verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 0, "0[><]456789");
+        verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 0, 1, "01[><]56789");
+        verifyDeleteSurroundingTextInCodePointsMain("01[><]456789", 1, 1, "0[><]56789");
     }
 
+    @Test
     public void testCloseConnection() {
         final CharSequence source = "0123456789";
         mConnection.commitText(source, source.length());
@@ -505,11 +502,13 @@
         assertEquals(-1, BaseInputConnection.getComposingSpanEnd(text));
     }
 
+    @Test
     public void testGetHandler() {
         // BaseInputConnection must not implement getHandler().
         assertNull(mConnection.getHandler());
     }
 
+    @Test
     public void testCommitContent() {
         final InputContentInfo inputContentInfo = new InputContentInfo(
                 Uri.parse("content://com.example/path"),
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/CompletionInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/CompletionInfoTest.java
index 9606a0e..9a8d206 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/CompletionInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/CompletionInfoTest.java
@@ -16,17 +16,26 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.CompletionInfo;
 
-public class CompletionInfoTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CompletionInfoTest {
     private static final int ID = 1;
     private static final int POSITION = 1;
     private static final String TEXT = "CompletionInfoText";
     private static final String LABEL = "CompletionInfoLabel";
 
+    @Test
     public void testCompletionInfo() {
         new CompletionInfo(ID, POSITION, TEXT);
         CompletionInfo info = new CompletionInfo(ID, POSITION, TEXT, LABEL);
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
index 0780460..1557511 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
@@ -16,19 +16,30 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 import android.text.TextUtils;
 import android.util.Printer;
 import android.view.inputmethod.EditorInfo;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class EditorInfoTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EditorInfoTest {
+    @Test
     public void testEditorInfo() {
         EditorInfo info = new EditorInfo();
 
@@ -77,12 +88,13 @@
         assertEquals(info.hintLocales, targetInfo.hintLocales);
         MoreAsserts.assertEquals(info.contentMimeTypes, targetInfo.contentMimeTypes);
 
-        TestPrinter printer = new TestPrinter();
+        Printer printer = mock(Printer.class);
         String prefix = "TestEditorInfo";
         info.dump(printer, prefix);
-        assertTrue(printer.isPrintlnCalled);
+        verify(printer, atLeastOnce()).println(anyString());
     }
 
+    @Test
     public void testNullHintLocals() {
         EditorInfo info = new EditorInfo();
         info.hintLocales = null;
@@ -93,11 +105,4 @@
         p.recycle();
         assertNull(targetInfo.hintLocales);
     }
-
-    private class TestPrinter implements Printer {
-        public boolean isPrintlnCalled;
-        public void println(String x) {
-            isPrintlnCalled = true;
-        }
-    }
 }
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextRequestTest.java b/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextRequestTest.java
index c3aa588..3e12579 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextRequestTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextRequestTest.java
@@ -16,13 +16,20 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.ExtractedTextRequest;
 
-public class ExtractedTextRequestTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExtractedTextRequestTest {
+    @Test
     public void testExtractedTextRequest() {
         ExtractedTextRequest request = new ExtractedTextRequest();
         request.flags = 1;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextTest.java b/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextTest.java
index 3dccee6..1a1d834 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/ExtractedTextTest.java
@@ -15,15 +15,21 @@
  */
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.ExtractedText;
 
-public class ExtractedTextTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExtractedTextTest {
+    @Test
     public void testWriteToParcel() {
-
         ExtractedText extractedText = new ExtractedText();
         extractedText.flags = 1;
         extractedText.selectionEnd = 11;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputBindingTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputBindingTest.java
index 0957a94..faaff3d 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputBindingTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputBindingTest.java
@@ -16,18 +16,28 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 
 import android.os.Binder;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.InputBinding;
 
-public class InputBindingTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputBindingTest {
+    @Test
     public void testInputBinding() {
-        View view = new View(getContext());
+        View view = new View(InstrumentationRegistry.getTargetContext());
         BaseInputConnection bic = new BaseInputConnection(view, false);
         Binder binder = new Binder();
         int uid = 1;
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
index 8bcb611..e91ed5a 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
@@ -16,27 +16,47 @@
 
 package android.view.inputmethod.cts;
 
+import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+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 android.content.ClipDescription;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.view.KeyEvent;
 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.InputConnectionWrapper;
 import android.view.inputmethod.InputContentInfo;
 
-public class InputConnectionWrapperTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputConnectionWrapperTest {
+    @Test
     public void testInputConnectionWrapper() {
-        MockInputConnection inputConnection = new MockInputConnection();
+        InputConnection inputConnection = mock(InputConnection.class);
+        doReturn(true).when(inputConnection).commitContent(any(InputContentInfo.class),
+                anyInt(), any(Bundle.class));
         InputConnectionWrapper wrapper = new InputConnectionWrapper(null, true);
         try {
             wrapper.beginBatchEdit();
@@ -47,220 +67,103 @@
         wrapper.setTarget(inputConnection);
 
         wrapper.beginBatchEdit();
-        assertTrue(inputConnection.isBeginBatchEditCalled);
+        verify(inputConnection, times(1)).beginBatchEdit();
+
         wrapper.clearMetaKeyStates(KeyEvent.META_ALT_ON);
-        assertTrue(inputConnection.isClearMetaKeyStatesCalled);
+        verify(inputConnection, times(1)).clearMetaKeyStates(KeyEvent.META_ALT_ON);
+
         wrapper.commitCompletion(new CompletionInfo(1, 1, "testText"));
-        assertTrue(inputConnection.isCommitCompletionCalled);
+        ArgumentCaptor<CompletionInfo> completionInfoCaptor =
+                ArgumentCaptor.forClass(CompletionInfo.class);
+        verify(inputConnection, times(1)).commitCompletion(completionInfoCaptor.capture());
+        assertEquals(1, completionInfoCaptor.getValue().getId());
+        assertEquals(1, completionInfoCaptor.getValue().getPosition());
+        assertEquals("testText", completionInfoCaptor.getValue().getText());
+
         wrapper.commitCorrection(new CorrectionInfo(0, "oldText", "newText"));
-        assertTrue(inputConnection.isCommitCorrectionCalled);
+        ArgumentCaptor<CorrectionInfo> correctionInfoCaptor =
+                ArgumentCaptor.forClass(CorrectionInfo.class);
+        verify(inputConnection, times(1)).commitCorrection(correctionInfoCaptor.capture());
+        assertEquals(0, correctionInfoCaptor.getValue().getOffset());
+        assertEquals("oldText", correctionInfoCaptor.getValue().getOldText());
+        assertEquals("newText", correctionInfoCaptor.getValue().getNewText());
+
         wrapper.commitText("Text", 1);
-        assertTrue(inputConnection.isCommitTextCalled);
+        verify(inputConnection, times(1)).commitText(sameCharSequence("Text"), eq(1));
+
         wrapper.deleteSurroundingText(10, 100);
-        assertTrue(inputConnection.isDeleteSurroundingTextCalled);
+        verify(inputConnection, times(1)).deleteSurroundingText(10, 100);
+
         wrapper.deleteSurroundingTextInCodePoints(10, 100);
-        assertTrue(inputConnection.isDeleteSurroundingTextInCodePointsCalled);
+        verify(inputConnection, times(1)).deleteSurroundingTextInCodePoints(10, 100);
+
         wrapper.endBatchEdit();
-        assertTrue(inputConnection.isEndBatchEditCalled);
+        verify(inputConnection, times(1)).endBatchEdit();
+
         wrapper.finishComposingText();
-        assertTrue(inputConnection.isFinishComposingTextCalled);
+        verify(inputConnection, times(1)).finishComposingText();
+
         wrapper.getCursorCapsMode(TextUtils.CAP_MODE_CHARACTERS);
-        assertTrue(inputConnection.isGetCursorCapsModeCalled);
+        verify(inputConnection, times(1)).getCursorCapsMode(TextUtils.CAP_MODE_CHARACTERS);
+
         wrapper.getExtractedText(new ExtractedTextRequest(), 0);
-        assertTrue(inputConnection.isGetExtractedTextCalled);
+        verify(inputConnection, times(1)).getExtractedText(any(ExtractedTextRequest.class), eq(0));
+
         wrapper.getTextAfterCursor(5, 0);
-        assertTrue(inputConnection.isGetTextAfterCursorCalled);
+        verify(inputConnection, times(1)).getTextAfterCursor(5, 0);
+
         wrapper.getTextBeforeCursor(3, 0);
-        assertTrue(inputConnection.isGetTextBeforeCursorCalled);
+        verify(inputConnection, times(1)).getTextBeforeCursor(3, 0);
+
         wrapper.performContextMenuAction(1);
-        assertTrue(inputConnection.isPerformContextMenuActionCalled);
+        verify(inputConnection, times(1)).performContextMenuAction(1);
+
         wrapper.performEditorAction(EditorInfo.IME_ACTION_GO);
-        assertTrue(inputConnection.isPerformEditorActionCalled);
+        verify(inputConnection, times(1)).performEditorAction(EditorInfo.IME_ACTION_GO);
+
         wrapper.performPrivateCommand("com.android.action.MAIN", new Bundle());
-        assertTrue(inputConnection.isPerformPrivateCommandCalled);
+        verify(inputConnection, times(1)).performPrivateCommand(eq("com.android.action.MAIN"),
+                any(Bundle.class));
+
         wrapper.reportFullscreenMode(true);
-        assertTrue(inputConnection.isReportFullscreenModeCalled);
+        verify(inputConnection, times(1)).reportFullscreenMode(true);
+
         wrapper.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0));
-        assertTrue(inputConnection.isSendKeyEventCalled);
+        ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class);
+        verify(inputConnection, times(1)).sendKeyEvent(keyEventCaptor.capture());
+        assertEquals(KeyEvent.ACTION_DOWN, keyEventCaptor.getValue().getAction());
+        assertEquals(KeyEvent.KEYCODE_0, keyEventCaptor.getValue().getKeyCode());
+
         wrapper.setComposingText("Text", 1);
-        assertTrue(inputConnection.isSetComposingTextCalled);
+        verify(inputConnection, times(1)).setComposingText("Text", 1);
+
         wrapper.setSelection(0, 10);
-        assertTrue(inputConnection.isSetSelectionCalled);
+        verify(inputConnection, times(1)).setSelection(0, 10);
+
         wrapper.getSelectedText(0);
-        assertTrue(inputConnection.isGetSelectedTextCalled);
+        verify(inputConnection, times(1)).getSelectedText(0);
+
         wrapper.setComposingRegion(0, 3);
-        assertTrue(inputConnection.isSetComposingRegionCalled);
+        verify(inputConnection, times(1)).setComposingRegion(0, 3);
+
         wrapper.requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE);
-        assertTrue(inputConnection.isRequestCursorUpdatesCalled);
+        verify(inputConnection, times(1)).requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE);
+
         wrapper.closeConnection();
-        assertTrue(inputConnection.isCloseConnectionCalled);
-        assertFalse(inputConnection.isGetHandlerCalled);
+        verify(inputConnection, times(1)).closeConnection();
+
+        verify(inputConnection, never()).getHandler();
         assertNull(wrapper.getHandler());
-        assertTrue(inputConnection.isGetHandlerCalled);
-        assertFalse(inputConnection.isCommitContentCalled);
+        verify(inputConnection, times(1)).getHandler();
+
+        verify(inputConnection, never()).commitContent(any(InputContentInfo.class), anyInt(),
+            any(Bundle.class));
+
         final InputContentInfo inputContentInfo = new InputContentInfo(
                 Uri.parse("content://com.example/path"),
                 new ClipDescription("sample content", new String[]{"image/png"}),
                 Uri.parse("https://example.com"));
-        wrapper.commitContent(inputContentInfo, 0 /* flags */, null /* opts */);
-        assertTrue(inputConnection.isCommitContentCalled);
-    }
-
-    private class MockInputConnection implements InputConnection {
-        public boolean isBeginBatchEditCalled;
-        public boolean isClearMetaKeyStatesCalled;
-        public boolean isCommitCompletionCalled;
-        public boolean isCommitCorrectionCalled;
-        public boolean isCommitTextCalled;
-        public boolean isDeleteSurroundingTextCalled;
-        public boolean isDeleteSurroundingTextInCodePointsCalled;
-        public boolean isEndBatchEditCalled;
-        public boolean isFinishComposingTextCalled;
-        public boolean isGetCursorCapsModeCalled;
-        public boolean isGetExtractedTextCalled;
-        public boolean isGetTextAfterCursorCalled;
-        public boolean isGetTextBeforeCursorCalled;
-        public boolean isGetSelectedTextCalled;
-        public boolean isPerformContextMenuActionCalled;
-        public boolean isPerformEditorActionCalled;
-        public boolean isPerformPrivateCommandCalled;
-        public boolean isReportFullscreenModeCalled;
-        public boolean isSendKeyEventCalled;
-        public boolean isSetComposingTextCalled;
-        public boolean isSetComposingRegionCalled;
-        public boolean isSetSelectionCalled;
-        public boolean isRequestCursorUpdatesCalled;
-        public boolean isGetHandlerCalled;
-        public boolean isCloseConnectionCalled;
-        public boolean isCommitContentCalled;
-
-        public boolean beginBatchEdit() {
-            isBeginBatchEditCalled = true;
-            return false;
-        }
-
-        public boolean clearMetaKeyStates(int states) {
-            isClearMetaKeyStatesCalled = true;
-            return false;
-        }
-
-        public boolean commitCompletion(CompletionInfo text) {
-            isCommitCompletionCalled = true;
-            return false;
-        }
-
-        public boolean commitCorrection(CorrectionInfo info) {
-            isCommitCorrectionCalled = true;
-            return false;
-        }
-
-        public boolean commitText(CharSequence text, int newCursorPosition) {
-            isCommitTextCalled = true;
-            return false;
-        }
-
-        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
-            isDeleteSurroundingTextCalled = true;
-            return false;
-        }
-
-        public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
-            isDeleteSurroundingTextInCodePointsCalled = true;
-            return false;
-        }
-
-        public boolean endBatchEdit() {
-            isEndBatchEditCalled = true;
-            return false;
-        }
-
-        public boolean finishComposingText() {
-            isFinishComposingTextCalled = true;
-            return false;
-        }
-
-        public int getCursorCapsMode(int reqModes) {
-            isGetCursorCapsModeCalled = true;
-            return 0;
-        }
-
-        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
-            isGetExtractedTextCalled = true;
-            return null;
-        }
-
-        public CharSequence getTextAfterCursor(int n, int flags) {
-            isGetTextAfterCursorCalled = true;
-            return null;
-        }
-
-        public CharSequence getTextBeforeCursor(int n, int flags) {
-            isGetTextBeforeCursorCalled = true;
-            return null;
-        }
-
-        public CharSequence getSelectedText(int flags) {
-            isGetSelectedTextCalled = true;
-            return null;
-        }
-
-        public boolean performContextMenuAction(int id) {
-            isPerformContextMenuActionCalled = true;
-            return false;
-        }
-
-        public boolean performEditorAction(int editorAction) {
-            isPerformEditorActionCalled = true;
-            return false;
-        }
-
-        public boolean performPrivateCommand(String action, Bundle data) {
-            isPerformPrivateCommandCalled = true;
-            return false;
-        }
-
-        public boolean reportFullscreenMode(boolean enabled) {
-            isReportFullscreenModeCalled = true;
-            return false;
-        }
-
-        public boolean sendKeyEvent(KeyEvent event) {
-            isSendKeyEventCalled = true;
-            return false;
-        }
-
-        public boolean setComposingText(CharSequence text, int newCursorPosition) {
-            isSetComposingTextCalled = true;
-            return false;
-        }
-
-        public boolean setComposingRegion(int start, int end) {
-            isSetComposingRegionCalled = true;
-            return false;
-        }
-
-        public boolean setSelection(int start, int end) {
-            isSetSelectionCalled = true;
-            return false;
-        }
-
-        public boolean requestCursorUpdates(int cursorUpdateMode) {
-            isRequestCursorUpdatesCalled = true;
-            return false;
-        }
-
-        public Handler getHandler() {
-            isGetHandlerCalled = true;
-            return null;
-        }
-
-        public void closeConnection() {
-            isCloseConnectionCalled = true;
-        }
-
-        public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
-            isCommitContentCalled = true;
-            return true;
-        }
+        wrapper.commitContent(inputContentInfo, 0 /* flags */, null /* opt */);
+        verify(inputConnection, times(1)).commitContent(inputContentInfo, 0, null);
     }
 }
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputContentInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputContentInfoTest.java
index d8eb897..f7a328c 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputContentInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputContentInfoTest.java
@@ -16,18 +16,25 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import android.content.ClipDescription;
 import android.net.Uri;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputContentInfo;
 
-import java.lang.NullPointerException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.security.InvalidParameterException;
 
-public class InputContentInfoTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputContentInfoTest {
+    @Test
     public void testInputContentInfo() {
         InputContentInfo info = new InputContentInfo(
                  Uri.parse("content://com.example/path"),
@@ -57,6 +64,7 @@
         assertEquals(info.describeContents(), targetInfo.describeContents());
     }
 
+    @Test
     public void testOptionalConstructorParam() {
         InputContentInfo info = new InputContentInfo(
                 Uri.parse("content://com.example/path"),
@@ -70,97 +78,68 @@
         assertEquals(0, info.describeContents());
     }
 
-    public void testContentUri() {
-        try {
-            InputContentInfo info = new InputContentInfo(
-                    null, new ClipDescription("sample content", new String[]{"image/png"}),
-                    Uri.parse("https://example.com"));
-            fail("InputContentInfo must not accept a null content URI.");
-        } catch (NullPointerException e) {
-            // OK.
-        } catch (Exception e) {
-            fail("Unexpected exception=" + e);
-        }
-
-        try {
-            InputContentInfo info = new InputContentInfo(
-                    Uri.parse("https://example.com"),
-                    new ClipDescription("sample content", new String[]{"image/png"}),
-                    Uri.parse("https://example.com"));
-            fail("InputContentInfo must accept content URI only.");
-        } catch (InvalidParameterException e) {
-            // OK.
-        } catch (Exception e) {
-            fail("Unexpected exception=" + e);
-        }
+    @Test(expected=NullPointerException.class)
+    public void testContentUriNullContentUri() {
+        new InputContentInfo(
+                null, new ClipDescription("sample content", new String[]{"image/png"}),
+                Uri.parse("https://example.com"));
     }
 
-    public void testMimeType() {
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"), null,
-                     Uri.parse("https://example.com"));
-            fail("InputContentInfo must not accept a null description.");
-        } catch (NullPointerException e) {
-            // OK.
-        } catch (Exception e) {
-            fail("Unexpected exception=" + e);
-        }
+    @Test(expected=InvalidParameterException.class)
+    public void testContentUriInvalidContentUri() {
+        new InputContentInfo(
+                Uri.parse("https://example.com"),
+                new ClipDescription("sample content", new String[]{"image/png"}),
+                Uri.parse("https://example.com"));
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testMimeTypeNulLDescription() {
+        new InputContentInfo(
+                 Uri.parse("content://com.example/path"), null,
+                 Uri.parse("https://example.com"));
+    }
+
+    @Test
     public void testLinkUri() {
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"),
-                     new ClipDescription("sample content", new String[]{"image/png"}),
-                     null);
-        } catch (Exception e) {
-            fail("InputContentInfo must accept a null link Uri.");
-        }
+        // Test that we accept null link Uri
+        new InputContentInfo(
+                Uri.parse("content://com.example/path"),
+                new ClipDescription("sample content", new String[]{"image/png"}),
+                null);
 
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"),
-                     new ClipDescription("sample content", new String[]{"image/png"}),
-                     Uri.parse("http://example.com/path"));
-        } catch (Exception e) {
-            fail("InputContentInfo must accept http link Uri.");
-        }
+        // Test that we accept http link Uri
+        new InputContentInfo(
+                Uri.parse("content://com.example/path"),
+                new ClipDescription("sample content", new String[]{"image/png"}),
+                Uri.parse("http://example.com/path"));
 
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"),
-                     new ClipDescription("sample content", new String[]{"image/png"}),
-                     Uri.parse("https://example.com/path"));
-        } catch (Exception e) {
-            fail("InputContentInfo must accept https link Uri.");
-        }
-
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"),
-                     new ClipDescription("sample content", new String[]{"image/png"}),
-                     Uri.parse("ftp://example.com/path"));
-            fail("InputContentInfo must accept http and https link Uri only.");
-        } catch (InvalidParameterException e) {
-            // OK.
-        } catch (Exception e) {
-            fail("Unexpected exception=" + e);
-        }
-
-        try {
-            InputContentInfo info = new InputContentInfo(
-                     Uri.parse("content://com.example/path"),
-                     new ClipDescription("sample content", new String[]{"image/png"}),
-                     Uri.parse("content://com.example/path"));
-            fail("InputContentInfo must accept http and https link Uri only.");
-        } catch (InvalidParameterException e) {
-            // OK.
-        } catch (Exception e) {
-            fail("Unexpected exception=" + e);
-        }
+        // Test that we accept https link Uri
+        new InputContentInfo(
+                Uri.parse("content://com.example/path"),
+                new ClipDescription("sample content", new String[]{"image/png"}),
+                Uri.parse("https://example.com/path"));
     }
 
+    @Test(expected=InvalidParameterException.class)
+    public void testLinkUriFtpLinkUri() {
+        // InputContentInfo must accept http and https link Uri only
+        new InputContentInfo(
+                Uri.parse("content://com.example/path"),
+                new ClipDescription("sample content", new String[]{"image/png"}),
+                Uri.parse("ftp://example.com/path"));
+    }
+
+    @Test(expected=InvalidParameterException.class)
+    public void testLinkUriContentLinkUri() {
+        // InputContentInfo must accept http and https link Uri only
+        new InputContentInfo(
+                 Uri.parse("content://com.example/path"),
+                 new ClipDescription("sample content", new String[]{"image/png"}),
+                 Uri.parse("content://com.example/path"));
+    }
+
+    @Test
     public void testRequestAndReleasePermission() {
         InputContentInfo info = new InputContentInfo(
                 Uri.parse("content://com.example/path"),
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
index 3e071b6..b63a8bc 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodInfoTest.java
@@ -16,6 +16,14 @@
 
 package android.view.inputmethod.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -25,13 +33,18 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Printer;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -39,7 +52,11 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class InputMethodInfoTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodInfoTest {
+    private Context mContext;
+
     private InputMethodInfo mInputMethodInfo;
     private String mPackageName;
     private String mClassName;
@@ -58,9 +75,9 @@
     private int mSubtypeId;
     private InputMethodSubtype mInputMethodSubtype;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mPackageName = mContext.getPackageName();
         mClassName = InputMethodSettingsActivityStub.class.getName();
         mLabel = "test";
@@ -82,6 +99,7 @@
                 mSubtypeOverridesImplicitlyEnabledSubtype, mSubtypeId);
     }
 
+    @Test
     public void testInputMethodInfoProperties() throws XmlPullParserException, IOException {
         assertEquals(0, mInputMethodInfo.describeContents());
         assertNotNull(mInputMethodInfo.toString());
@@ -101,6 +119,7 @@
         }
     }
 
+    @Test
     public void testInputMethodSubtypeProperties() {
         // TODO: Test InputMethodSubtype.getDisplayName()
         assertEquals(mSubtypeNameResId, mInputMethodSubtype.getNameResId());
@@ -135,29 +154,35 @@
         assertEquals(mClassName, info.getServiceName());
     }
 
+    @Test
     public void testDump() {
-        MockPrinter printer = new MockPrinter();
+        Printer printer = mock(Printer.class);
         String prefix = "test";
         mInputMethodInfo.dump(printer, prefix);
+        verify(printer, atLeastOnce()).println(anyString());
     }
 
+    @Test
     public void testLoadIcon() {
         PackageManager pm = mContext.getPackageManager();
         assertNotNull(mInputMethodInfo.loadIcon(pm));
     }
 
+    @Test
     public void testEquals() {
         InputMethodInfo inputMethodInfo = new InputMethodInfo(mPackageName, mClassName, mLabel,
                 mSettingsActivity);
         assertTrue(inputMethodInfo.equals(mInputMethodInfo));
     }
 
+    @Test
     public void testLoadLabel() {
         CharSequence expected = "test";
         PackageManager pm = mContext.getPackageManager();
         assertEquals(expected.toString(), mInputMethodInfo.loadLabel(pm).toString());
     }
 
+    @Test
     public void testInputMethodInfoWriteToParcel() {
         final Parcel p = Parcel.obtain();
         mInputMethodInfo.writeToParcel(p, 0);
@@ -173,6 +198,7 @@
         assertService(mInputMethodInfo.getServiceInfo(), imi.getServiceInfo());
     }
 
+    @Test
     public void testInputMethodSubtypeWriteToParcel() {
         final Parcel p = Parcel.obtain();
         mInputMethodSubtype.writeToParcel(p, 0);
@@ -195,8 +221,9 @@
                 subtype.overridesImplicitlyEnabledSubtype());
     }
 
+    @Test
     public void testInputMethodSubtypesOfSystemImes() {
-        if (!getContext().getPackageManager().hasSystemFeature(
+        if (!mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS)) {
             return;
         }
@@ -237,8 +264,9 @@
         assertTrue(foundEnabledSystemImeSubtypeWithValidLanguage);
     }
 
+    @Test
     public void testAtLeastOneEncryptionAwareInputMethodIsAvailable() {
-        if (!getContext().getPackageManager().hasSystemFeature(
+        if (!mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS)) {
             return;
         }
@@ -262,10 +290,4 @@
         }
         assertTrue(hasEncryptionAwareInputMethod);
     }
-
-    class MockPrinter implements Printer {
-        @Override
-        public void println(String x) {
-        }
-    }
 }
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
index 9389e92..1ae1960 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputMethodManagerTest.java
@@ -15,51 +15,61 @@
  */
 package android.view.inputmethod.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.cts.util.PollingCheck;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.ResultReceiver;
-import android.test.ActivityInstrumentationTestCase2;
+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.KeyEvent;
 import android.view.Window;
+import android.view.cts.R;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.List;
 
-public class InputMethodManagerTest
-                  extends ActivityInstrumentationTestCase2<InputMethodCtsActivity> {
-
-    public InputMethodManagerTest() {
-        super("android.view.cts", InputMethodCtsActivity.class);
-    }
-
-    private InputMethodCtsActivity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodManagerTest {
     private Instrumentation mInstrumentation;
+    private InputMethodCtsActivity mActivity;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Rule
+    public ActivityTestRule<InputMethodCtsActivity> mActivityRule =
+            new ActivityTestRule<>(InputMethodCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        // Close soft input just in case.
-        sendKeys(KeyEvent.KEYCODE_BACK);
-        super.tearDown();
+    @After
+    public void teardown() {
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
     }
 
+    @Test
     public void testInputMethodManager() throws Throwable {
-        if (!getActivity().getPackageManager().hasSystemFeature(
+        if (!mActivity.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS)) {
             return;
         }
@@ -67,20 +77,10 @@
         Window window = mActivity.getWindow();
         final EditText view = (EditText) window.findViewById(R.id.entry);
 
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return view.hasWindowFocus();
-            }
-        }.run();
+        PollingCheck.waitFor(1000, view::hasWindowFocus);
 
-        runTestOnUiThread(new Runnable() {
-           @Override
-            public void run() {
-               view.requestFocus();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(view::requestFocus);
+        mInstrumentation.waitForIdleSync();
         assertTrue(view.isFocused());
 
         BaseInputConnection connection = new BaseInputConnection(view, false);
@@ -88,12 +88,7 @@
         final InputMethodManager imManager = (InputMethodManager) context
                 .getSystemService(Context.INPUT_METHOD_SERVICE);
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return imManager.isActive();
-            }
-        }.run();
+        PollingCheck.waitFor(imManager::isActive);
 
         assertTrue(imManager.isAcceptingText());
         assertTrue(imManager.isActive(view));
@@ -104,40 +99,37 @@
         // application should have no effect.
         assertFalse(imManager.isFullscreenMode());
 
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                IBinder token = view.getWindowToken();
+        mActivityRule.runOnUiThread(() -> {
+            IBinder token = view.getWindowToken();
 
-                // Show and hide input method.
-                assertTrue(imManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT));
-                assertTrue(imManager.hideSoftInputFromWindow(token, 0));
+            // Show and hide input method.
+            assertTrue(imManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT));
+            assertTrue(imManager.hideSoftInputFromWindow(token, 0));
 
-                Handler handler = new Handler();
-                ResultReceiver receiver = new ResultReceiver(handler);
-                assertTrue(imManager.showSoftInput(view, 0, receiver));
-                receiver = new ResultReceiver(handler);
-                assertTrue(imManager.hideSoftInputFromWindow(token, 0, receiver));
+            Handler handler = new Handler();
+            ResultReceiver receiver = new ResultReceiver(handler);
+            assertTrue(imManager.showSoftInput(view, 0, receiver));
+            receiver = new ResultReceiver(handler);
+            assertTrue(imManager.hideSoftInputFromWindow(token, 0, receiver));
 
-                imManager.showSoftInputFromInputMethod(token, InputMethodManager.SHOW_FORCED);
-                imManager.hideSoftInputFromInputMethod(token, InputMethodManager.HIDE_NOT_ALWAYS);
+            imManager.showSoftInputFromInputMethod(token, InputMethodManager.SHOW_FORCED);
+            imManager.hideSoftInputFromInputMethod(token, InputMethodManager.HIDE_NOT_ALWAYS);
 
-                // status: hide to show to hide
-                imManager.toggleSoftInputFromWindow(token, 0, InputMethodManager.HIDE_NOT_ALWAYS);
-                imManager.toggleSoftInputFromWindow(token, 0, InputMethodManager.HIDE_NOT_ALWAYS);
+            // status: hide to show to hide
+            imManager.toggleSoftInputFromWindow(token, 0, InputMethodManager.HIDE_NOT_ALWAYS);
+            imManager.toggleSoftInputFromWindow(token, 0, InputMethodManager.HIDE_NOT_ALWAYS);
 
-                List<InputMethodInfo> enabledImList = imManager.getEnabledInputMethodList();
-                if (enabledImList != null && enabledImList.size() > 0) {
-                    imManager.setInputMethod(token, enabledImList.get(0).getId());
-                    // cannot test whether setting was successful
-                }
+            List<InputMethodInfo> enabledImList = imManager.getEnabledInputMethodList();
+            if (enabledImList != null && enabledImList.size() > 0) {
+                imManager.setInputMethod(token, enabledImList.get(0).getId());
+                // cannot test whether setting was successful
+            }
 
-                List<InputMethodInfo> imList = imManager.getInputMethodList();
-                if (imList != null && enabledImList != null) {
-                    assertTrue(imList.size() >= enabledImList.size());
-                }
+            List<InputMethodInfo> imList = imManager.getInputMethodList();
+            if (imList != null && enabledImList != null) {
+                assertTrue(imList.size() >= enabledImList.size());
             }
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
     }
 }
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java b/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
index f56ad0e..bd0c811 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/KeyboardTest.java
@@ -16,23 +16,30 @@
 
 package android.view.inputmethod.cts;
 
-import android.view.cts.R;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.test.AndroidTestCase;
 import android.inputmethodservice.Keyboard;
 import android.inputmethodservice.Keyboard.Key;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.cts.R;
 
-import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class KeyboardTest extends AndroidTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardTest {
+    @Test
     public void testKeyOnPressedAndReleased() {
         Key nonStickyKey = null;
         Key stickyKey = null;
         // Indirectly instantiate Keyboard.Key with XML resources.
-        final Keyboard keyboard = new Keyboard(getContext(), R.xml.keyboard);
+        final Keyboard keyboard =
+                new Keyboard(InstrumentationRegistry.getTargetContext(), R.xml.keyboard);
         for (final Key key : keyboard.getKeys()) {
             if (!key.sticky) {
                 nonStickyKey = key;
diff --git a/tests/tests/voiceinteraction/Android.mk b/tests/tests/voiceinteraction/Android.mk
index d64574a..cbb874a 100644
--- a/tests/tests/voiceinteraction/Android.mk
+++ b/tests/tests/voiceinteraction/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 := CtsVoiceInteractionCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsVoiceInteractionCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index c69c247..01ea670 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -27,5 +27,6 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.voiceinteraction.cts" />
+        <option name="runtime-hint" value="11m" />
     </test>
 </configuration>
diff --git a/tests/tests/voiceinteraction/service/Android.mk b/tests/tests/voiceinteraction/service/Android.mk
index c485f21..b8d3aa8 100644
--- a/tests/tests/voiceinteraction/service/Android.mk
+++ b/tests/tests/voiceinteraction/service/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 := CtsVoiceInteractionCommon ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := CtsVoiceInteractionCommon ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/voicesettings/Android.mk b/tests/tests/voicesettings/Android.mk
index cbc97a2..c554470 100644
--- a/tests/tests/voicesettings/Android.mk
+++ b/tests/tests/voicesettings/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 ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/voicesettings/AndroidManifest.xml b/tests/tests/voicesettings/AndroidManifest.xml
index dfd1de5..cf1fa1a 100644
--- a/tests/tests/voicesettings/AndroidManifest.xml
+++ b/tests/tests/voicesettings/AndroidManifest.xml
@@ -23,7 +23,7 @@
     <application>
         <uses-library android:name="android.test.runner" />
 
-        <activity android:name="android.cts.util.BroadcastTestStartActivity"
+        <activity android:name="com.android.compatibility.common.util.BroadcastTestStartActivity"
                   android:label="The Target Activity for VoiceSettings CTS Test">
             <intent-filter>
                 <action android:name="android.intent.action.TEST_START_ACTIVITY_ZEN_MODE" />
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 64f5335..951ad44 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -24,5 +24,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.voicesettings.cts" />
+        <option name="runtime-hint" value="10m" />
     </test>
 </configuration>
diff --git a/tests/tests/voicesettings/service/Android.mk b/tests/tests/voicesettings/service/Android.mk
index cc26569..6f246bd 100644
--- a/tests/tests/voicesettings/service/Android.mk
+++ b/tests/tests/voicesettings/service/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 ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionService.java b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionService.java
index 1029235..6d5470b 100644
--- a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionService.java
+++ b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionService.java
@@ -16,12 +16,13 @@
 
 package android.voicesettings.service;
 
+import com.android.compatibility.common.util.BroadcastUtils;
+
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
-import android.cts.util.BroadcastUtils;
 
 public class MainInteractionService extends VoiceInteractionService {
     static final String TAG = "MainInteractionService";
diff --git a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
index d9a0746..87c8926 100644
--- a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
+++ b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
@@ -24,11 +24,12 @@
 import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
 import static android.provider.Settings.EXTRA_BATTERY_SAVER_MODE_ENABLED;
 
+import com.android.compatibility.common.util.BroadcastUtils;
+import com.android.compatibility.common.util.BroadcastUtils.TestcaseType;
+
 import android.app.VoiceInteractor;
 import android.content.Context;
 import android.content.Intent;
-import android.cts.util.BroadcastUtils;
-import android.cts.util.BroadcastUtils.TestcaseType;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
diff --git a/tests/tests/voicesettings/service/src/android/voicesettings/service/VoiceInteractionMain.java b/tests/tests/voicesettings/service/src/android/voicesettings/service/VoiceInteractionMain.java
index 645b4e9..9eba4c0 100644
--- a/tests/tests/voicesettings/service/src/android/voicesettings/service/VoiceInteractionMain.java
+++ b/tests/tests/voicesettings/service/src/android/voicesettings/service/VoiceInteractionMain.java
@@ -16,14 +16,14 @@
 
 package android.voicesettings.service;
 
+import com.android.compatibility.common.util.BroadcastUtils;
+
 import android.app.Activity;
 import android.content.Intent;
 import android.content.ComponentName;
 import android.os.Bundle;
 import android.util.Log;
 
-import android.cts.util.BroadcastUtils;
-
 public class VoiceInteractionMain extends Activity {
     static final String TAG = "VoiceInteractionMain";
 
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index 44efc28..db6bbb9 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -18,8 +18,9 @@
 
 import static android.provider.Settings.ACTION_VOICE_CONTROL_AIRPLANE_MODE;
 
-import android.cts.util.BroadcastTestBase;
-import android.cts.util.BroadcastUtils;
+import com.android.compatibility.common.util.BroadcastTestBase;
+import com.android.compatibility.common.util.BroadcastUtils;
+
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Log;
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
index fe858fc..759d82e 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
@@ -18,8 +18,9 @@
 
 import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
 
-import android.cts.util.BroadcastTestBase;
-import android.cts.util.BroadcastUtils;
+import com.android.compatibility.common.util.BroadcastTestBase;
+import com.android.compatibility.common.util.BroadcastUtils;
+
 import android.content.Context;
 import android.os.PowerManager;
 import android.util.Log;
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
index f6a164d..e01f3b9 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
@@ -20,8 +20,9 @@
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED;
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES;
 
-import android.cts.util.BroadcastTestBase;
-import android.cts.util.BroadcastUtils;
+import com.android.compatibility.common.util.BroadcastTestBase;
+import com.android.compatibility.common.util.BroadcastUtils;
+
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Log;
diff --git a/tests/tests/webkit/Android.mk b/tests/tests/webkit/Android.mk
index d133d80..2385647 100644
--- a/tests/tests/webkit/Android.mk
+++ b/tests/tests/webkit/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil \
+    compatibility-device-util \
     ctsdeviceutillegacy \
     ctstestserver \
     ctstestrunner
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index ffde739..799545a 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -16,14 +16,15 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 import android.webkit.WebView;
 import android.webkit.ValueCallback;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerCtsActivity.java b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerCtsActivity.java
index e623405..10369c6 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerCtsActivity.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerCtsActivity.java
@@ -17,11 +17,12 @@
 package android.webkit.cts;
 
 import android.app.Activity;
-import android.cts.util.NullWebViewUtils;
 import android.os.Bundle;
 import android.webkit.CookieSyncManager;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+
 public class CookieSyncManagerCtsActivity extends Activity {
     private WebView mWebView;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
index 4f89ec1..887b891 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieTest.java
@@ -16,12 +16,13 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
 import android.platform.test.annotations.Presubmit;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+
 /**
  * Original framework tests for CookieManager
  */
diff --git a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
index b6dc991..9f27081 100644
--- a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
@@ -17,9 +17,6 @@
 package android.webkit.cts;
 
 import android.content.Context;
-import android.cts.util.LocationUtils;
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.location.Criteria;
 import android.location.Location;
@@ -41,6 +38,10 @@
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
 
+import com.android.compatibility.common.util.LocationUtils;
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.concurrent.Callable;
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index 10bf6d8..dc9bf3c 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -16,12 +16,12 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.HttpAuthHandler;
 import android.webkit.WebView;
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
 
 import org.apache.http.HttpStatus;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
index 6ffe69c..ecc3e4f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -16,8 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -25,6 +23,9 @@
 import android.webkit.WebMessagePort;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.util.concurrent.CountDownLatch;
 import junit.framework.Assert;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
index e09e0d6..1e9f5e8 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerClientTest.java
@@ -16,8 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 
 import android.webkit.JavascriptInterface;
@@ -29,6 +27,9 @@
 import android.webkit.WebViewClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
index e7d6211..eb5b413 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
@@ -16,13 +16,13 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebHistoryItem;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
 
 public class WebBackForwardListTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 424d856..66b3399 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -16,8 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
@@ -29,6 +27,9 @@
 import android.webkit.WebView;
 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private static final long TEST_TIMEOUT = 5000L;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
index dc9e615..d04fd69 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
@@ -16,8 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.test.ActivityInstrumentationTestCase2;
 import android.webkit.WebBackForwardList;
@@ -26,6 +24,9 @@
 import android.webkit.WebIconDatabase;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 public class WebHistoryItemTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     private final static long TEST_TIMEOUT = 10000;
     private CtsTestServer mWebServer;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 7729baf..586f398 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -16,8 +16,6 @@
 package android.webkit.cts;
 
 import android.content.Context;
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.net.http.SslError;
 import android.os.Build;
@@ -33,6 +31,10 @@
 import android.webkit.WebViewClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.FileOutputStream;
 import java.util.Locale;
 import java.util.regex.Matcher;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 2f99b49..9d01827 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -16,9 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.EvaluateJsResultPollingCheck;
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
@@ -36,6 +33,10 @@
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 import android.util.Pair;
 
+import com.android.compatibility.common.util.EvaluateJsResultPollingCheck;
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java b/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
index 1b05154..9875662 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewCtsActivity.java
@@ -19,12 +19,13 @@
 import android.webkit.cts.R;
 
 import android.app.Activity;
-import android.cts.util.NullWebViewUtils;
 import android.os.Bundle;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.webkit.WebView;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+
 public class WebViewCtsActivity extends Activity {
     private WebView mWebView;
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
index e07267f..0708568 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
@@ -16,8 +16,6 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.net.Uri;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
@@ -34,6 +32,9 @@
 import android.webkit.WebViewClient;
 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.security.KeyFactory;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupCtsActivity.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupCtsActivity.java
deleted file mode 100644
index 933d0ed..0000000
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupCtsActivity.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.webkit.cts;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.webkit.WebView;
-
-public class WebViewStartupCtsActivity extends Activity {
-    private WebView mWebView;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    public WebView createAndAttachWebView() {
-        mWebView = new WebView(this);
-        setContentView(mWebView);
-        return mWebView;
-    }
-
-    public WebView getWebView() {
-        return mWebView;
-    }
-
-    public void detachAndDestroyWebView() {
-        if (mWebView != null) {
-            ViewGroup vg = (ViewGroup)mWebView.getParent();
-            vg.removeView(mWebView);
-            mWebView.destroy();
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        detachAndDestroyWebView();
-        super.onDestroy();
-    }
-}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
deleted file mode 100644
index 3b67d84..0000000
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewStartupTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit.cts;
-
-
-import android.content.Context;
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.util.Log;
-import android.webkit.CookieManager;
-import android.webkit.CookieSyncManager;
-import android.webkit.WebView;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class WebViewStartupTest
-        extends ActivityInstrumentationTestCase2<WebViewStartupCtsActivity> {
-
-    private static final int TEST_TIMEOUT = 5000;
-    private static final String TAG = "WebViewStartupTest";
-
-    private WebViewStartupCtsActivity mActivity;
-
-    public WebViewStartupTest() {
-        super("android.webkit.cts", WebViewStartupCtsActivity.class);
-    }
-
-    @Override
-    public void setUp() throws Exception {
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
-    public void testCookieManagerBlockingUiThread() throws Throwable {
-        CtsTestServer server = new CtsTestServer(mActivity, false);
-        final String url = server.getCookieUrl("death.html");
-
-        Thread background = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                CookieSyncManager csm = CookieSyncManager.createInstance(mActivity);
-                CookieManager cookieManager = CookieManager.getInstance();
-
-                cookieManager.removeAllCookie();
-                cookieManager.setAcceptCookie(true);
-                cookieManager.setCookie(url, "count=41");
-                Log.i(TAG, "done setting cookie before creating webview");
-            }
-        });
-        NullWebViewUtils.NullWebViewFromThreadExceptionHandler h =
-                new NullWebViewUtils.NullWebViewFromThreadExceptionHandler();
-
-        background.setUncaughtExceptionHandler(h);
-        background.start();
-        background.join();
-
-        if (!h.isWebViewAvailable(mActivity)) {
-            return;
-        }
-
-        // Now create WebView and test that setting the cookie beforehand really worked.
-        mActivity.createAndAttachWebView();
-        WebViewOnUiThread onUiThread = new WebViewOnUiThread(this, mActivity.getWebView());
-        onUiThread.loadUrlAndWaitForCompletion(url);
-        assertEquals("1|count=41", onUiThread.getTitle()); // outgoing cookie
-        CookieManager cookieManager = CookieManager.getInstance();
-        String cookie = cookieManager.getCookie(url);
-        assertNotNull(cookie);
-        final Pattern pat = Pattern.compile("count=(\\d+)");
-        Matcher m = pat.matcher(cookie);
-        assertTrue(m.matches());
-        assertEquals("42", m.group(1)); // value got incremented
-    }
-}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 9151783..01a88b1 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -19,9 +19,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetManager;
-import android.cts.util.EvaluateJsResultPollingCheck;
-import android.cts.util.NullWebViewUtils;
-import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
@@ -72,6 +69,10 @@
 import android.webkit.cts.WebViewOnUiThread.WaitForProgressClient;
 import android.widget.LinearLayout;
 
+import com.android.compatibility.common.util.EvaluateJsResultPollingCheck;
+import com.android.compatibility.common.util.NullWebViewUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
 import junit.framework.Assert;
 
 import java.io.ByteArrayInputStream;
@@ -2574,6 +2575,35 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    @UiThreadTest
+    public void testGetWebViewClient() throws Exception {
+        // getWebViewClient should return a default WebViewClient if it hasn't been set yet
+        WebView webView = new WebView(getActivity());
+        WebViewClient client = webView.getWebViewClient();
+        assertNotNull(client);
+        assertTrue(client instanceof WebViewClient);
+
+        // getWebViewClient should return the client after it has been set
+        WebViewClient client2 = new WebViewClient();
+        assertNotSame(client, client2);
+        webView.setWebViewClient(client2);
+        assertSame(client2, webView.getWebViewClient());
+    }
+
+    @UiThreadTest
+    public void testGetWebChromeClient() throws Exception {
+        // getWebChromeClient should return null if the client hasn't been set yet
+        WebView webView = new WebView(getActivity());
+        WebChromeClient client = webView.getWebChromeClient();
+        assertNull(client);
+
+        // getWebChromeClient should return the client after it has been set
+        WebChromeClient client2 = new WebChromeClient();
+        assertNotSame(client, client2);
+        webView.setWebChromeClient(client2);
+        assertSame(client2, webView.getWebChromeClient());
+    }
+
     private void savePrintedPage(final PrintDocumentAdapter adapter,
             final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
         adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
index 4fa9b4f..b4e4d04 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebView_WebViewTransportTest.java
@@ -16,12 +16,12 @@
 
 package android.webkit.cts;
 
-import android.cts.util.NullWebViewUtils;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.webkit.WebView;
 import android.webkit.WebView.WebViewTransport;
 
+import com.android.compatibility.common.util.NullWebViewUtils;
 
 public class WebView_WebViewTransportTest
         extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 4bc9eee..c19c27e 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 += \
-    mockito-target \
+    android-support-test \
+    mockito-target-minus-junit4 \
     android-common \
-    ctsdeviceutil \
-    ctstestrunner
+    compatibility-device-util \
+    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 5d41337..800b8a9 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"
@@ -36,6 +37,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.AbsoluteLayoutCtsActivity"
+                  android:label="AbsoluteLayoutCtsActivity">
+            <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.TwoLineListItemCtsActivity"
             android:label="TwoLineListItemCtsActivity">
             <intent-filter>
@@ -84,6 +93,22 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.ImageSwitcherCtsActivity"
+                  android:label="ImageSwitcherCtsActivity">
+            <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.TextSwitcherCtsActivity"
+                  android:label="TextSwitcherCtsActivity">
+            <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.SwitchCtsActivity"
                   android:label="SwitchCtsActivity">
             <intent-filter>
@@ -92,9 +117,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 +190,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 +238,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" />
@@ -222,6 +279,7 @@
         </activity>
 
         <activity android:name="android.widget.cts.PopupWindowCtsActivity"
+            android:configChanges="keyboardHidden|orientation|screenSize"
             android:label="PopupWindowCtsActivity"
             android:theme="@style/Theme.PopupWindowCtsActivity">
             <intent-filter>
@@ -247,7 +305,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" />
@@ -255,9 +321,19 @@
         </activity>
 
         <activity android:name="android.widget.cts.TextViewCtsActivity"
-            android:label="TextViewCtsActivity"
-            android:screenOrientation="nosensor"
-            android:windowSoftInputMode="stateAlwaysHidden">
+                  android:label="TextViewCtsActivity"
+                  android:screenOrientation="nosensor"
+                  android:windowSoftInputMode="stateAlwaysHidden">
+            <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.EditTextCtsActivity"
+                  android:label="EditTextCtsActivity"
+                  android:screenOrientation="nosensor"
+                  android:windowSoftInputMode="stateAlwaysHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -280,14 +356,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.widget.cts.ViewGroupCtsActivity"
-            android:label="WidgetViewGroupCtsActivity">
-            <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.VideoViewCtsActivity"
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:label="VideoViewCtsActivity">
@@ -381,16 +449,88 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.widget.cts.TimePickerDialogCtsActivity"
-                  android:label="TimePickerDialogCtsActivity">
+        <activity android:name="android.widget.cts.CalendarViewCtsActivity"
+                  android:label="CalendarViewCtsActivity">
             <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.CalendarViewCtsActivity"
-                  android:label="CalendarViewCtsActivity">
+        <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.CompoundButtonCtsActivity"
+                  android:label="CompoundButtonCtsActivity">
+            <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.widget.cts.RadioGroupCtsActivity"
+                  android:label="RadioGroupCtsActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -414,6 +554,24 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.PointerIconCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </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/absolute_layout.xml b/tests/tests/widget/res/layout/absolute_layout.xml
index 6cec61b..be525e2 100644
--- a/tests/tests/widget/res/layout/absolute_layout.xml
+++ b/tests/tests/widget/res/layout/absolute_layout.xml
@@ -14,14 +14,17 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
     <AbsoluteLayout
         android:id="@+id/absolute_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="0.5"
         android:layout_x="1dip"
         android:layout_y="2dip">
 
@@ -36,4 +39,24 @@
 
     </AbsoluteLayout>
 
+    <view
+        class="android.widget.cts.AbsoluteLayoutTest$MyAbsoluteLayout"
+        android:id="@+id/absolute_view_custom"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="0.5"
+        android:layout_x="1dip"
+        android:layout_y="2dip">
+
+        <TextView
+            android:id="@+id/absolute_textview2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_x="10dip"
+            android:layout_y="20dip"
+            android:background="@drawable/blue"
+            android:text="@string/hello_world"/>
+
+    </view>
+
 </LinearLayout>
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..793dfb0 100644
--- a/tests/tests/widget/res/layout/autocompletetextview_layout.xml
+++ b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
@@ -24,10 +24,17 @@
         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:inputType="none"/>
+        android:completionThreshold="1"
+        android:completionHint="@string/tabs_1"
+        android:inputType="none" />
+
+    <view
+        class="android.widget.cts.AutoCompleteTextViewTest$MockAutoCompleteTextView"
+        android:id="@+id/autocompletetv_custom"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
 </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/compoundbutton_layout.xml b/tests/tests/widget/res/layout/compoundbutton_layout.xml
new file mode 100644
index 0000000..4ab73c8
--- /dev/null
+++ b/tests/tests/widget/res/layout/compoundbutton_layout.xml
@@ -0,0 +1,37 @@
+<?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">
+
+    <view
+        class="android.widget.cts.CompoundButtonTest$MockCompoundButton"
+        android:id="@+id/compound_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/hello_world" />
+
+    <view
+        class="android.widget.cts.CompoundButtonTest$MockCompoundButton"
+        android:id="@+id/button_tint"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:buttonTint="@android:color/white"
+        android:buttonTintMode="src_over" />
+</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/edittext_layout.xml b/tests/tests/widget/res/layout/edittext_layout.xml
index 398d3be..64a41e5 100644
--- a/tests/tests/widget/res/layout/edittext_layout.xml
+++ b/tests/tests/widget/res/layout/edittext_layout.xml
@@ -14,26 +14,46 @@
      limitations under the License.
 -->
 
-<ScrollView 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" >
 
-    <LinearLayout android:id="@+id/edit_text"
+    <LinearLayout
+        android:id="@+id/edit_text"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical">
 
+        <EditText
+            android:id="@+id/edittext_simple1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <EditText
+            android:id="@+id/edittext_simple2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
         <EditText android:id="@+id/edittext1"
             style="@android:style/Widget.EditText"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
+            android:layout_height="wrap_content"
             android:layout_marginTop="10dip"
             android:scrollHorizontally="true"
             android:capitalize="sentences"
             android:autoText="false"
             android:maxLines="3"
             android:textColor="#FF0000"
-            android:text="@string/edit_text"
-        />
+            android:text="@string/edit_text" />
+
+        <EditText
+            android:id="@+id/edittext_autosize"
+            android:layout_width="300dp"
+            android:layout_height="400dp"
+            android:text="@string/long_text"
+            android:autoSizeText="xy"
+            android:textSize="50dp"
+            android:autoSizeStepGranularity="2dp" />
     </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/gallery_test.xml b/tests/tests/widget/res/layout/gallery_test.xml
index 03f0e60..1feb680 100644
--- a/tests/tests/widget/res/layout/gallery_test.xml
+++ b/tests/tests/widget/res/layout/gallery_test.xml
@@ -19,10 +19,10 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <android.widget.cts.MyGallery xmlns:android="http://schemas.android.com/apk/res/android"
+    <view
+        class="android.widget.cts.GalleryTest$MyGallery"
         android:id="@+id/gallery_test"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-    </android.widget.cts.MyGallery>
+        android:layout_height="match_parent"/>
 
 </LinearLayout>
diff --git a/tests/tests/widget/res/layout/gridlayout_layout.xml b/tests/tests/widget/res/layout/gridlayout_layout.xml
index 54b3b2c..44495d9 100644
--- a/tests/tests/widget/res/layout/gridlayout_layout.xml
+++ b/tests/tests/widget/res/layout/gridlayout_layout.xml
@@ -16,8 +16,6 @@
  -->
 <GridLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/gridlayout"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    >
-</GridLayout>
+    android:layout_height="match_parent" />
diff --git a/tests/tests/widget/res/layout/horizontal_scrollview.xml b/tests/tests/widget/res/layout/horizontal_scrollview.xml
index 0f88ab3..e14fe54 100644
--- a/tests/tests/widget/res/layout/horizontal_scrollview.xml
+++ b/tests/tests/widget/res/layout/horizontal_scrollview.xml
@@ -14,92 +14,110 @@
      limitations under the License.
 -->
 
-<android.widget.cts.MyHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/horizontal_scroll_view"
-    android:layout_width="100px"
-    android:layout_height="100px">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <view
+        class="android.widget.cts.HorizontalScrollViewTest$MyHorizontalScrollView"
+        android:id="@+id/horizontal_scroll_view_custom"
+        android:layout_width="100px"
+        android:layout_height="100px">
 
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="250px"
-        android:layout_height="wrap_content">
-
-        <Button
-            android:id="@+id/first_horizontal_child"
+        <LinearLayout
+            android:orientation="horizontal"
             android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_1"/>
+            android:layout_height="wrap_content">
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:id="@+id/first_horizontal_child"
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:id="@+id/last_horizontal_child"
-            android:layout_width="250px"
-            android:layout_height="100px"
-            android:text="@string/vertical_text_3"/>
-    </LinearLayout>
+            <Button
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_2"/>
 
-</android.widget.cts.MyHorizontalScrollView>
+            <Button
+                android:id="@+id/last_horizontal_child"
+                android:layout_width="250px"
+                android:layout_height="100px"
+                android:text="@string/vertical_text_3"/>
+        </LinearLayout>
+
+    </view>
+
+    <HorizontalScrollView
+        android:id="@+id/horizontal_scroll_view_regular"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <view
+        class="android.widget.cts.HorizontalScrollViewTest$MyHorizontalScrollView"
+        android:id="@+id/horizontal_scroll_view_custom_empty"
+        android:layout_width="100px"
+        android:layout_height="100px" />
+</LinearLayout>
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/imageswitcher_layout.xml b/tests/tests/widget/res/layout/imageswitcher_layout.xml
new file mode 100644
index 0000000..2cb15db
--- /dev/null
+++ b/tests/tests/widget/res/layout/imageswitcher_layout.xml
@@ -0,0 +1,28 @@
+<?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.
+ -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageSwitcher
+        android:id="@+id/switcher"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</FrameLayout>
+
diff --git a/tests/tests/widget/res/layout/imageswitcher_test.xml b/tests/tests/widget/res/layout/imageswitcher_test.xml
deleted file mode 100644
index 496b2ba..0000000
--- a/tests/tests/widget/res/layout/imageswitcher_test.xml
+++ /dev/null
@@ -1,29 +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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <ImageSwitcher android:id="@+id/switcher"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
-    />
-</RelativeLayout>
-
diff --git a/tests/tests/widget/res/layout/imageview_layout.xml b/tests/tests/widget/res/layout/imageview_layout.xml
index 80512e2..1876e2f 100644
--- a/tests/tests/widget/res/layout/imageview_layout.xml
+++ b/tests/tests/widget/res/layout/imageview_layout.xml
@@ -24,24 +24,30 @@
     android:orientation="vertical">
 
     <ImageView
-        android:id="@+id/imageview"
+        android:id="@+id/imageview_regular"
         android:layout_width="320px"
         android:layout_height="240px"/>
 
     <ImageView
-        android:id="@+id/image_tint"
+        android:id="@+id/imageview_tint"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:tint="@android:color/white"
         android:tintMode="src_over" />
 
     <ImageView
-        android:id="@+id/image_tint_with_source"
+        android:id="@+id/imageview_tint_with_source"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:src="@drawable/icon_red"
         android:tint="@android:color/white"
         android:tintMode="src_over" />
 
+    <view
+        class="android.widget.cts.ImageViewTest$MockImageView"
+        android:id="@+id/imageview_custom"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
 </LinearLayout>
 
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index 8881552..e4f881f 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -14,125 +14,238 @@
  * 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/linear_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/linear_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/linear_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/linear_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/linear_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/linear_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/linear_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
+        android:id="@+id/linear_empty"
+        android:layout_width="100px"
+        android:layout_height="100px" />
+
+    <view
+        class="android.widget.cts.LinearLayoutTest$MockLinearLayout"
+        android:id="@+id/linear_custom"
+        android:layout_width="100px"
+        android:layout_height="100px" />
 </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..fe8858f
--- /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="@dimen/listrow_height"
+    android:gravity="center_vertical"
+    android:textSize="24sp"
+    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..8b20169
--- /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="300dp"
+        android:layout_height="300dp"
+        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/pointer_icon_layout.xml b/tests/tests/widget/res/layout/pointer_icon_layout.xml
new file mode 100644
index 0000000..605eed2
--- /dev/null
+++ b/tests/tests/widget/res/layout/pointer_icon_layout.xml
@@ -0,0 +1,58 @@
+<?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/top"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button"/>
+
+    <ImageButton
+        android:id="@+id/image_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_green"/>
+
+    <Spinner
+        android:id="@+id/spinner"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"/>
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TabWidget
+            android:id="@android:id/tabs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"/>
+
+    </TabHost>
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/progressbar_layout.xml b/tests/tests/widget/res/layout/progressbar_layout.xml
index a1786b8..e51684a 100644
--- a/tests/tests/widget/res/layout/progressbar_layout.xml
+++ b/tests/tests/widget/res/layout/progressbar_layout.xml
@@ -14,28 +14,54 @@
      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" />
+
+        <view
+            class="android.widget.cts.ProgressBarTest$MockProgressBar"
+            style="@android:style/Widget.Material.Light.ProgressBar"
+            android:id="@+id/progress_custom"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </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/radiogroup_layout.xml b/tests/tests/widget/res/layout/radiogroup_layout.xml
new file mode 100755
index 0000000..9bce731
--- /dev/null
+++ b/tests/tests/widget/res/layout/radiogroup_layout.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<RadioGroup
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/radio_group"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:layout_weight="0.5"
+    android:layout_gravity="bottom"
+    android:layout_margin="@dimen/radiogroup_margin">
+
+    <RadioButton
+        android:id="@+id/radio_button_0"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/radio_choice_0" />
+
+    <RadioButton
+        android:id="@+id/radio_button_1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/radio_choice_1" />
+
+    <RadioButton
+        android:id="@+id/radio_button_2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/radio_choice_2" />
+
+    <RadioButton
+        android:id="@+id/radio_button_3"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/radio_choice_3" />
+
+</RadioGroup>
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/scrollview_layout.xml b/tests/tests/widget/res/layout/scrollview_layout.xml
index 3c9a474..57547ed 100644
--- a/tests/tests/widget/res/layout/scrollview_layout.xml
+++ b/tests/tests/widget/res/layout/scrollview_layout.xml
@@ -14,92 +14,112 @@
      limitations under the License.
 -->
 
-<android.widget.cts.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/scroll_view"
-    android:layout_width="100dip"
-    android:layout_height="100dip">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="250dip"
-        android:layout_height="wrap_content">
+    <view
+        class="android.widget.cts.ScrollViewTest$MyScrollView"
+        android:id="@+id/scroll_view_custom"
+        android:layout_width="100dip"
+        android:layout_height="100dip">
 
-        <Button
-            android:id="@+id/first_child"
+        <LinearLayout
+            android:orientation="vertical"
             android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_1"/>
+            android:layout_height="wrap_content">
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:id="@+id/first_child"
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_3"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_2"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_1"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_3"/>
 
-        <Button
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_2"/>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_1"/>
 
-        <Button
-            android:id="@+id/last_child"
-            android:layout_width="250dip"
-            android:layout_height="100dip"
-            android:text="@string/vertical_text_3"/>
-    </LinearLayout>
+            <Button
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_2"/>
 
-</android.widget.cts.MyScrollView>
+            <Button
+                android:id="@+id/last_child"
+                android:layout_width="250dip"
+                android:layout_height="100dip"
+                android:text="@string/vertical_text_3"/>
+        </LinearLayout>
+
+    </view>
+
+    <ScrollView
+        android:id="@+id/scroll_view_regular"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <view
+        class="android.widget.cts.ScrollViewTest$MyScrollView"
+        android:id="@+id/scroll_view_custom_empty"
+        android:layout_width="100dip"
+        android:layout_height="100dip" />
+</LinearLayout>
+
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/table_layout_1.xml b/tests/tests/widget/res/layout/table_layout_1.xml
index 0896cd2..9ddc3af 100644
--- a/tests/tests/widget/res/layout/table_layout_1.xml
+++ b/tests/tests/widget/res/layout/table_layout_1.xml
@@ -14,23 +14,44 @@
      limitations under the License.
 -->
 
-<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/table1"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:collapseColumns="0"
-    android:stretchColumns="2">
+    android:orientation="vertical">
 
-    <TableRow>
-        <TextView
-            android:text="@string/table_layout_first"
-            android:padding="3dip" />
-        <TextView
-            android:text="@string/table_layout_second"
-            android:padding="3dip" />
-        <TextView
-            android:text="@string/table_layout_third"
-            android:padding="3dip" />
-    </TableRow>
-</TableLayout>
+    <TableLayout
+        android:id="@+id/table1"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1.0"
+        android:collapseColumns="0"
+        android:stretchColumns="2">
 
+        <TableRow>
+            <TextView
+                android:text="@string/table_layout_first"
+                android:padding="3dip" />
+            <TextView
+                android:text="@string/table_layout_second"
+                android:padding="3dip" />
+            <TextView
+                android:text="@string/table_layout_third"
+                android:padding="3dip" />
+        </TableRow>
+    </TableLayout>
+
+    <TableLayout
+        android:id="@+id/table_empty"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1.0" />
+
+    <view
+        class="android.widget.cts.TableLayoutTest$MockTableLayout"
+        android:id="@+id/table_custom_empty"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1.0" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/textswitcher_layout.xml b/tests/tests/widget/res/layout/textswitcher_layout.xml
new file mode 100644
index 0000000..869f6ba
--- /dev/null
+++ b/tests/tests/widget/res/layout/textswitcher_layout.xml
@@ -0,0 +1,28 @@
+<?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">
+
+    <TextSwitcher
+        android:id="@+id/switcher"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</FrameLayout>
+
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index e3144eb..5611255 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -14,209 +14,279 @@
      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"/>
+
+            <TextView
+                android:id="@+id/textview_autosize_xy"
+                android:layout_width="100dp"
+                android:layout_height="200dp"
+                android:text="@string/sample_text"
+                android:autoSizeText="xy"
+                android:textSize="50dp"
+                android:autoSizeMinTextSize="2px"
+                android:autoSizeStepGranularity="1dp" />
+
         </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..8581008 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:timePickerMode="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..6680b12 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,17 +25,39 @@
         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/toggle_tint"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:buttonTint="@android:color/white"
-            android:buttonTintMode="src_over"
+            android:buttonTintMode="src_over" />
+
+        <view
+            class="android.widget.cts.ToggleButtonTest$MockToggleButton"
+            android:id="@+id/toggle_custom"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
 
diff --git a/tests/tests/widget/res/layout/viewflipper_layout.xml b/tests/tests/widget/res/layout/viewflipper_layout.xml
index 6480379..8865879 100644
--- a/tests/tests/widget/res/layout/viewflipper_layout.xml
+++ b/tests/tests/widget/res/layout/viewflipper_layout.xml
@@ -14,31 +14,38 @@
  * 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:padding="10dip"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:padding="10dip"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
 
-    <ViewFlipper android:id="@+id/viewflipper_test"
+    <ViewFlipper
+        android:id="@+id/viewflipper_test"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:flipInterval="1000"
-                android:layout_marginBottom="20dip" >
-                <TextView android:id="@+id/viewflipper_textview1"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal"
-                        android:textSize="26sp"
-                        android:visibility="gone"
-                        android:text="@string/hello_world"/>
-                <TextView android:id="@+id/viewflipper_textview2"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal"
-                        android:textSize="26sp"
-                        android:visibility="gone"
-                        android:text="@string/hello_android"/>
+        android:flipInterval="@integer/view_flipper_interval"
+        android:layout_marginBottom="20dip">
+
+        <TextView
+            android:id="@+id/viewflipper_textview1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textSize="26sp"
+            android:visibility="gone"
+            android:text="@string/hello_world"/>
+        <TextView
+            android:id="@+id/viewflipper_textview2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:textSize="26sp"
+            android:visibility="gone"
+            android:text="@string/hello_android"/>
+
     </ViewFlipper>
+
 </LinearLayout>
 
diff --git a/tests/tests/widget/res/layout/viewgrouptest_stub.xml b/tests/tests/widget/res/layout/viewgrouptest_stub.xml
deleted file mode 100644
index ee59126..0000000
--- a/tests/tests/widget/res/layout/viewgrouptest_stub.xml
+++ /dev/null
@@ -1,33 +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.
- -->
-
-<android.widget.cts.MockLinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/mocklinearlayout">
-
-    <!-- view1 goes on top -->
-    <TextView
-        android:id="@+id/viewgrouptest_stub"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-    />
-
-</android.widget.cts.MockLinearLayout>
-
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-w320dp-h426dp/integers.xml b/tests/tests/widget/res/values-w320dp-h426dp/integers.xml
deleted file mode 100644
index a9d049c..0000000
--- a/tests/tests/widget/res/values-w320dp-h426dp/integers.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="date_picker_mode">2</integer>
-    <integer name="time_picker_mode">2</integer>
-</resources>
diff --git a/tests/tests/widget/res/values-w426dp-h320dp/integers.xml b/tests/tests/widget/res/values-w426dp-h320dp/integers.xml
deleted file mode 100644
index a9d049c..0000000
--- a/tests/tests/widget/res/values-w426dp-h320dp/integers.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="date_picker_mode">2</integer>
-    <integer name="time_picker_mode">2</integer>
-</resources>
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..5287b22 100644
--- a/tests/tests/widget/res/values/dimens.xml
+++ b/tests/tests/widget/res/values/dimens.xml
@@ -15,4 +15,36 @@
 -->
 <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>
+
+    <dimen name="radiogroup_margin">4dip</dimen>
+    <dimen name="listrow_height">40dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/ids.xml b/tests/tests/widget/res/values/ids.xml
new file mode 100644
index 0000000..1e840d0
--- /dev/null
+++ b/tests/tests/widget/res/values/ids.xml
@@ -0,0 +1,18 @@
+<!-- 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>
+    <item type="id" name="radio_button_dynamic" />
+</resources>
diff --git a/tests/tests/widget/res/values/integers.xml b/tests/tests/widget/res/values/integers.xml
index b2c1e65..c696024 100644
--- a/tests/tests/widget/res/values/integers.xml
+++ b/tests/tests/widget/res/values/integers.xml
@@ -13,8 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <resources>
-    <integer name="date_picker_mode">1</integer>
-    <integer name="time_picker_mode">1</integer>
+    <integer name="view_flipper_interval">1000</integer>
 </resources>
diff --git a/tests/tests/widget/res/values/strings.xml b/tests/tests/widget/res/values/strings.xml
index 63ceffa..1f6f87c 100644
--- a/tests/tests/widget/res/values/strings.xml
+++ b/tests/tests/widget/res/values/strings.xml
@@ -193,4 +193,20 @@
     <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>
+
+    <string name="radio_choice_0">choice 0</string>
+    <string name="radio_choice_1">choice 1</string>
+    <string name="radio_choice_2">choice 2</string>
+    <string name="radio_choice_3">choice 3</string>
 </resources>
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index d2e8e48..7ba9711 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -193,11 +193,6 @@
         <item name="android:windowSwipeToDismiss">false</item>
     </style>
 
-    <style name="Theme_Holo_With_Material_Pickers" parent="@android:style/Theme.Holo">
-        <item name="android:timePickerStyle">@android:style/Widget.Material.TimePicker</item>
-        <item name="android:datePickerStyle">@android:style/Widget.Material.DatePicker</item>
-    </style>
-
     <style name="PopupEmptyStyle" />
 
     <style name="TabWidgetCustomStyle" parent="android:Widget.TabWidget">
@@ -208,6 +203,26 @@
 
     <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>
+
+    <style name="FastScrollCustomStyle" parent="@android:style/Widget.Material.FastScroll">
+        <item name="android:textSize">32sp</item>
+        <item name="android:minWidth">120dp</item>
+        <item name="android:minHeight">64dp</item>
+    </style>
+
     <style name="Theme.PopupWindowCtsActivity" parent="@android:style/Theme.Holo">
         <!-- Force swipe-to-dismiss to false. -->
         <item name="android:windowSwipeToDismiss">false</item>
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 2a6883f..f2d70ec 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsListViewTest.java
@@ -16,100 +16,133 @@
 
 package android.widget.cts;
 
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.cts.R;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
 
-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.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.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.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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 com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
-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 Instrumentation mInstrumentation;
+    private AbsListView mListView;
+    private Context mContext;
     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();
 
+        final Activity activity = mActivityRule.getActivity();
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+        PollingCheck.waitFor(activity::hasWindowFocus);
 
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
-
-        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
     @UiThreadTest
     public void testAccessFastScrollEnabled_UiThread() {
         mListView.setFastScrollAlwaysVisible(false);
@@ -121,26 +154,18 @@
         assertTrue(mListView.isFastScrollEnabled());
     }
 
+    @Test
     public void testAccessFastScrollEnabled() {
         mListView.setFastScrollAlwaysVisible(false);
         mListView.setFastScrollEnabled(false);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !mListView.isFastScrollEnabled();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> !mListView.isFastScrollEnabled());
 
         mListView.setFastScrollAlwaysVisible(true);
         mListView.setFastScrollEnabled(true);
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mListView.isFastScrollEnabled();
-            }
-        }.run();
+        PollingCheck.waitFor(mListView::isFastScrollEnabled);
     }
 
+    @Test
     public void testAccessSmoothScrollbarEnabled() {
         mListView.setSmoothScrollbarEnabled(false);
         assertFalse(mListView.isSmoothScrollbarEnabled());
@@ -149,6 +174,7 @@
         assertTrue(mListView.isSmoothScrollbarEnabled());
     }
 
+    @Test
     public void testAccessScrollingCacheEnabled() {
         mListView.setScrollingCacheEnabled(false);
         assertFalse(mListView.isScrollingCacheEnabled());
@@ -158,116 +184,116 @@
     }
 
     private void setAdapter() throws Throwable {
-        setAdapter(mAdapter_countries);
+        setAdapter(mCountriesAdapter);
     }
 
     private void setAdapter(final ListAdapter adapter) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setAdapter(adapter);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setSelection(index));
         mInstrumentation.waitForIdleSync();
     }
+
+    @LargeTest
+    @Test
     public void testSetOnScrollListener() throws Throwable {
-        MockOnScrollListener onScrollListener = new MockOnScrollListener();
+        AbsListView.OnScrollListener mockScrollListener =
+                mock(AbsListView.OnScrollListener.class);
 
-        assertNull(onScrollListener.getView());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
-        assertEquals(0, onScrollListener.getVisibleItemCount());
-        assertEquals(0, onScrollListener.getTotalItemCount());
-        assertEquals(-1, onScrollListener.getScrollState());
+        verifyZeroInteractions(mockScrollListener);
 
-        assertFalse(onScrollListener.isOnScrollCalled());
-        assertFalse(onScrollListener.isOnScrollStateChangedCalled());
+        mListView.setOnScrollListener(mockScrollListener);
+        verify(mockScrollListener, times(1)).onScroll(mListView, 0, 0, 0);
+        verifyNoMoreInteractions(mockScrollListener);
 
-        mListView.setOnScrollListener(onScrollListener);
-        assertSame(mListView, onScrollListener.getView());
-        assertEquals(0, onScrollListener.getFirstVisibleItem());
-        assertEquals(0, onScrollListener.getVisibleItemCount());
-        assertEquals(0, onScrollListener.getTotalItemCount());
-        assertEquals(-1, onScrollListener.getScrollState());
-
-        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));
     }
 
+    @LargeTest
+    @Test
     public void testFling() throws Throwable {
-        MockOnScrollListener onScrollListener = new MockOnScrollListener();
-        mListView.setOnScrollListener(onScrollListener);
+        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) throws Throwable {
+        reset(mockScrollListener);
 
-        final int v = velocityY;
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.fling(v);
-            }
-        });
+        // Fling the list view
+        mActivityRule.runOnUiThread(() -> mListView.fling(velocityY));
 
-        do {
-            mInstrumentation.waitForIdleSync();
-        } while (onScrollListener.getScrollState() != OnScrollListener.SCROLL_STATE_IDLE);
+        // and wait until our mock listener is invoked with IDLE state
+        verify(mockScrollListener, within(20000)).onScrollStateChanged(
+                mListView, OnScrollListener.SCROLL_STATE_IDLE);
     }
 
+    @Test
     public void testGetFocusedRect() throws Throwable {
-        setAdapter(mAdapter_short);
+        setAdapter(mShortAdapter);
         setListSelection(0);
 
         Rect r1 = new Rect();
@@ -291,45 +317,47 @@
         assertEquals(r1.right, r2.right);
     }
 
+    @Test
     public void testAccessStackFromBottom() throws Throwable {
         setAdapter();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setStackFromBottom(false);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setStackFromBottom(false));
         assertFalse(mListView.isStackFromBottom());
         assertEquals(0, mListView.getSelectedItemPosition());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.setStackFromBottom(true);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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());
     }
 
+    @Test
     public void testAccessSelectedItem() throws Throwable {
         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());
+        }
     }
 
+    @Test
     public void testAccessListPadding() throws Throwable {
         setAdapter();
 
@@ -339,11 +367,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);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> mListView.setPadding(r.left, r.top, r.right, r.bottom));
         mInstrumentation.waitForIdleSync();
 
         assertEquals(r.left, mListView.getListPaddingLeft());
@@ -352,17 +377,14 @@
         assertEquals(r.bottom, mListView.getListPaddingBottom());
     }
 
+    @Test
     public void testAccessSelector() throws Throwable {
         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();
-            }
-        });
+        mActivityRule.runOnUiThread(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
         assertSame(d, mListView.getSelector());
         assertTrue(mListView.verifyDrawable(d));
@@ -370,11 +392,7 @@
         mListView.setSelector(R.drawable.failed);
         mListView.setDrawSelectorOnTop(true);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mListView.requestLayout();
-            }
-        });
+        mActivityRule.runOnUiThread(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
 
         Drawable drawable = mListView.getSelector();
@@ -382,33 +400,27 @@
         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);
     }
 
+    @Test
     public void testSetScrollIndicators() throws Throwable {
-        TextView tv1 = (TextView) mActivity.findViewById(R.id.headerview1);
-        TextView tv2 = (TextView) mActivity.findViewById(R.id.footerview1);
+        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();
-            }
-        });
+        mActivityRule.runOnUiThread(mListView::requestLayout);
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testShowContextMenuForChild() throws Throwable {
         setAdapter();
         setListSelection(1);
@@ -419,6 +431,7 @@
         // TODO: how to show the contextMenu success
     }
 
+    @Test
     public void testPointToPosition() throws Throwable {
         assertEquals(AbsListView.INVALID_POSITION, mListView.pointToPosition(-1, -1));
         assertEquals(AbsListView.INVALID_ROW_ID, mListView.pointToRowId(-1, -1));
@@ -432,39 +445,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
-    }
-
+    @Test
     public void testSetRecyclerListener() throws Throwable {
         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());
@@ -479,6 +490,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());
@@ -490,8 +502,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));
@@ -500,15 +513,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());
 
@@ -517,14 +531,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);
@@ -533,6 +548,8 @@
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, res.height);
     }
 
+    @UiThreadTest
+    @Test
     public void testBeforeAndAfterTextChanged() {
         // The java doc says these two methods do nothing
         CharSequence str = "test";
@@ -542,8 +559,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());
@@ -560,8 +577,9 @@
         assertTrue(listView.isAfterTextChangedCalled());
     }
 
+    @Test
     public void testAddTouchables() throws Throwable {
-        ArrayList<View> views = new ArrayList<View>();
+        ArrayList<View> views = new ArrayList<>();
         assertEquals(0, views.size());
 
         setAdapter();
@@ -570,78 +588,69 @@
         assertEquals(mListView.getChildCount(), views.size());
     }
 
+    @Test
     public void testInvalidateViews() throws Throwable {
-        TextView tv1 = (TextView) mActivity.findViewById(R.id.headerview1);
-        TextView tv2 = (TextView) mActivity.findViewById(R.id.footerview1);
+        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();
-            }
-        });
+        mActivityRule.runOnUiThread(mListView::invalidateViews);
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testGetContextMenuInfo() throws Throwable {
-        final MyListView listView = new MyListView(mActivity, mAttributeSet);
+        final MyListView listView = new MyListView(mContext, mAttributeSet);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(listView);
-                listView.setAdapter(mAdapter_countries);
-                listView.setSelection(2);
-            }
+        mActivityRule.runOnUiThread(() ->  {
+            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);
 
-        mInstrumentation.waitForIdleSync();
-        TouchUtils.longClickView(this, v);
-
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return v == listener.getView();
-            }
-        }.run();
-
-        assertSame(listView, listener.getParent());
-        assertEquals(2, listener.getPosition());
-        assertEquals(listView.getItemIdAtPosition(2), listener.getID());
+        // Now long click our view
+        CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, v, 500);
+        // and wait until our mock listener is invoked with the expected view
+        verify(mockOnItemLongClickListener, within(5000)).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?
     }
 
+    @UiThreadTest
+    @Test
     public void testSetFilterText() {
-        MyListView listView = new MyListView(mActivity, mAttributeSet, 0);
+        MyListView listView = new MyListView(mContext, mAttributeSet, 0);
         String filterText = "xyz";
 
         assertFalse(listView.isTextFilterEnabled());
@@ -674,231 +683,413 @@
     }
 
     @MediumTest
-    public void testSetItemChecked_multipleModeSameValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_multipleModeSameValue() throws Throwable {
         // 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         assertFalse(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_singleModeSameValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_singleModeSameValue() throws Throwable {
         // 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, false);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         assertFalse(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_multipleModeDifferentValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_multipleModeDifferentValue() throws Throwable {
         // 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, true);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, true));
         assertTrue(mListView.isLayoutRequested());
     }
 
     @MediumTest
-    public void testSetItemChecked_singleModeDifferentValue()
-            throws Throwable {
+    @Test
+    public void testSetItemChecked_singleModeDifferentValue() throws Throwable {
         // 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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(0, false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mListView.isLayoutRequested());
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mListView.setItemChecked(0, true);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        // 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);
+
+        mActivityRule.runOnUiThread(() -> {
+            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
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(COUNTRY_LIST));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, items);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mActivityRule.runOnUiThread(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_NONE));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderSingleChoiceMode() throws Throwable {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(COUNTRY_LIST));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, items);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mActivityRule.runOnUiThread(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] { 4 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderMultipleChoiceMode() throws Throwable {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(COUNTRY_LIST));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, items);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mActivityRule.runOnUiThread(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE));
+        verifyCheckedState(new long[] {});
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, true));
+        verifyCheckedState(new long[] { 2, 4 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+    }
+
+    private void configureMultiChoiceModalState() throws Throwable {
+        final ArrayList<String> items = new ArrayList<>(Arrays.asList(COUNTRY_LIST));
+        final ArrayAdapter<String> adapter = new PositionArrayAdapter<>(mContext,
+                android.R.layout.simple_list_item_1, items);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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);
+
+        mActivityRule.runOnUiThread(
+                () -> mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL));
+        verifyCheckedState(new long[] {});
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckedItemsUnderMultipleModalChoiceMode() throws Throwable {
+        configureMultiChoiceModalState();
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, true));
+        verifyCheckedState(new long[] { 2 });
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(2), eq(2L), eq(true));
+
+        reset(mMultiChoiceModeListener);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, false));
+        verifyCheckedState(new long[] { 4 });
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(2), eq(2L), eq(false));
+
+        reset(mMultiChoiceModeListener);
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, false));
+        verifyCheckedState(new long[] {});
+        mListView.setMultiChoiceModeListener(mMultiChoiceModeListener);
+        verify(mMultiChoiceModeListener, times(1)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(4), eq(4L), eq(false));
+    }
+
+    @LargeTest
+    @Test
+    public void testMultiSelectionWithLongPressAndTaps() throws Throwable {
+        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;
+        CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation,
+                mListView.getChildAt(positionForInitialSelection));
+        // wait until our listener has been notified that the item has been checked
+        verify(mMultiChoiceModeListener, within(1000)).onItemCheckedStateChanged(
+                any(ActionMode.class), eq(positionForInitialSelection),
+                eq((long) positionForInitialSelection), eq(true));
+        // and verify the overall checked state of our list
+        verifyCheckedState(new long[] { positionForInitialSelection });
+
+        if (firstVisiblePosition != positionForInitialSelection) {
+            // Tap the first element in our list
+            CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation,
+                    mListView.getChildAt(firstVisiblePosition));
+            // wait until our listener has been notified that the item has been checked
+            verify(mMultiChoiceModeListener, within(1000)).onItemCheckedStateChanged(
+                    any(ActionMode.class), eq(firstVisiblePosition),
+                    eq((long) firstVisiblePosition), eq(true));
+            // and verify the overall checked state of our list
+            verifyCheckedState(new long[] { firstVisiblePosition, positionForInitialSelection });
+        }
+
+        // Scroll down
+        CtsTouchUtils.emulateScrollToBottom(mInstrumentation, mListView);
+        final int lastListPosition = COUNTRY_LIST.length - 1;
+        if (lastListPosition != positionForInitialSelection) {
+            // Tap the last element in our list
+            CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation,
+                    mListView.getChildAt(mListView.getChildCount() - 1));
+            // wait until our listener has been notified that the item has been checked
+            verify(mMultiChoiceModeListener, within(1000)).onItemCheckedStateChanged(
+                    any(ActionMode.class), eq(lastListPosition),
+                    eq((long) lastListPosition), eq(true));
+            // and verify the overall checked state of our list
+            verifyCheckedState(new long[] { firstVisiblePosition, positionForInitialSelection,
+                    lastListPosition });
+        }
+    }
+
+    // Helper method that emulates fast scroll by dragging along the right edge of our ListView.
+    private void verifyFastScroll() throws Throwable {
+        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;
+        }
+
+        mActivityRule.runOnUiThread(() -> mListView.setFastScrollAlwaysVisible(true));
+        mInstrumentation.waitForIdleSync();
+        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());
+    }
+
+    @LargeTest
+    @Test
+    public void testFastScroll() throws Throwable {
+        verifyFastScroll();
+    }
+
+    @LargeTest
+    @Test
+    public void testFastScrollStyle() throws Throwable {
+        mListView.setFastScrollStyle(R.style.FastScrollCustomStyle);
+
+        verifyFastScroll();
+    }
+
     /**
-     * MyListView for test
+     * MyListView for test.
      */
     private static class MyListView extends ListView {
         public MyListView(Context context) {
@@ -1006,5 +1197,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..3bb7d55 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,46 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.AbsListView;
 import android.widget.AbsListView.LayoutParams;
 
-public class AbsListView_LayoutParamsTest extends AndroidTestCase {
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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..32fee43
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AbsListView_ScrollTest.java
@@ -0,0 +1,690 @@
+/*
+ * 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.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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 com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
+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;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AbsListView_ScrollTest {
+    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 Instrumentation mInstrumentation;
+    private AbsListView mListView;
+    private Context mContext;
+    private ArrayAdapter<String> mCountriesAdapter;
+    private int mRowHeightPx;
+
+    @Before
+    public void setup() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> mListView.setAdapter(mCountriesAdapter));
+        mInstrumentation.waitForIdleSync();
+
+        mRowHeightPx = mContext.getResources().getDimensionPixelSize(R.dimen.listrow_height);
+    }
+
+    /**
+     * 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) throws Throwable {
+        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));
+        mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPosition(
+                positionToScrollTo));
+
+        assertTrue("Timed out while waiting for the scroll to complete",
+                latch.await(2, TimeUnit.SECONDS));
+
+        // 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() throws Throwable {
+        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() throws Throwable {
+        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) throws Throwable {
+        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));
+        mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPosition(
+                positionToScrollTo, boundPosition));
+
+        assertTrue("Timed out while waiting for the scroll to complete",
+                latch.await(2, TimeUnit.SECONDS));
+
+        // 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() throws Throwable {
+        // Our list is 300dp high and each row is 40dp 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) throws Throwable {
+        final int startTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * mRowHeightPx -
+                        mListView.getChildAt(0).getTop();
+        int targetTopPositionInListCoordinates = positionToScrollTo * mRowHeightPx - 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 * mRowHeightPx - 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) {
+            mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPositionFromTop(
+                    positionToScrollTo, offset, durationMs));
+        } else {
+            mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPositionFromTop(
+                    positionToScrollTo, offset));
+        }
+
+        // Since position-based scroll is emulated as a series of mini-flings, scrolling
+        // might take considerable time.
+        int timeoutMs = durationMs > 0 ? 5000 + durationMs : 5000;
+        assertTrue("Timed out while waiting for the scroll to complete",
+                latch.await(timeoutMs, TimeUnit.MILLISECONDS));
+
+        final int endTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * mRowHeightPx -
+                        mListView.getChildAt(0).getTop();
+
+        assertEquals(targetTopPositionInListCoordinates, endTopPositionInListCoordinates);
+    }
+
+    @Test
+    public void testSmoothScrollToPositionFromTop() throws Throwable {
+        // Ask to scroll so that the top of position 5 is 10 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 dps below the top edge of the list
+        // (which means that since row height is 40 dps high, the top item should be 3
+        verifyScrollToPositionFromTop(5, 2 * mRowHeightPx, -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() throws Throwable {
+        // 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 dps below the top edge of the list
+        // (which means that since row height is 40 dps high, the top item should be 3
+        verifyScrollToPositionFromTop(5, 2 * mRowHeightPx, 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() throws Throwable {
+        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) throws Throwable {
+        // Here we rely on knowing the fixed pixel height of each row
+        final int startTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * mRowHeightPx -
+                        mListView.getChildAt(0).getTop();
+
+        // Since scrollListBy is a synchronous operation, we do not need to wait
+        // until we can proceed to test the result
+        mActivityRule.runOnUiThread(() -> mListView.scrollListBy(y));
+
+        final int endTopPositionInListCoordinates =
+                mListView.getFirstVisiblePosition() * mRowHeightPx -
+                        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 * mRowHeightPx - mListView.getHeight(),
+                expectedTopPositionInListCoordinates);
+
+        assertEquals(expectedTopPositionInListCoordinates, endTopPositionInListCoordinates);
+    }
+
+    @Test
+    public void testScrollListBy() throws Throwable {
+        final int listHeight = mListView.getHeight();
+        final int itemCount = COUNTRY_LIST.length;
+
+        // Scroll down by half row height
+        verifyScrollBy(mRowHeightPx / 2);
+
+        // Scroll up by full row height - verifying that we're going to stop at the top of the first
+        // row
+        verifyScrollBy(-mRowHeightPx);
+
+        // 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 + mRowHeightPx);
+
+        // Scroll down by another half row
+        verifyScrollBy(mRowHeightPx / 2);
+
+        // Scroll up by full row height
+        verifyScrollBy(-mRowHeightPx);
+
+        // 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(-mRowHeightPx / 2);
+
+        // Scroll down by full row height - verifying that we're going to stop at the bottom of the
+        // last row
+        verifyScrollBy(mRowHeightPx);
+
+        // Scroll up halfway into the list - we expect it to be capped by the list height minus
+        // one pixel.
+        verifyScrollBy(-itemCount * mRowHeightPx / 2);
+    }
+
+    @Test
+    public void testListScrollAndTap() throws Throwable {
+        // 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));
+        mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPosition(30));
+
+        // Since position-based scroll is emulated as a series of mini-flings, scrolling
+        // might take considerable time.
+        assertTrue("Timed out while waiting for the scroll to complete",
+                scrollLatch.await(5, TimeUnit.SECONDS));
+
+        // 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)
+            throws Throwable {
+        // 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));
+        mActivityRule.runOnUiThread(() -> mListView.smoothScrollToPosition(30));
+
+        // Since position-based scroll is emulated as a series of mini-flings, scrolling
+        // might take considerable time.
+        assertTrue("Timed out while waiting for the scroll to complete",
+                scrollLatch.await(5, TimeUnit.SECONDS));
+
+        // 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);
+
+        assertTrue("Timed out while waiting for the fling to complete",
+                flingLatch.await(5, TimeUnit.SECONDS));
+
+        // 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() throws Throwable {
+        verifyListScrollAndEmulateFlingGesture(true);
+    }
+
+    @Test
+    public void testListScrollAndEmulateUpwardsFlingGesture() throws Throwable {
+        verifyListScrollAndEmulateFlingGesture(false);
+    }
+
+    @Test
+    public void testListFlingWithZeroVelocity() throws Throwable {
+        mListView.setVelocityScale(0.0f);
+
+        final CountDownLatch flingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(flingLatch));
+        final int flingAmount =
+                CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+
+        assertTrue("Timed out while waiting for the fling to complete",
+                flingLatch.await(5, TimeUnit.SECONDS));
+
+        // 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 / mRowHeightPx;
+        final int expectedBottomPositionAtFlingEnd = expectedBottomOffsetAtFlingEnd / mRowHeightPx;
+
+        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() throws Throwable {
+        // 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
+        mActivityRule.runOnUiThread(
+                () -> mListView.setAdapter(new LargeContentAdapter(mContext, 100000)));
+        mInstrumentation.waitForIdleSync();
+
+        final CountDownLatch initialFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(initialFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        assertTrue("Timed out while waiting for the fling to complete",
+                initialFlingLatch.await(5, TimeUnit.SECONDS));
+
+        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() / 4.0f);
+        // and do the fling again
+        final CountDownLatch fastFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(fastFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        assertTrue("Timed out while waiting for the fling to complete",
+                fastFlingLatch.await(5, TimeUnit.SECONDS));
+
+        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() * 4.0f);
+        // and do the fling again
+        final CountDownLatch slowFlingLatch = new CountDownLatch(1);
+        mListView.setOnScrollListener(new ScrollIdleListListener(slowFlingLatch));
+        CtsTouchUtils.emulateFlingGesture(mInstrumentation, mListView, false);
+        assertTrue("Timed out while waiting for the fling to complete",
+                slowFlingLatch.await(5, TimeUnit.SECONDS));
+
+        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/tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java
new file mode 100644
index 0000000..1bac1f5
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AbsSeekBarCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.AbsSeekBar;
+
+/**
+ * A minimal application for {@link AbsSeekBar} test
+ */
+public class AbsSeekBarCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    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..606c86f 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSeekBarTest.java
@@ -16,49 +16,77 @@
 
 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.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.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.widget.AbsSeekBar;
 import android.widget.SeekBar;
+import android.widget.cts.util.TestUtils;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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 +103,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 +210,35 @@
         assertTrue(myAbsSeekBar.verifyDrawable(drawable4));
     }
 
+    @Test
     public void testAccessKeyProgressIncrement() throws Throwable {
         // 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();
+        mActivityRule.runOnUiThread(() -> 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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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);
@@ -225,59 +266,74 @@
     }
 
     @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());
+        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);
+        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());
+        inflatedView.setThumbTintMode(PorterDuff.Mode.DST_ATOP);
+        assertEquals("Thumb tint mode changed correctly",
+                PorterDuff.Mode.DST_ATOP, inflatedView.getThumbTintMode());
+
+        reset(mockThumb);
+        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());
+        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);
+        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());
+        inflatedView.setTickMarkTintMode(PorterDuff.Mode.DARKEN);
+        assertEquals("TickMark tint mode changed correctly",
+                PorterDuff.Mode.DARKEN, inflatedView.getTickMarkTintMode());
+
+        reset(mockTickMark);
+        inflatedView.setTickMark(null);
+        inflatedView.setTickMark(mockTickMark);
+        verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
+    }
+
+    @Test
+    public void testAccessSplitTrack() throws Throwable {
+        AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.tick_mark_tint);
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, inflatedView,
+                () -> inflatedView.setSplitTrack(true));
+        assertTrue(inflatedView.getSplitTrack());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, inflatedView,
+                () -> inflatedView.setSplitTrack(false));
+        assertFalse(inflatedView.getSplitTrack());
     }
 
     private static class MyAbsSeekBar extends AbsSeekBar {
@@ -293,6 +349,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 +363,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..36f56a1 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsSpinnerTest.java
@@ -16,17 +16,20 @@
 
 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.database.DataSetObserver;
 import android.graphics.Rect;
 import android.os.Parcelable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -39,109 +42,115 @@
 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 Activity mActivity;
+    private AbsSpinner mAbsSpinner;
+
+    @Rule
+    public ActivityTestRule<RelativeLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RelativeLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        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.
      */
+    @UiThreadTest
+    @Test
     public void testSetSelectionIntBoolean() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                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);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
+        mAbsSpinner.setAdapter(adapter);
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(1, true);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
+        mAbsSpinner.setSelection(1, true);
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(absSpinner.getCount() - 1, false);
-        assertEquals(absSpinner.getCount() - 1, absSpinner.getSelectedItemPosition());
+        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.
      */
+    @UiThreadTest
+    @Test
     public void testSetSelectionInt() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                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);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
+        mAbsSpinner.setAdapter(adapter);
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(1);
-        assertEquals(1, absSpinner.getSelectedItemPosition());
+        mAbsSpinner.setSelection(1);
+        assertEquals(1, mAbsSpinner.getSelectedItemPosition());
 
-        absSpinner.setSelection(absSpinner.getCount() - 1);
-        assertEquals(absSpinner.getCount() - 1, absSpinner.getSelectedItemPosition());
+        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.
      */
+    @UiThreadTest
+    @Test
     public void testAccessAdapter() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                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);
 
-        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.
+        mAbsSpinner.setAdapter(adapter);
+        assertSame(adapter, mAbsSpinner.getAdapter());
+        assertEquals(adapter.getCount(), mAbsSpinner.getCount());
+        assertEquals(0, mAbsSpinner.getSelectedItemPosition());
+        assertEquals(adapter.getItemId(0), mAbsSpinner.getSelectedItemId());
+        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 +158,26 @@
         assertTrue(absSpinner.isLayoutRequested());
     }
 
-    @UiThreadTest
     /**
      * Check points:
      * 1. The value returned from getCount() equals the count of Adapter associated with
      * this AdapterView.
      */
+    @UiThreadTest
+    @Test
     public void testGetCount() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
+        ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
 
-        ArrayAdapter<CharSequence> adapter1 = ArrayAdapter.createFromResource(mContext,
-                android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
-
-        absSpinner.setAdapter(adapter1);
-        assertEquals(adapter1.getCount(), absSpinner.getCount());
+        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());
+        mAbsSpinner.setAdapter(adapter2);
+        assertEquals(anotherStringArray.length, mAbsSpinner.getCount());
     }
 
     /**
@@ -177,9 +185,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 +220,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 +232,34 @@
 
         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().
      */
+    @UiThreadTest
+    @Test
     public void testOnSaveAndRestoreInstanceState() {
-        AbsSpinner absSpinner = (AbsSpinner) getActivity().findViewById(R.id.spinner1);
-        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mContext,
-                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);
-        absSpinner.setAdapter(adapter);
-        assertEquals(0, absSpinner.getSelectedItemPosition());
-        assertEquals(adapter.getItemId(0), absSpinner.getSelectedItemId());
-        Parcelable parcelable = absSpinner.onSaveInstanceState();
+        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());
+        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
+        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 +295,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/AbsoluteLayoutCtsActivity.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutCtsActivity.java
new file mode 100644
index 0000000..cfd570c
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.AbsoluteLayout;
+
+/**
+ * A minimal application for {@link AbsoluteLayout} test
+ */
+public class AbsoluteLayoutCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.absolute_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
index a838f65..924da09 100644
--- a/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AbsoluteLayoutTest.java
@@ -16,44 +16,56 @@
 
 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.content.Context;
-import android.cts.util.WidgetTestUtils;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.ViewGroup;
 import android.widget.AbsoluteLayout;
 import android.widget.AbsoluteLayout.LayoutParams;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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 Activity mActivity;
+    private AbsoluteLayout mAbsoluteLayout;
     private MyAbsoluteLayout mMyAbsoluteLayout;
     private LayoutParams mAbsoluteLayoutParams;
 
-    public AbsoluteLayoutTest() {
-        super("android.widget.cts", CtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<AbsoluteLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(AbsoluteLayoutCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mMyAbsoluteLayout = new MyAbsoluteLayout(mActivity);
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mAbsoluteLayout = (AbsoluteLayout) mActivity.findViewById(R.id.absolute_view);
+        mMyAbsoluteLayout = (MyAbsoluteLayout) mActivity.findViewById(R.id.absolute_view_custom);
         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,8 @@
         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
-    }
-
+    @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
         assertTrue(mMyAbsoluteLayout.checkLayoutParams(mAbsoluteLayoutParams));
 
@@ -90,15 +97,11 @@
         assertFalse(mMyAbsoluteLayout.checkLayoutParams(null));
     }
 
-    public void testGenerateLayoutParams1() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(R.layout.absolute_layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        AbsoluteLayout layout = (AbsoluteLayout) mActivity.findViewById(R.id.absolute_view);
-        LayoutParams params = (LayoutParams) layout.generateLayoutParams(getAttributeSet());
+    @UiThreadTest
+    @Test
+    public void testGenerateLayoutParamsFromAttributeSet() throws Throwable {
+        LayoutParams params = (LayoutParams) mAbsoluteLayout.generateLayoutParams(
+                getAttributeSet());
 
         assertNotNull(params);
         assertEquals(LayoutParams.MATCH_PARENT, params.width);
@@ -107,7 +110,9 @@
         assertEquals(0, params.y);
     }
 
-    public void testGenerateLayoutParams2() {
+    @UiThreadTest
+    @Test
+    public void testGenerateLayoutParamsFromLayoutParams() {
         LayoutParams params =
             (LayoutParams) mMyAbsoluteLayout.generateLayoutParams(mAbsoluteLayoutParams);
 
@@ -115,15 +120,15 @@
         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);
+    }
+
+    @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams() {
         LayoutParams params = (LayoutParams) mMyAbsoluteLayout.generateDefaultLayoutParams();
 
@@ -133,11 +138,15 @@
         assertEquals(0, params.y);
     }
 
-    private static class MyAbsoluteLayout extends AbsoluteLayout {
+    public static class MyAbsoluteLayout extends AbsoluteLayout {
         public MyAbsoluteLayout(Context context) {
             super(context);
         }
 
+        public MyAbsoluteLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         @Override
         protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
             return super.checkLayoutParams(p);
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..0faa547 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,37 @@
 
 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.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.AbsoluteLayout;
 import android.widget.AbsoluteLayout.LayoutParams;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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 +54,7 @@
         return Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         LayoutParams layoutParams;
 
@@ -58,6 +73,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/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
new file mode 100644
index 0000000..1b58b63
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ActionMenuView;
+
+/**
+ * A minimal application for {@link ActionMenuView} test.
+ */
+public class ActionMenuViewCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..36b13d2
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Menu;
+import android.widget.ActionMenuView;
+import android.widget.cts.util.TestUtils;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testMenuContent() {
+        final Menu menu = mActionMenuView.getMenu();
+        assertNotNull(menu);
+
+        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() throws Throwable {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mActivityRule.runOnUiThread(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to show overflow menu and check that it's showing
+        mActivityRule.runOnUiThread(mActionMenuView::showOverflowMenu);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to hide the overflow menu and check that it's not showing
+        mActivityRule.runOnUiThread(mActionMenuView::hideOverflowMenu);
+        mInstrumentation.waitForIdleSync();
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+    }
+
+    @Test
+    public void testMenuOverflowSubmenu() throws Throwable {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mActivityRule.runOnUiThread(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+        // Ask to show overflow menu and check that it's showing
+        mActivityRule.runOnUiThread(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
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(mActionMenuView::dismissPopupMenus);
+        mInstrumentation.waitForIdleSync();
+        assertFalse(mActionMenuView.isOverflowMenuShowing());
+    }
+
+    @Test
+    public void testMenuOverflowIcon() throws Throwable {
+        // Inflate menu and check that we're not showing overflow menu yet
+        mActivityRule.runOnUiThread(
+                () -> mActivity.getMenuInflater().inflate(
+                        R.menu.toolbar_menu, mActionMenuView.getMenu()));
+
+        final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testPopupTheme() {
+        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..f7fc033 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -16,12 +16,29 @@
 
 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.content.Context;
 import android.os.Parcelable;
-import android.test.ActivityInstrumentationTestCase2;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -31,18 +48,22 @@
 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 com.android.compatibility.common.util.WidgetTestUtils;
 
+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 +72,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 +96,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 +160,7 @@
         assertEquals(FRUIT.length, mAdapterView.getCount());
     }
 
+    @Test
     public void testAccessEmptyView() {
         ImageView emptyView = new ImageView(mActivity);
 
@@ -203,8 +202,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 +211,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 +222,7 @@
         assertEquals(FRUIT.length - 1, mAdapterView.getLastVisiblePosition());
     }
 
+    @Test
     public void testItemOrItemIdAtPosition() {
         // no adapter set
         assertNull(mAdapterView.getItemAtPosition(0));
@@ -235,12 +236,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 +244,75 @@
         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));
     }
 
-    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);
+    @Test
+    public void testAccessOnItemSelectedListener() throws Throwable {
+        mAdapterView = mActivity.getListView();
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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());
+        mActivityRule.runOnUiThread(() -> 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(mActivityRule, 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(mActivityRule, 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 +323,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 +333,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 +368,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 +406,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 +419,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 +433,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 +480,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..8fad791 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterView_AdapterContextMenuInfoTest.java
@@ -16,15 +16,24 @@
 
 package android.widget.cts;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
 
-public class AdapterView_AdapterContextMenuInfoTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterView_AdapterContextMenuInfoTest {
+    @Test
     public void testConstructor() {
         AdapterView.AdapterContextMenuInfo menuInfo;
-        View testView = new View(getContext());
+        View testView = new View(InstrumentationRegistry.getTargetContext());
         int position = 1;
         long id = 0xffL;
         menuInfo = new AdapterView.AdapterContextMenuInfo(testView, position, id);
diff --git a/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java b/tests/tests/widget/src/android/widget/cts/AlphabetIndexerTest.java
index dd9393c..7ddbbd5 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.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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..144deca 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.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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..84c60c8 100644
--- a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
@@ -16,25 +16,39 @@
 
 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.content.Context;
 import android.content.res.Resources.Theme;
 import android.database.DataSetObserver;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.ArrayAdapter;
 import android.widget.Filter;
 import android.widget.TextView;
 
-import android.widget.cts.R;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
 
-public class ArrayAdapterTest extends InstrumentationTestCase {
-
-    private static final int INVALD_ID = -1;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ArrayAdapterTest {
+    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 +56,90 @@
     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);
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule =
+            new ActivityTestRule<>(CtsActivity.class);
+
+    @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();
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessView() {
         final TextView textView = new TextView(mContext);
         textView.setText(STR3);
@@ -145,48 +162,54 @@
         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());
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDropDownGetViewOutOfBoundsLow() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getDropDownView(-1, textView, null);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetViewOutOfBoundsHigh() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getView(mArrayAdapter.getCount(), textView, null);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testDropDownGetViewOutOfBoundsHigh() {
+        final TextView textView = new TextView(mContext);
+        mArrayAdapter.getDropDownView(mArrayAdapter.getCount(), textView, null);
+    }
+
+    @Test
+    public void testGetFilter() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            Filter filter = mArrayAdapter.getFilter();
+
+            assertNotNull(mArrayAdapter.getFilter());
+            assertSame(filter, mArrayAdapter.getFilter());
+        });
     }
 
     /**
-     * just simple change the resource id from which the drop view inflate from
+     * Just simple change the resource id from which the drop view inflate from
      * 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() {
+    @UiThreadTest
+    @Test
+    public void testSetDropDownViewResource() {
         mArrayAdapter.add(STR1);
 
         mArrayAdapter.getDropDownView(0, null, null);
@@ -194,17 +217,19 @@
         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);
     }
 
+    @UiThreadTest
+    @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 +240,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 +261,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 +294,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 +329,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 +356,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 +381,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 +399,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 +454,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 +482,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 +499,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..5b969d3 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 com.android.compatibility.common.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.cts.util.PollingCheck;
+import android.content.res.Resources;
+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.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.KeyCharacterMap;
@@ -40,37 +63,40 @@
 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 com.android.compatibility.common.util.PollingCheck;
 
-public class AutoCompleteTextViewTest extends
-        ActivityInstrumentationTestCase2<AutoCompleteCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
-    /**
-     * Instantiates a new text view test.
-     */
-    public AutoCompleteTextViewTest() {
-        super("android.widget.cts", AutoCompleteCtsActivity.class);
-    }
+@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";
 
-    /** The m activity. */
     private Activity mActivity;
-
-    /** The m instrumentation. */
     private Instrumentation mInstrumentation;
     private AutoCompleteTextView mAutoCompleteTextView;
+    private MockAutoCompleteTextView mMockAutoCompleteTextView;
     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,25 +106,40 @@
         }
     };
 
-    /*
-     * (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,
+        mMockAutoCompleteTextView = (MockAutoCompleteTextView) mActivity
+                .findViewById(R.id.autocompletetv_custom);
+        mAdapter = new ArrayAdapter<>(mActivity,
                 android.R.layout.simple_dropdown_item_1line, WORDS);
         KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
@@ -107,37 +148,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,38 +190,50 @@
         new AutoCompleteTextView(mActivity, null, -1);
     }
 
+    @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() throws Throwable {
         mAutoCompleteTextView.setThreshold(3);
         assertEquals(3, mAutoCompleteTextView.getThreshold());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                String testString = "TryToTest";
-                mAutoCompleteTextView.setText(testString);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("TryToTest"));
         mInstrumentation.waitForIdleSync();
         assertTrue(mAutoCompleteTextView.enoughToFilter());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                String testString = "No";
-                mAutoCompleteTextView.setText(testString);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("No"));
         mInstrumentation.waitForIdleSync();
         assertFalse(mAutoCompleteTextView.enoughToFilter());
     }
 
     @UiThreadTest
+    @Test
     public void testAccessAdapter() {
+        mAutoCompleteTextView.setAdapter(null);
+        assertNull(mAutoCompleteTextView.getAdapter());
+
+        mAutoCompleteTextView.setAdapter(mAdapter);
+        assertSame(mAdapter, mAutoCompleteTextView.getAdapter());
+
+        // Re-set adapter to null
+        mAutoCompleteTextView.setAdapter(null);
+        assertNull(mAutoCompleteTextView.getAdapter());
+    }
+
+    @UiThreadTest
+    @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());
 
@@ -187,52 +244,59 @@
         assertSame(filter, autoCompleteTextView.getFilter());
 
         // Re-set adapter to null
-        autoCompleteTextView.setAdapter(adapter);
+        autoCompleteTextView.setAdapter(null);
         assertNull(autoCompleteTextView.getAdapter());
         assertNull(autoCompleteTextView.getFilter());
     }
 
-    @SuppressWarnings("deprecation")
+    @UiThreadTest
+    @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")
+    @UiThreadTest
+    @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);
 
@@ -246,119 +310,177 @@
     }
 
     @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());
+        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());
+        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 {
+    @Test
+    public void testPopupWindow() {
+        final AutoCompleteTextView.OnDismissListener mockDismissListener =
+                mock(AutoCompleteTextView.OnDismissListener.class);
+        mAutoCompleteTextView.setOnDismissListener(mockDismissListener);
+
         assertFalse(mAutoCompleteTextView.isPopupShowing());
         mAutoCompleteTextView.showDropDown();
         assertTrue(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockDismissListener);
 
         mAutoCompleteTextView.dismissDropDown();
         assertFalse(mAutoCompleteTextView.isPopupShowing());
+        verify(mockDismissListener, times(1)).onDismiss();
 
         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);
         assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
+
         // clearFocus will trigger onFocusChanged, and onFocusChanged will validate the text.
         mAutoCompleteTextView.clearFocus();
         assertFalse(mAutoCompleteTextView.isPopupShowing());
         assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
+        verify(mockDismissListener, times(2)).onDismiss();
+
+        verifyNoMoreInteractions(mockDismissListener);
     }
 
     @UiThreadTest
+    @Test
+    public void testDropDownMetrics() {
+        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);
+
+        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() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+
+        mActivityRule.runOnUiThread(() -> {
+            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);
+
+        mActivityRule.runOnUiThread(() -> {
+            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);
+    }
+
+    @UiThreadTest
+    @Test
     public void testReplaceText() {
-        MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+        mMockAutoCompleteTextView.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());
+        mMockAutoCompleteTextView.replaceText("Text");
+        assertEquals("Text", mMockAutoCompleteTextView.getText().toString());
+        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());
+        mMockAutoCompleteTextView.replaceText("Another");
+        assertEquals("Another", mMockAutoCompleteTextView.getText().toString());
+        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);
-
-        assertTrue(autoCompleteTextView.setFrame(0, 1, 2, 3));
-        assertEquals(0, autoCompleteTextView.getLeft());
-        assertEquals(1, autoCompleteTextView.getTop());
-        assertEquals(2, autoCompleteTextView.getRight());
-        assertEquals(3, autoCompleteTextView.getBottom());
+        assertTrue(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
+        assertEquals(0, mMockAutoCompleteTextView.getLeft());
+        assertEquals(1, mMockAutoCompleteTextView.getTop());
+        assertEquals(2, mMockAutoCompleteTextView.getRight());
+        assertEquals(3, mMockAutoCompleteTextView.getBottom());
 
         // If the values are the same as old ones, function will return false
-        assertFalse(autoCompleteTextView.setFrame(0, 1, 2, 3));
-        assertEquals(0, autoCompleteTextView.getLeft());
-        assertEquals(1, autoCompleteTextView.getTop());
-        assertEquals(2, autoCompleteTextView.getRight());
-        assertEquals(3, autoCompleteTextView.getBottom());
+        assertFalse(mMockAutoCompleteTextView.setFrame(0, 1, 2, 3));
+        assertEquals(0, mMockAutoCompleteTextView.getLeft());
+        assertEquals(1, mMockAutoCompleteTextView.getTop());
+        assertEquals(2, mMockAutoCompleteTextView.getRight());
+        assertEquals(3, mMockAutoCompleteTextView.getBottom());
 
         // If the values are not the same as old ones, function will return true
-        assertTrue(autoCompleteTextView.setFrame(2, 3, 4, 5));
-        assertEquals(2, autoCompleteTextView.getLeft());
-        assertEquals(3, autoCompleteTextView.getTop());
-        assertEquals(4, autoCompleteTextView.getRight());
-        assertEquals(5, autoCompleteTextView.getBottom());
+        assertTrue(mMockAutoCompleteTextView.setFrame(2, 3, 4, 5));
+        assertEquals(2, mMockAutoCompleteTextView.getLeft());
+        assertEquals(3, mMockAutoCompleteTextView.getTop());
+        assertEquals(4, mMockAutoCompleteTextView.getRight());
+        assertEquals(5, mMockAutoCompleteTextView.getBottom());
     }
 
+    @UiThreadTest
+    @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());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessValidater() {
         final MockValidator validator = new MockValidator();
 
@@ -371,6 +493,7 @@
         assertNull(mAutoCompleteTextView.getValidator());
     }
 
+    @Test
     public void testOnFilterComplete() throws Throwable {
         // Set Threshold to 4 characters
         mAutoCompleteTextView.setThreshold(4);
@@ -384,22 +507,15 @@
         }
 
         // Test the filter if the input string is not long enough to threshold
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mActivityRule.runOnUiThread(() -> {
                 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 +524,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() {
+        mActivityRule.runOnUiThread(() -> {
                 mAutoCompleteTextView.setFocusable(true);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.setText("");
-            }
         });
         if (mNumeric) {
             // "test" in case of 12-key(NUMERIC) keyboard
@@ -431,20 +540,15 @@
         }
         assertTrue(mAutoCompleteTextView.hasFocus());
         assertTrue(mAutoCompleteTextView.hasWindowFocus());
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mAutoCompleteTextView.isPopupShowing();
-            }
-        }.run();
+        PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
     }
 
+    @Test
     public void testPerformFiltering() throws Throwable {
         if (isTvMode()) {
             return;
         }
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mActivityRule.runOnUiThread(() -> {
                 mAutoCompleteTextView.setAdapter(mAdapter);
                 mAutoCompleteTextView.setValidator(mValidator);
 
@@ -452,7 +556,6 @@
                 mAutoCompleteTextView.setFocusable(true);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.showDropDown();
-            }
         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mAutoCompleteTextView.isPopupShowing());
@@ -461,11 +564,9 @@
         // KeyBack will close the popup.
         assertFalse(mAutoCompleteTextView.isPopupShowing());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mActivityRule.runOnUiThread(() -> {
                 mAutoCompleteTextView.dismissDropDown();
                 mAutoCompleteTextView.setText(STRING_TEST);
-            }
         });
         mInstrumentation.waitForIdleSync();
 
@@ -478,12 +579,10 @@
                 android.R.layout.simple_dropdown_item_1line, WORDS);
 
         // Set Threshold to 4 charactersonKeyDown
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mActivityRule.runOnUiThread(() -> {
                 mAutoCompleteTextView.setAdapter(adapter);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.setText("");
-            }
         });
         mInstrumentation.waitForIdleSync();
         // Create and get the filter.
@@ -495,38 +594,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() throws Throwable {
         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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+            mAutoCompleteTextView.requestFocus();
+            mAutoCompleteTextView.showDropDown();
         });
         mInstrumentation.waitForIdleSync();
         assertFalse(mAutoCompleteTextView.isPerformingCompletion());
@@ -535,55 +624,117 @@
         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();
-            }
-        });
+        mActivityRule.runOnUiThread(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();
-            }
-        });
+        mActivityRule.runOnUiThread(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();
-            }
-        });
+        mActivityRule.runOnUiThread(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());
     }
 
+    @Test
+    public void testPerformCompletionExplicit() throws Throwable {
+        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);
+
+        mActivityRule.runOnUiThread(() -> {
+            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);
+        mActivityRule.runOnUiThread(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() throws Throwable {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+        mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("testO", true));
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockItemClickListener);
+    }
+
+    @Test
+    public void testSetTextWithNoCompletion() throws Throwable {
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
+
+        mActivityRule.runOnUiThread(() -> {
+            mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+            mAutoCompleteTextView.setAdapter(mAdapter);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+        mActivityRule.runOnUiThread(() -> mAutoCompleteTextView.setText("testO", false));
+        mInstrumentation.waitForIdleSync();
+
+        assertFalse(mAutoCompleteTextView.isPopupShowing());
+        verifyZeroInteractions(mockItemClickListener);
+    }
+
     @UiThreadTest
+    @Test
     public void testPerformValidation() {
         final CharSequence text = "this";
 
@@ -596,41 +747,30 @@
         mAutoCompleteTextView.setValidator(null);
     }
 
-    public void testSetCompletionHint() {
+    @UiThreadTest
+    @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
-    }
-
-    public void testOnCommitCompletion() {
-        // implement details, do not test
-    }
-
-    public void testOnDetachedFromWindow() {
-        // implement details, do not test
-    }
-
-    public void testOnKeyPreIme() {
-        // implement details, do not test
-    }
-
+    @Test
     public void testAccessListSelection() throws Throwable {
-        final MockOnItemClickListener listener = new MockOnItemClickListener();
+        final AdapterView.OnItemClickListener mockItemClickListener =
+                mock(AdapterView.OnItemClickListener.class);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mAutoCompleteTextView.setOnItemClickListener(listener);
+        mActivityRule.runOnUiThread(() -> {
+                mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
                 mAutoCompleteTextView.setAdapter(mAdapter);
                 mAutoCompleteTextView.requestFocus();
                 mAutoCompleteTextView.showDropDown();
-            }
         });
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
+        mActivityRule.runOnUiThread(() -> {
                 mAutoCompleteTextView.setListSelection(1);
                 assertEquals(1, mAutoCompleteTextView.getListSelection());
 
@@ -639,11 +779,12 @@
 
                 mAutoCompleteTextView.clearListSelection();
                 assertEquals(2, mAutoCompleteTextView.getListSelection());
-            }
         });
         mInstrumentation.waitForIdleSync();
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessDropDownAnchor() {
         mAutoCompleteTextView.setDropDownAnchor(View.NO_ID);
         assertEquals(View.NO_ID, mAutoCompleteTextView.getDropDownAnchor());
@@ -652,6 +793,8 @@
         assertEquals(0x5555, mAutoCompleteTextView.getDropDownAnchor());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessDropDownWidth() {
         mAutoCompleteTextView.setDropDownWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, mAutoCompleteTextView.getDropDownWidth());
@@ -660,75 +803,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;
-        }
-
+    public 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 +838,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 +851,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..42c3269 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.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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..28859d0 100644
--- a/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BaseExpandableListAdapterTest.java
@@ -16,23 +16,51 @@
 
 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.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.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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 testDefaults() {
+        // Test child type / group type APIs for the default values documented in the method
+        // Javadocs
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        assertEquals(1, adapter.getGroupTypeCount());
+        assertEquals(0, adapter.getGroupType(0));
+        assertEquals(1, adapter.getChildTypeCount());
+        assertEquals(0, adapter.getChildType(0, 0));
+    }
+
+    @Test
     public void testAreAllItemsEnabled() {
-        MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         assertTrue(adapter.areAllItemsEnabled());
     }
 
+    @Test
     public void testGetCombinedId() {
-        MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
 
         long childID = adapter.getCombinedChildId(10, 100);
         long groupID = adapter.getCombinedGroupId(10);
@@ -45,6 +73,7 @@
         assertTrue(childID != groupID);
     }
 
+    @Test
     public void testIsEmpty() {
         MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         assertTrue(adapter.isEmpty());
@@ -52,81 +81,57 @@
         assertFalse(adapter.isEmpty());
     }
 
+    @Test
     public void testNotifyDataSetChanged() {
-        MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
-        MockDataSetObserver dataSetObserver = new MockDataSetObserver();
-        adapter.registerDataSetObserver(dataSetObserver);
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        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);
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        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();
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
         // this function is non-operation.
         adapter.onGroupCollapsed(0);
     }
 
+    @Test
     public void testOnGroupExpanded() {
-        MockBaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        BaseExpandableListAdapter 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);
+        BaseExpandableListAdapter adapter = new MockBaseExpandableListAdapter();
+        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..c320895 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.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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..670b4f8 100644
--- a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
@@ -16,41 +16,67 @@
 
 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.test.suitebuilder.annotation.MediumTest;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
 import android.widget.CalendarView;
+import android.widget.ScrollView;
 import android.widget.cts.util.TestUtils;
 
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+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();
+    @UiThreadTest
+    @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(() -> {
-            mCalendarViewMaterial.setDate(currentDate);
-            mCalendarViewHolo.setDate(currentDate);
-        });
+        mCalendarViewMaterial.setDate(currentDate);
+        mCalendarViewHolo.setDate(currentDate);
     }
 
+    @UiThreadTest
+    @Test
     public void testConstructor() {
         new CalendarView(mActivity);
 
@@ -58,33 +84,38 @@
 
         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);
     }
 
+    @UiThreadTest
+    @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(
-                () -> mCalendarViewMaterial.setDate(yearAgoDate));
+        mCalendarViewMaterial.setDate(yearAgoDate);
         assertEquals(yearAgoDate, mCalendarViewMaterial.getDate());
 
         // Go forward two years (one year from current date in aggregate)
         newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) + 2);
         final long yearHenceDate = newCalendar.getTime().getTime();
 
-        instrumentation.runOnMainSync(
-                () -> mCalendarViewMaterial.setDate(yearHenceDate, true, false));
+        mCalendarViewMaterial.setDate(yearHenceDate, true, false);
         assertEquals(yearHenceDate, mCalendarViewMaterial.getDate());
     }
 
+    @UiThreadTest
+    @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,15 +125,104 @@
         final long minDate = minCalendar.getTime().getTime();
         final long maxDate = maxCalendar.getTime().getTime();
 
-        instrumentation.runOnMainSync(() -> {
-            mCalendarViewMaterial.setMinDate(minDate);
-            mCalendarViewMaterial.setMaxDate(maxDate);
-        });
+        mCalendarViewMaterial.setMinDate(minDate);
+        mCalendarViewMaterial.setMaxDate(maxDate);
 
         assertEquals(mCalendarViewMaterial.getMinDate(), minDate);
         assertEquals(mCalendarViewMaterial.getMaxDate(), maxDate);
     }
 
+    @UiThreadTest
+    @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();
+
+        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) throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(
+                () -> 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.emulateTapOnView(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() throws Throwable {
+        // 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);
+
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        // 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);
+    }
+
+    @UiThreadTest
+    @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,20 @@
         assertEquals(R.style.TextAppearance_WithColorGreen,
                 mCalendarViewMaterial.getWeekDayTextAppearance());
 
-        final Instrumentation instrumentation = getInstrumentation();
-
         // Change the visual appearance of the widget
-        instrumentation.runOnMainSync(() -> {
-            mCalendarViewMaterial.setFirstDayOfWeek(3);
-            mCalendarViewMaterial.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
-            mCalendarViewMaterial.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
-        });
+        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());
     }
 
+    @UiThreadTest
+    @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 +269,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,20 +281,18 @@
         final @ColorInt int newWeekSeparatorLineColor =
                 mActivity.getColor(R.color.calendarview_week_separatorline_new);
 
-        instrumentation.runOnMainSync(() -> {
-            mCalendarViewHolo.setFirstDayOfWeek(1);
-            mCalendarViewHolo.setShownWeekCount(4);
-            mCalendarViewHolo.setShowWeekNumber(true);
-            mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
-            mCalendarViewHolo.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
-            mCalendarViewHolo.setSelectedWeekBackgroundColor(newSelectedWeekBackgroundColor);
-            mCalendarViewHolo.setFocusedMonthDateColor(newFocusedMonthDateColor);
-            mCalendarViewHolo.setUnfocusedMonthDateColor(newUnfocusedMonthDataColor);
-            mCalendarViewHolo.setWeekNumberColor(newWeekNumberColor);
-            mCalendarViewHolo.setWeekSeparatorLineColor(newWeekSeparatorLineColor);
-        });
+        mCalendarViewHolo.setFirstDayOfWeek(Calendar.SUNDAY);
+        mCalendarViewHolo.setShownWeekCount(4);
+        mCalendarViewHolo.setShowWeekNumber(true);
+        mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
+        mCalendarViewHolo.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
+        mCalendarViewHolo.setSelectedWeekBackgroundColor(newSelectedWeekBackgroundColor);
+        mCalendarViewHolo.setFocusedMonthDateColor(newFocusedMonthDateColor);
+        mCalendarViewHolo.setUnfocusedMonthDateColor(newUnfocusedMonthDataColor);
+        mCalendarViewHolo.setWeekNumberColor(newWeekNumberColor);
+        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,14 +310,12 @@
         assertEquals(newWeekSeparatorLineColor,
                 mCalendarViewHolo.getWeekSeparatorLineColor());
 
-        instrumentation.runOnMainSync(
-                () -> mCalendarViewHolo.setSelectedDateVerticalBar(R.drawable.yellow_fill));
+        mCalendarViewHolo.setSelectedDateVerticalBar(R.drawable.yellow_fill);
         TestUtils.assertAllPixelsOfColor("Selected date vertical bar yellow",
                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFFFF00, 1, true);
 
-        instrumentation.runOnMainSync(
-                () -> mCalendarViewHolo.setSelectedDateVerticalBar(
-                        mActivity.getDrawable(R.drawable.magenta_fill)));
+        mCalendarViewHolo.setSelectedDateVerticalBar(
+                mActivity.getDrawable(R.drawable.magenta_fill));
         TestUtils.assertAllPixelsOfColor("Selected date vertical bar magenta",
                 mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFF00FF, 1, true);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
new file mode 100644
index 0000000..9ad0b23
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.CheckBox;
+
+/**
+ * A minimal application for {@link CheckBox} test.
+ */
+public class CheckBoxCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..cd265f9 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
@@ -16,44 +16,190 @@
 
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 import android.widget.CheckBox;
 
-public class CheckBoxTest extends AndroidTestCase {
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+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.
-        }
+    @UiThreadTest
+    @Test
+    public void testText() {
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.hello_world), mCheckBox.getText()));
+
+        mCheckBox.setText("new text");
+        assertTrue(TextUtils.equals("new text", mCheckBox.getText()));
+
+        mCheckBox.setText(R.string.text_name);
+        assertTrue(TextUtils.equals(mActivity.getString(R.string.text_name), mCheckBox.getText()));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessChecked() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // not checked -> not checked
+        mCheckBox.setChecked(false);
+        verifyZeroInteractions(mockCheckedChangeListener);
+        assertFalse(mCheckBox.isChecked());
+
+        // not checked -> checked
+        mCheckBox.setChecked(true);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // checked -> checked
+        mCheckBox.setChecked(true);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // checked -> not checked
+        mCheckBox.setChecked(false);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+        assertFalse(mCheckBox.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testToggleViaApi() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // toggle to checked
+        mCheckBox.toggle();
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // toggle to not checked
+        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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testToggleViaPerformClick() {
+        final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CheckBox.OnCheckedChangeListener.class);
+        mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mCheckBox.isChecked());
+
+        // click to checked
+        mCheckBox.performClick();
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+        assertTrue(mCheckBox.isChecked());
+
+        // click to not checked
+        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..6423af0 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.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.CheckedTextView;
 
 /**
- * A minimal application for CheckedTextView test.
+ * A minimal application for {@link CheckedTextView} test.
  */
 public class CheckedTextViewCtsActivity 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/CheckedTextViewTest.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
index 039ca70..da31c2d 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.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.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.view.View;
@@ -35,84 +43,92 @@
 import android.widget.CheckedTextView;
 import android.widget.ListAdapter;
 import android.widget.ListView;
+import android.widget.cts.util.TestUtils;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+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;
 
-    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);
     }
 
-    public void testChecked() {
-        final ListView lv = (ListView) mActivity.findViewById(R.id.checkedtextview_listview);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new CheckedTextView(null);
+    }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                lv.setAdapter(new CheckedTextViewAdapter());
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new CheckedTextView(null, null);
+    }
 
-                lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-                lv.setItemChecked(1, true);
-            }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new CheckedTextView(null, null, -1);
+    }
+
+    @Test
+    public void testChecked() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mListView.setAdapter(new CheckedTextViewAdapter());
+
+            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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+            mListView.setItemChecked(2, true);
         });
         mInstrumentation.waitForIdleSync();
         assertFalse(view0.isChecked());
@@ -127,58 +143,54 @@
         assertFalse(view2.isChecked());
     }
 
+    @UiThreadTest
+    @Test
     public void testToggle() {
-        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
-        assertFalse(checkedTextView.isChecked());
+        assertFalse(mCheckedTextView.isChecked());
 
-        checkedTextView.toggle();
-        assertTrue(checkedTextView.isChecked());
+        mCheckedTextView.toggle();
+        assertTrue(mCheckedTextView.isChecked());
 
-        checkedTextView.toggle();
-        assertFalse(checkedTextView.isChecked());
+        mCheckedTextView.toggle();
+        assertFalse(mCheckedTextView.isChecked());
 
-        checkedTextView.setChecked(true);
-        checkedTextView.toggle();
-        assertFalse(checkedTextView.isChecked());
+        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());
     }
 
-    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();
-            }
+    @Test
+    public void testSetPadding() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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();
+
+        mActivityRule.runOnUiThread(() -> {
+            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) {
@@ -188,124 +200,166 @@
         }
     }
 
+    @UiThreadTest
+    @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);
+        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());
+        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());
+
+        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);
+        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);
+        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);
+        mCheckedTextView.setCheckMarkDrawable(null);
+        assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+        assertTrue(mCheckedTextView.isLayoutRequested());
     }
 
+    @UiThreadTest
+    @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);
+        mCheckedTextView.setPadding(0, 0, basePaddingRight, 0);
+        Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        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);
+        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);
+        mCheckedTextView.setCheckMarkDrawable(secondDrawable);
         assertEquals(secondDrawable.getIntrinsicWidth() + basePaddingRight,
-                checkedTextView.getPaddingRight());
-        assertTrue(checkedTextView.isLayoutRequested());
+                mCheckedTextView.getPaddingRight());
+        assertTrue(mCheckedTextView.isLayoutRequested());
+
+        mCheckedTextView.setCheckMarkDrawable(null);
 
         // resId is 0
-        checkedTextView = new MockCheckedTextView(mActivity);
-        checkedTextView.setPadding(0, 0, basePaddingRight, 0);
-        cleanUpForceLayoutFlags(checkedTextView);
+        mCheckedTextView.setPadding(0, 0, basePaddingRight, 0);
+        cleanUpForceLayoutFlags(mCheckedTextView);
 
-        checkedTextView.setCheckMarkDrawable(0);
-        assertEquals(basePaddingRight, checkedTextView.getPaddingRight());
-        assertFalse(checkedTextView.isLayoutRequested());
+        mCheckedTextView.setCheckMarkDrawable(0);
+        assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+        assertFalse(mCheckedTextView.isLayoutRequested());
     }
 
+    @UiThreadTest
+    @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());
+        mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        mCheckedTextView.setCheckMarkDrawable(null);
+        mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+        assertNotNull(mCheckedTextView.getCheckMarkDrawable());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessInstanceState() {
-        CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
-        Parcelable state;
+        assertFalse(mCheckedTextView.isChecked());
+        assertFalse(mCheckedTextView.getFreezesText());
 
-        assertFalse(checkedTextView.isChecked());
-        assertFalse(checkedTextView.getFreezesText());
-
-        state = checkedTextView.onSaveInstanceState();
+        final Parcelable state = mCheckedTextView.onSaveInstanceState();
         assertNotNull(state);
-        assertFalse(checkedTextView.getFreezesText());
+        assertFalse(mCheckedTextView.getFreezesText());
 
-        checkedTextView.setChecked(true);
+        mCheckedTextView.setChecked(true);
 
-        checkedTextView.onRestoreInstanceState(state);
-        assertFalse(checkedTextView.isChecked());
-        assertTrue(checkedTextView.isLayoutRequested());
+        mCheckedTextView.onRestoreInstanceState(state);
+        assertFalse(mCheckedTextView.isChecked());
+        assertTrue(mCheckedTextView.isLayoutRequested());
     }
 
-    public void testOnDraw() {
-        // Do not test. Implementation details.
-    }
+    @Test
+    public void testCheckMarkTinting() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mCheckedTextView.setChecked(true));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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 +374,6 @@
             super(context, attrs, defStyle);
         }
 
-        public static int[] getSuperViewStateSet() {
-            return ENABLED_STATE_SET;
-        }
-
         @Override
         protected void drawableStateChanged() {
             super.drawableStateChanged();
@@ -340,24 +390,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..2ff415f 100644
--- a/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ChronometerTest.java
@@ -16,28 +16,53 @@
 
 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.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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 +71,50 @@
         new Chronometer(mActivity, null, 0);
     }
 
+    @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());
+    }
+
     @UiThreadTest
+    @Test
     public void testAccessBase() {
         Chronometer chronometer = mActivity.getChronometer();
         CharSequence oldText = chronometer.getText();
 
-        int expected = 100000;
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        chronometer.setBase(100000);
+        assertEquals(100000, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
 
-        expected = 100;
         oldText = chronometer.getText();
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        chronometer.setBase(100);
+        assertEquals(100, chronometer.getBase());
         assertNotSame(oldText, chronometer.getText());
 
-        expected = -1;
         oldText = chronometer.getText();
-        chronometer.setBase(expected);
-        assertEquals(expected, chronometer.getBase());
+        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());
+        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";
@@ -89,79 +128,100 @@
         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
-    }
-
+    @Test
+    @LargeTest
     public void testStartAndStop() throws Throwable {
         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());
-            }
+        // in the same thread with UI, that's why we use runOnUiThread here.
+        mActivityRule.runOnUiThread(() -> {
+            // 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());
-            }
+        // in the same thread with UI, that's why we use runOnUiThread here.
+        mActivityRule.runOnUiThread(() -> {
+            // 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()));
     }
 
+    @Test
+    @LargeTest
     public void testAccessOnChronometerTickListener() throws Throwable {
         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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            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() throws Throwable {
+        final Chronometer chronometer = mActivity.getChronometer();
+        final Chronometer.OnChronometerTickListener mockTickListener =
+                mock(Chronometer.OnChronometerTickListener.class);
 
-        public void onChronometerTick(Chronometer chronometer) {
-            mCalledOnChronometerTick = true;
-        }
+        mActivityRule.runOnUiThread(() -> {
+            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() throws Throwable {
+        final Chronometer chronometer = mActivity.getChronometer();
+        final Chronometer.OnChronometerTickListener mockTickListener =
+                mock(Chronometer.OnChronometerTickListener.class);
+
+        mActivityRule.runOnUiThread(() -> {
+            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/CompoundButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CompoundButtonCtsActivity.java
new file mode 100644
index 0000000..166c581
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/CompoundButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.CompoundButton;
+
+/**
+ * A minimal application for {@link CompoundButton} test.
+ */
+public class CompoundButtonCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.compoundbutton_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
index 34d94a5..b81b37c 100644
--- a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
@@ -16,163 +16,186 @@
 
 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 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 org.xmlpull.v1.XmlPullParser;
-
+import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
-import android.content.res.Resources;
+import android.content.res.ColorStateList;
 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.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.StateSet;
 import android.util.Xml;
 import android.view.Gravity;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
+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.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link CompoundButton}.
  */
-public class CompoundButtonTest extends AndroidTestCase {
-    private Resources mResources;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class CompoundButtonTest  {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private CompoundButton mCompoundButton;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mResources = mContext.getResources();
+    @Rule
+    public ActivityTestRule<CompoundButtonCtsActivity> mActivityRule =
+            new ActivityTestRule<>(CompoundButtonCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mCompoundButton = (CompoundButton) mActivity.findViewById(R.id.compound_button);
     }
 
+    @Test
     public void testConstructor() {
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.togglebutton_layout);
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.compoundbutton_layout);
         AttributeSet mAttrSet = Xml.asAttributeSet(parser);
 
-        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.
-        }
+        new MockCompoundButton(mActivity, mAttrSet, 0);
+        new MockCompoundButton(mActivity, mAttrSet);
+        new MockCompoundButton(mActivity);
     }
 
+    @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);
+    }
+
+    @UiThreadTest
+    @Test
     public void testAccessChecked() {
-        CompoundButton compoundButton = new MockCompoundButton(mContext);
-        MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        compoundButton.setOnCheckedChangeListener(listener);
-        assertFalse(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        CompoundButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CompoundButton.OnCheckedChangeListener.class);
+        mCompoundButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        assertFalse(mCompoundButton.isChecked());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
-        compoundButton.setChecked(true);
-        assertTrue(compoundButton.isChecked());
-        assertTrue(listener.hasCalledCheckedChange());
-        assertSame(compoundButton, listener.getInputCompoundButton());
-        assertTrue(listener.getInputChecked());
+        mCompoundButton.setChecked(true);
+        assertTrue(mCompoundButton.isChecked());
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, true);
 
-        listener.reset();
-        compoundButton.setChecked(true);
-        assertTrue(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        reset(mockCheckedChangeListener);
+        mCompoundButton.setChecked(true);
+        assertTrue(mCompoundButton.isChecked());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
-        compoundButton.setChecked(false);
-        assertFalse(compoundButton.isChecked());
-        assertTrue(listener.hasCalledCheckedChange());
-        assertSame(compoundButton, listener.getInputCompoundButton());
-        assertFalse(listener.getInputChecked());
+        mCompoundButton.setChecked(false);
+        assertFalse(mCompoundButton.isChecked());
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, false);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetOnCheckedChangeListener() {
-        CompoundButton compoundButton = new MockCompoundButton(mContext);
-        MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        compoundButton.setOnCheckedChangeListener(listener);
-        assertFalse(compoundButton.isChecked());
-        assertFalse(listener.hasCalledCheckedChange());
+        CompoundButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(CompoundButton.OnCheckedChangeListener.class);
+        mCompoundButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        assertFalse(mCompoundButton.isChecked());
+        verifyZeroInteractions(mockCheckedChangeListener);
 
-        compoundButton.setChecked(true);
-        assertTrue(listener.hasCalledCheckedChange());
+        mCompoundButton.setChecked(true);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCompoundButton, true);
 
         // set null
-        compoundButton.setOnCheckedChangeListener(null);
-        listener.reset();
-        compoundButton.setChecked(false);
-        assertFalse(listener.hasCalledCheckedChange());
+        mCompoundButton.setOnCheckedChangeListener(null);
+        reset(mockCheckedChangeListener);
+        mCompoundButton.setChecked(false);
+        verifyZeroInteractions(mockCheckedChangeListener);
     }
 
+    @UiThreadTest
+    @Test
     public void testToggle() {
-        CompoundButton compoundButton = new MockCompoundButton(mContext);
-        assertFalse(compoundButton.isChecked());
+        assertFalse(mCompoundButton.isChecked());
 
-        compoundButton.toggle();
-        assertTrue(compoundButton.isChecked());
+        mCompoundButton.toggle();
+        assertTrue(mCompoundButton.isChecked());
 
-        compoundButton.toggle();
-        assertFalse(compoundButton.isChecked());
+        mCompoundButton.toggle();
+        assertFalse(mCompoundButton.isChecked());
 
-        compoundButton.setChecked(true);
-        compoundButton.toggle();
-        assertFalse(compoundButton.isChecked());
+        mCompoundButton.setChecked(true);
+        mCompoundButton.toggle();
+        assertFalse(mCompoundButton.isChecked());
     }
 
+    @UiThreadTest
+    @Test
     public void testPerformClick() {
-        CompoundButton compoundButton = new MockCompoundButton(mContext);
-        assertFalse(compoundButton.isChecked());
+        assertFalse(mCompoundButton.isChecked());
 
         // performClick without OnClickListener will return false.
-        assertFalse(compoundButton.performClick());
-        assertTrue(compoundButton.isChecked());
+        assertFalse(mCompoundButton.performClick());
+        assertTrue(mCompoundButton.isChecked());
 
-        assertFalse(compoundButton.performClick());
-        assertFalse(compoundButton.isChecked());
+        assertFalse(mCompoundButton.performClick());
+        assertFalse(mCompoundButton.isChecked());
 
         // performClick with OnClickListener will return true.
-        compoundButton.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-            }
-        });
-        assertTrue(compoundButton.performClick());
-        assertTrue(compoundButton.isChecked());
+        mCompoundButton.setOnClickListener((view) -> {});
+        assertTrue(mCompoundButton.performClick());
+        assertTrue(mCompoundButton.isChecked());
 
-        assertTrue(compoundButton.performClick());
-        assertFalse(compoundButton.isChecked());
+        assertTrue(mCompoundButton.performClick());
+        assertFalse(mCompoundButton.isChecked());
     }
 
+    @UiThreadTest
+    @Test
     public void testDrawableStateChanged() {
-        MockCompoundButton compoundButton = new MockCompoundButton(mContext);
+        MockCompoundButton compoundButton = new MockCompoundButton(mActivity);
         assertFalse(compoundButton.isChecked());
         // drawableStateChanged without any drawables.
         compoundButton.drawableStateChanged();
 
         // drawableStateChanged when CheckMarkDrawable is not null.
-        Drawable drawable = mResources.getDrawable(R.drawable.statelistdrawable);
+        Drawable drawable = mActivity.getDrawable(R.drawable.statelistdrawable);
         compoundButton.setButtonDrawable(drawable);
         drawable.setState(null);
         assertNull(drawable.getState());
@@ -182,60 +205,56 @@
         assertSame(compoundButton.getDrawableState(), drawable.getState());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetButtonDrawableByDrawable() {
-        CompoundButton compoundButton;
-
         // set null drawable
-        compoundButton = new MockCompoundButton(mContext);
-        compoundButton.setButtonDrawable(null);
-        assertNull(compoundButton.getButtonDrawable());
+        mCompoundButton.setButtonDrawable(null);
+        assertNull(mCompoundButton.getButtonDrawable());
 
-        // set drawable when checkedTextView is GONE
-        compoundButton = new MockCompoundButton(mContext);
-        compoundButton.setVisibility(View.GONE);
-        Drawable firstDrawable = mResources.getDrawable(R.drawable.scenery);
+        // set drawable when button is GONE
+        mCompoundButton.setVisibility(View.GONE);
+        Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
         firstDrawable.setVisible(true, false);
         assertEquals(StateSet.WILD_CARD, firstDrawable.getState());
 
-        compoundButton.setButtonDrawable(firstDrawable);
-        assertSame(firstDrawable, compoundButton.getButtonDrawable());
+        mCompoundButton.setButtonDrawable(firstDrawable);
+        assertSame(firstDrawable, mCompoundButton.getButtonDrawable());
         assertFalse(firstDrawable.isVisible());
 
-        // update drawable when checkedTextView is VISIBLE
-        compoundButton.setVisibility(View.VISIBLE);
-        Drawable secondDrawable = mResources.getDrawable(R.drawable.pass);
+        // update drawable when button is VISIBLE
+        mCompoundButton.setVisibility(View.VISIBLE);
+        Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass);
         secondDrawable.setVisible(true, false);
         assertEquals(StateSet.WILD_CARD, secondDrawable.getState());
 
-        compoundButton.setButtonDrawable(secondDrawable);
-        assertSame(secondDrawable, compoundButton.getButtonDrawable());
+        mCompoundButton.setButtonDrawable(secondDrawable);
+        assertSame(secondDrawable, mCompoundButton.getButtonDrawable());
         assertTrue(secondDrawable.isVisible());
         // the firstDrawable is not active.
         assertFalse(firstDrawable.isVisible());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetButtonDrawableById() {
-        CompoundButton compoundButton;
         // resId is 0
-        compoundButton = new MockCompoundButton(mContext);
-        compoundButton.setButtonDrawable(0);
+        mCompoundButton.setButtonDrawable(0);
 
         // set drawable
-        compoundButton = new MockCompoundButton(mContext);
-        compoundButton.setButtonDrawable(R.drawable.scenery);
+        mCompoundButton.setButtonDrawable(R.drawable.scenery);
 
         // set the same drawable again
-        compoundButton.setButtonDrawable(R.drawable.scenery);
+        mCompoundButton.setButtonDrawable(R.drawable.scenery);
 
         // update drawable
-        compoundButton.setButtonDrawable(R.drawable.pass);
+        mCompoundButton.setButtonDrawable(R.drawable.pass);
     }
 
+    @Test
     public void testOnCreateDrawableState() {
-        MockCompoundButton compoundButton;
-
         // compoundButton is not checked, append 0 to state array.
-        compoundButton = new MockCompoundButton(mContext);
+        MockCompoundButton compoundButton = new MockCompoundButton(mActivity);
         int[] state = compoundButton.onCreateDrawableState(0);
         assertEquals(0, state[state.length - 1]);
 
@@ -252,6 +271,7 @@
         assertEquals(0, state[state.length - 1]);
     }
 
+    @Test
     public void testOnDraw() {
         int viewHeight;
         int drawableWidth;
@@ -263,12 +283,12 @@
         MockCompoundButton compoundButton;
 
         // onDraw when there is no drawable
-        compoundButton = new MockCompoundButton(mContext);
+        compoundButton = new MockCompoundButton(mActivity);
         compoundButton.onDraw(canvas);
 
         // onDraw when Gravity.TOP, it's default.
-        compoundButton = new MockCompoundButton(mContext);
-        drawable = mResources.getDrawable(R.drawable.scenery);
+        compoundButton = new MockCompoundButton(mActivity);
+        drawable = mActivity.getDrawable(R.drawable.scenery);
         compoundButton.setButtonDrawable(drawable);
         viewHeight = compoundButton.getHeight();
         drawableWidth = drawable.getIntrinsicWidth();
@@ -300,27 +320,29 @@
         assertEquals( (viewHeight - drawableHeight) / 2 + drawableHeight, bounds.bottom);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessInstanceState() {
-        CompoundButton compoundButton = new MockCompoundButton(mContext);
         Parcelable state;
 
-        assertFalse(compoundButton.isChecked());
-        assertFalse(compoundButton.getFreezesText());
+        assertFalse(mCompoundButton.isChecked());
+        assertFalse(mCompoundButton.getFreezesText());
 
-        state = compoundButton.onSaveInstanceState();
+        state = mCompoundButton.onSaveInstanceState();
         assertNotNull(state);
-        assertFalse(compoundButton.getFreezesText());
+        assertFalse(mCompoundButton.getFreezesText());
 
-        compoundButton.setChecked(true);
+        mCompoundButton.setChecked(true);
 
-        compoundButton.onRestoreInstanceState(state);
-        assertFalse(compoundButton.isChecked());
-        assertTrue(compoundButton.isLayoutRequested());
+        mCompoundButton.onRestoreInstanceState(state);
+        assertFalse(mCompoundButton.isChecked());
+        assertTrue(mCompoundButton.isLayoutRequested());
     }
 
+    @Test
     public void testVerifyDrawable() {
-        MockCompoundButton compoundButton = new MockCompoundButton(mContext);
-        Drawable drawable = mContext.getResources().getDrawable(R.drawable.scenery);
+        MockCompoundButton compoundButton = new MockCompoundButton(mActivity);
+        Drawable drawable = mActivity.getDrawable(R.drawable.scenery);
 
         assertTrue(compoundButton.verifyDrawable(null));
         assertFalse(compoundButton.verifyDrawable(drawable));
@@ -330,66 +352,34 @@
         assertTrue(compoundButton.verifyDrawable(drawable));
     }
 
+    @UiThreadTest
+    @Test
     public void testButtonTint() {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        View layout = inflater.inflate(R.layout.togglebutton_layout, null);
-        CompoundButton inflatedView = (CompoundButton) layout.findViewById(R.id.button_tint);
+        CompoundButton tintedButton = (CompoundButton) mActivity.findViewById(R.id.button_tint);
 
         assertEquals("Button tint inflated correctly",
-                Color.WHITE, inflatedView.getButtonTintList().getDefaultColor());
+                Color.WHITE, tintedButton.getButtonTintList().getDefaultColor());
         assertEquals("Button tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, inflatedView.getButtonTintMode());
+                PorterDuff.Mode.SRC_OVER, tintedButton.getButtonTintMode());
 
-        MockDrawable button = new MockDrawable();
-        CompoundButton view = new ToggleButton(mContext);
+        Drawable mockDrawable = spy(new ColorDrawable(Color.GREEN));
 
-        view.setButtonDrawable(button);
-        assertFalse("No button tint applied by default", button.hasCalledSetTint());
+        mCompoundButton.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());
+        mCompoundButton.setButtonTintList(ColorStateList.valueOf(Color.WHITE));
+        // Button tint applied when setButtonTintList() called after setButton()
+        verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
 
-        button.reset();
-        view.setButtonDrawable(null);
-        view.setButtonDrawable(button);
-        assertTrue("Button tint applied when setButtonTintList() called before setButton()",
-                button.hasCalledSetTint());
+        reset(mockDrawable);
+        mCompoundButton.setButtonDrawable(null);
+        mCompoundButton.setButtonDrawable(mockDrawable);
+        // Button tint applied when setButtonTintList() called before setButton()
+        verify(mockDrawable, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
     }
 
-    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 final class MockCompoundButton extends CompoundButton {
+    public static final class MockCompoundButton extends CompoundButton {
         public MockCompoundButton(Context context) {
             super(context);
         }
@@ -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/CursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
index 0e6fb4d..ff36bbd 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
@@ -16,19 +16,25 @@
 
 package android.widget.cts;
 
-import java.io.File;
+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 android.content.Context;
 import android.content.res.Resources.Theme;
-import android.cts.util.PollingCheck;
-import android.cts.util.TestThread;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Looper;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,12 +43,22 @@
 import android.widget.FilterQueryProvider;
 import android.widget.TextView;
 
-import android.widget.cts.R;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.TestThread;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
 
 /**
  * Test {@link CursorAdapter}.
  */
-public class CursorAdapterTest extends InstrumentationTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CursorAdapterTest {
     private static final long TEST_TIME_OUT = 5000;
     private static final int NUMBER_INDEX = 1;
     private static final String FIRST_NUMBER = "123";
@@ -60,10 +76,9 @@
     private MockCursorAdapter mMockCursorAdapter;
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE);
         mDatabaseFile = new File(dbDir, "database_test.db");
         if (mDatabaseFile.exists()) {
@@ -82,18 +97,18 @@
         assertNotNull(mParent);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         if (null != mCursor) {
             mCursor.close();
             mCursor = null;
         }
         mDatabase.close();
         mDatabaseFile.delete();
-        super.tearDown();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new MockCursorAdapter(mContext, mCursor);
 
@@ -105,6 +120,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testInit() {
         MockCursorAdapter cursorAdapter = new MockCursorAdapter(null, null, false);
         cursorAdapter.init(null, null, false);
@@ -150,6 +166,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCount() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         assertEquals(0, cursorAdapter.getCount());
@@ -159,6 +176,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessCursor() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         assertNull(cursorAdapter.getCursor());
@@ -171,6 +189,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConvertToString() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         assertEquals("", cursorAdapter.convertToString(null));
@@ -179,6 +198,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testHasStableIds() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
         assertTrue(cursorAdapter.hasStableIds());
@@ -188,6 +208,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetView() {
         TextView textView = new TextView(mContext);
         textView.setText("getView test");
@@ -220,6 +241,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testNewDropDownView() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
         // null cursor
@@ -230,6 +252,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetDropDownView() {
         MockCursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         // null cursor
@@ -252,6 +275,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessDropDownViewTheme() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         Theme theme = mContext.getResources().newTheme();
@@ -260,6 +284,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetFilter() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
         Filter filter = cursorAdapter.getFilter();
@@ -267,6 +292,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetItem() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         // cursor is null
@@ -285,6 +311,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetItemId() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
         // cursor is null
@@ -300,6 +327,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessFilterQueryProvider() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
         FilterQueryProvider filterProvider = new MockFilterQueryProvider();
@@ -312,6 +340,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testRunQueryOnBackgroundThread() {
         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
         final String constraint = "constraint";
@@ -325,14 +354,12 @@
         assertNull(cursorAdapter.runQueryOnBackgroundThread(constraint));
     }
 
+    @Test
     public void testOnContentChanged() throws Throwable {
-        TestThread testThread = new TestThread(new Runnable() {
-            public void run() {
-                Looper.prepare();
-                mMockCursorAdapter = new MockCursorAdapter(mContext, mCursor);
-            }
-        });
-        testThread.runTest(TEST_TIME_OUT);
+        new TestThread(() -> {
+            Looper.prepare();
+            mMockCursorAdapter = new MockCursorAdapter(mContext, mCursor);
+        }).runTest(TEST_TIME_OUT);
         assertFalse(mMockCursorAdapter.hasContentChanged());
         // insert a new row
         mDatabase.execSQL("INSERT INTO test (number) VALUES ('" + FIRST_NUMBER + "');");
diff --git a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
index 8ef414d..1084805 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
@@ -16,14 +16,27 @@
 
 package android.widget.cts;
 
-import java.io.File;
+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.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.content.Context;
 import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.database.sqlite.SQLiteDatabase;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,13 +45,19 @@
 import android.widget.FilterQueryProvider;
 import android.widget.TextView;
 
-import android.widget.cts.R;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.File;
 
 /**
  * Test {@link CursorTreeAdapter}.
  */
-public class CursorTreeAdapterTest extends InstrumentationTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CursorTreeAdapterTest {
     private static final int NAME_INDEX = 1;
     private static final int VALUE_INDEX = 1;
     private static final String GROUP_ONE         = "group_one";
@@ -92,10 +111,9 @@
         return mDatabase.query("child2", VALUE_PROJECTION, null, null, null, null, null);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE);
         mDatabaseFile = new File(dbDir, "database_test.db");
         if (mDatabaseFile.exists()) {
@@ -118,8 +136,8 @@
         assertNotNull(mParent);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() {
         if (null != mGroupCursor) {
             mGroupCursor.close();
             mGroupCursor = null;
@@ -136,10 +154,10 @@
         }
         mDatabase.close();
         mDatabaseFile.delete();
-        super.tearDown();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new MockCursorTreeAdapter(mGroupCursor, mContext);
 
@@ -151,6 +169,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCursor() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertSame(mGroupCursor, adapter.getCursor());
@@ -163,6 +182,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetGroupCursor() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertSame(mGroupCursor, adapter.getCursor());
@@ -175,6 +195,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetChildrenCursor() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertTrue(mGroupCursor.moveToFirst());
@@ -185,6 +206,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testChangeCursor() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext);
         assertNull(adapter.getCursor());
@@ -197,25 +219,26 @@
     }
 
     @UiThreadTest
+    @Test
     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 +246,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());
@@ -236,24 +259,25 @@
     }
 
     @UiThreadTest
+    @Test
     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());
@@ -262,24 +286,25 @@
     }
 
     @UiThreadTest
+    @Test
     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());
@@ -288,6 +313,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnGroupCollapsed() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
 
@@ -326,6 +352,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testHasStableIds() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertTrue(adapter.hasStableIds());
@@ -335,6 +362,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testIsChildSelectable() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertTrue(adapter.isChildSelectable(0, 0));
@@ -345,6 +373,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConvertToString() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertEquals("", adapter.convertToString(null));
@@ -353,6 +382,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetFilter() {
         MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         Filter filter = adapter.getFilter();
@@ -365,6 +395,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessQueryProvider() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         FilterQueryProvider filterProvider = new MockFilterQueryProvider();
@@ -377,6 +408,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testRunQueryOnBackgroundThread() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         final String constraint = "constraint";
@@ -391,6 +423,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetGroup() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext);
 
@@ -411,6 +444,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetGroupCount() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertEquals(mGroupCursor.getCount(), adapter.getGroupCount());
@@ -420,6 +454,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetGroupId() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext);
 
@@ -436,6 +471,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetGroupView() {
         final String expectedStr = "getGroupView test";
         TextView retView;
@@ -472,6 +508,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetChild() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext);
         assertEquals(2, adapter.getGroupCount());
@@ -500,6 +537,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetChildId() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext);
 
@@ -529,6 +567,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetChildrenCount() {
         CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext);
 
@@ -545,6 +584,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetChildView() {
         final String expectedStr = "getChildView test";
         TextView retView;
@@ -707,34 +747,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/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
new file mode 100644
index 0000000..81e6e69
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.DatePicker;
+
+/**
+ * A minimal application for {@link DatePicker} test.
+ */
+public class DatePickerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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 74d0ff5..c0aa95dc 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
@@ -16,85 +16,73 @@
 
 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.widget.DatePicker;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+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;
 
 /**
  * Test {@link DatePickerDialog}.
  */
-public class DatePickerDialogTest extends
-        ActivityInstrumentationTestCase2<DatePickerDialogCtsActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class DatePickerDialogTest {
     private Activity mActivity;
 
-    public DatePickerDialogTest() {
-        super(DatePickerDialogCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<DatePickerDialogCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DatePickerDialogCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
-    @SuppressWarnings("deprecation")
+    @Test
     public void testConstructor() {
         new DatePickerDialog(mActivity, null, 1970, 1, 1);
 
         new DatePickerDialog(mActivity, AlertDialog.THEME_TRADITIONAL, null, 1970, 1, 1);
 
-        // Ensure the picker is shown using the Holo-style layout.
-        DatePickerDialog holoDialog = new DatePickerDialog(mActivity, AlertDialog.THEME_HOLO_DARK,
-                null, 1970, 1, 1);
-        assertEquals(DatePicker.MODE_SPINNER, holoDialog.getDatePicker().getMode());
-
-        // Ensure the picker is shown using the Material-style layout where available.
-        DatePickerDialog holoCalendarDialog = new DatePickerDialog(mActivity,
-                R.style.Theme_Holo_With_Material_Pickers, null, 1970, 1, 1);
-        final int expectedMode = mActivity.getResources().getInteger(R.integer.date_picker_mode);
-        assertEquals(expectedMode, holoCalendarDialog.getDatePicker().getMode());
+        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) {
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        new DatePickerDialog(null, null, 1970, 1, 1);
+    }
+
+    @UiThreadTest
+    @Test
     public void testShowDismiss() {
-        DatePickerDialog d = createDatePickerDialog();
+        final DatePickerDialog datePickerDialog = new DatePickerDialog(mActivity, null, 1970, 1, 1);
 
-        d.show();
-        assertTrue("Showing date picker", d.isShowing());
+        datePickerDialog.show();
+        assertTrue("Showing date picker", datePickerDialog.isShowing());
 
-        d.show();
-        assertTrue("Date picker still showing", d.isShowing());
+        datePickerDialog.show();
+        assertTrue("Date picker still showing", datePickerDialog.isShowing());
 
-        d.dismiss();
-        assertFalse("Dismissed date picker", d.isShowing());
+        datePickerDialog.dismiss();
+        assertFalse("Dismissed date picker", datePickerDialog.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);
-        }
+        datePickerDialog.dismiss();
+        assertFalse("Date picker still dismissed", datePickerDialog.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..a45ac2b 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
@@ -16,92 +16,164 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+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.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.app.Activity;
 import android.content.Context;
-import android.content.res.XmlResourceParser;
 import android.os.Parcelable;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
-import android.util.Xml;
 import android.view.View;
 import android.widget.DatePicker;
-import android.widget.cts.util.XmlUtils;
+
+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;
 
 /**
  * Test {@link DatePicker}.
  */
-public class DatePickerTest extends InstrumentationTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class DatePickerTest {
+    private Activity mActivity;
+    private DatePicker mDatePickerSpinnerMode;
+    private DatePicker mDatePickerCalendarMode;
 
-    private Context mContext;
+    @Rule
+    public ActivityTestRule<DatePickerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DatePickerCtsActivity.class);
 
-    @Override
+    @Before
     public void setUp() {
-        mContext = getInstrumentation().getTargetContext();
+        mActivity = mActivityRule.getActivity();
+        mDatePickerSpinnerMode = (DatePicker) mActivity.findViewById(R.id.date_picker_spinner_mode);
+        mDatePickerCalendarMode =
+                (DatePicker) mActivity.findViewById(R.id.date_picker_calendar_mode);
     }
 
-    @UiThreadTest
+    @Test
     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
+    @Test
     public void testSetEnabled() {
-        MockDatePicker datePicker = createDatePicker();
+        assertTrue(mDatePickerCalendarMode.isEnabled());
 
-        assertTrue(datePicker.isEnabled());
+        mDatePickerCalendarMode.setEnabled(false);
+        assertFalse(mDatePickerCalendarMode.isEnabled());
 
-        datePicker.setEnabled(false);
-        assertFalse(datePicker.isEnabled());
+        mDatePickerCalendarMode.setEnabled(true);
+        assertTrue(mDatePickerCalendarMode.isEnabled());
+    }
 
-        datePicker.setEnabled(true);
-        assertTrue(datePicker.isEnabled());
+    private void verifyInit(DatePicker datePicker) {
+        final DatePicker.OnDateChangedListener mockDateChangeListener =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        datePicker.init(2000, 10, 15, mockDateChangeListener);
+        assertEquals(2000, datePicker.getYear());
+        assertEquals(10, datePicker.getMonth());
+        assertEquals(15, datePicker.getDayOfMonth());
+
+        verifyZeroInteractions(mockDateChangeListener);
     }
 
     @UiThreadTest
+    @Test
     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 DatePicker.OnDateChangedListener mockDateChangeListener =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        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());
+
+        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
+    @Test
     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 DatePicker.OnDateChangedListener mockDateChangeListener1 =
+                mock(DatePicker.OnDateChangedListener.class);
+        final DatePicker.OnDateChangedListener mockDateChangeListener2 =
+                mock(DatePicker.OnDateChangedListener.class);
+
+        datePicker.init(2000, 10, 15, mockDateChangeListener1);
+        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);
+
+        datePicker.setOnDateChangedListener(mockDateChangeListener2);
+        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);
+    }
 
+    @UiThreadTest
+    @Test
+    public void testSetOnDateChangedListener() {
+        verifySetOnDateChangedListener(mDatePickerSpinnerMode);
+        verifySetOnDateChangedListener(mDatePickerCalendarMode);
+    }
+
+    private void verifyUpdateDate(DatePicker datePicker) {
         datePicker.updateDate(1989, 9, 19);
         assertEquals(1989, datePicker.getYear());
         assertEquals(9, datePicker.getMonth());
@@ -109,27 +181,108 @@
     }
 
     @UiThreadTest
+    @Test
     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) {
+        // 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();
+
+        datePicker.setMinDate(minDate);
+        datePicker.setMaxDate(maxDate);
+
+        assertEquals(datePicker.getMinDate(), minDate);
+        assertEquals(datePicker.getMaxDate(), maxDate);
     }
 
     @UiThreadTest
-    public void testOnSaveInstanceState() {
-        MockDatePicker datePicker = createDatePicker();
+    @Test
+    public void testMinMaxDate() {
+        verifyMinMaxDate(mDatePickerSpinnerMode);
+        verifyMinMaxDate(mDatePickerCalendarMode);
+    }
+
+    private void verifyFirstDayOfWeek(DatePicker datePicker) {
+        datePicker.setFirstDayOfWeek(Calendar.TUESDAY);
+        assertEquals(Calendar.TUESDAY, datePicker.getFirstDayOfWeek());
+
+        datePicker.setFirstDayOfWeek(Calendar.SUNDAY);
+        assertEquals(Calendar.SUNDAY, datePicker.getFirstDayOfWeek());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testFirstDayOfWeek() {
+        verifyFirstDayOfWeek(mDatePickerSpinnerMode);
+        verifyFirstDayOfWeek(mDatePickerCalendarMode);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testCalendarViewInSpinnerMode() {
+        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);
+        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));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testPartsVisibilityInSpinnerMode() {
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        mDatePickerSpinnerMode.setSpinnersShown(false);
+        assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        mDatePickerSpinnerMode.setCalendarViewShown(false);
+        assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+        assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        mDatePickerSpinnerMode.setSpinnersShown(true);
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+        mDatePickerSpinnerMode.setCalendarViewShown(true);
+        assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+        assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+    }
+
+    @UiThreadTest
+    @Test
+    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 +290,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 +334,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..f7f6bc7 100644
--- a/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DialerFilterTest.java
@@ -16,55 +16,65 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
 
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.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.verifyZeroInteractions;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.text.Editable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Spannable;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
-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;
 
-public class DialerFilterTest extends ActivityInstrumentationTestCase2<DialerFilterCtsActivity> {
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+
+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 DialerFilterTest {
     private Activity mActivity;
     private Instrumentation mInstrumentation;
     private DialerFilter mDialerFilter;
 
-    public DialerFilterTest() {
-        super("android.widget.cts", DialerFilterCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<DialerFilterCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DialerFilterCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
 
         mDialerFilter = (DialerFilter) mActivity.findViewById(R.id.dialer_filter);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         final XmlPullParser parser = mActivity.getResources().getXml(R.layout.dialerfilter_layout);
         final AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -74,34 +84,32 @@
     }
 
     @UiThreadTest
+    @Test
     public void testIsQwertyKeyboard() {
         // Simply call the method. Return value may depend on the default keyboard.
         mDialerFilter.isQwertyKeyboard();
     }
 
-    public void testOnKeyUpDown() {
+    @Test
+    public void testOnKeyUpDown() throws Throwable {
         // The exact behavior depends on the implementation of DialerKeyListener and
         // TextKeyListener, but even that may be changed. Simply assert basic scenarios.
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mDialerFilter.setMode(DialerFilter.DIGITS_ONLY);
-                mDialerFilter.requestFocus();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mDialerFilter.setMode(DialerFilter.DIGITS_ONLY);
+            mDialerFilter.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mDialerFilter.hasFocus());
 
-        mInstrumentation.sendStringSync("123");
+        CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "123");
         assertEquals("", mDialerFilter.getLetters().toString());
         assertEquals("123", mDialerFilter.getDigits().toString());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mDialerFilter.clearText();
-                mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mDialerFilter.clearText();
+            mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
         });
         mInstrumentation.waitForIdleSync();
 
@@ -110,47 +118,44 @@
                 = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
             // "adg" in case of 12-key(NUMERIC) keyboard
-            mInstrumentation.sendStringSync("234");
+            CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "234");
         }
         else {
-            mInstrumentation.sendStringSync("adg");
+            CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "adg");
         }
         assertEquals("ADG", mDialerFilter.getLetters().toString());
         assertEquals("", mDialerFilter.getDigits().toString());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mDialerFilter.clearText();
-                mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mDialerFilter.clearText();
+            mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS);
         });
         mInstrumentation.waitForIdleSync();
 
         // 12-key support
         if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
             // "adg" in case of 12-key(NUMERIC) keyboard
-            mInstrumentation.sendStringSync("234");
+            CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "234");
         }
         else {
-            mInstrumentation.sendStringSync("adg");
+            CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "adg");
         }
         assertEquals("ADG", mDialerFilter.getLetters().toString());
         // A, D, K may map to numbers on some keyboards. Don't test.
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mDialerFilter.clearText();
-                mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mDialerFilter.clearText();
+            mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS);
         });
         mInstrumentation.waitForIdleSync();
 
-        mInstrumentation.sendStringSync("123");
+        CtsKeyEventUtil.sendString(mInstrumentation, mDialerFilter, "123");
         // 1, 2, 3 may map to letters on some keyboards. Don't test.
         assertEquals("123", mDialerFilter.getDigits().toString());
     }
 
     @UiThreadTest
+    @Test
     public void testAccessMode() {
         mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS_NO_LETTERS);
         assertEquals(DialerFilter.DIGITS_AND_LETTERS_NO_LETTERS, mDialerFilter.getMode());
@@ -163,6 +168,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetLetters() {
         assertEquals("", mDialerFilter.getLetters().toString());
 
@@ -172,6 +178,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetDigits() {
         assertEquals("", mDialerFilter.getDigits().toString());
 
@@ -181,6 +188,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetFilterText() {
         assertEquals("", mDialerFilter.getFilterText().toString());
 
@@ -196,6 +204,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend() {
         mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
         mDialerFilter.append("ANDROID");
@@ -236,16 +245,17 @@
         assertEquals("", mDialerFilter.getLetters().toString());
         assertEquals("", mDialerFilter.getDigits().toString());
         assertEquals("", mDialerFilter.getFilterText().toString());
-
-        try {
-            mDialerFilter.append(null);
-            fail("A NullPointerException should be thrown out.");
-        } catch (final NullPointerException e) {
-            // expected, test success.
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAppendNull() {
+        mDialerFilter.setMode(DialerFilter.DIGITS_AND_LETTERS);
+        mDialerFilter.append(null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testClearText() {
         assertEquals("", mDialerFilter.getLetters().toString());
         assertEquals("", mDialerFilter.getDigits().toString());
@@ -262,112 +272,116 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetLettersWatcher() {
-        MockTextWatcher tw = new MockTextWatcher("A");
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
 
         Spannable span = (Spannable) mDialerFilter.getLetters();
-        assertEquals(-1, span.getSpanStart(tw));
-        assertEquals(-1, span.getSpanEnd(tw));
+        assertEquals(-1, span.getSpanStart(mockTextWatcher));
+        assertEquals(-1, span.getSpanEnd(mockTextWatcher));
 
         mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
-        mDialerFilter.setLettersWatcher(tw);
+        mDialerFilter.setLettersWatcher(mockTextWatcher);
         mDialerFilter.append("ANDROID");
-        assertEquals("ANDROID", tw.getText());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("ANDROID"), eq(0),
+                eq(0), eq(7));
 
         span = (Spannable) mDialerFilter.getLetters();
-        assertEquals(0, span.getSpanStart(tw));
-        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(tw));
+        assertEquals(0, span.getSpanStart(mockTextWatcher));
+        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(mockTextWatcher));
         assertEquals("ANDROID", span.toString());
 
-        tw = new MockTextWatcher("");
-        mDialerFilter.setLettersWatcher(tw);
+        reset(mockTextWatcher);
+        mDialerFilter.setLettersWatcher(mockTextWatcher);
         mDialerFilter.append("");
-        assertEquals("", tw.getText());
-
-        try {
-            mDialerFilter.setLettersWatcher(new MockTextWatcher(null));
-            mDialerFilter.append(null);
-            fail("A NullPointerException should be thrown out.");
-        } catch (final NullPointerException e) {
-            // expected, test success.
-        }
+        verifyZeroInteractions(mockTextWatcher);
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testSetLettersWatcherWithNullAppend() {
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+
+        mDialerFilter.setLettersWatcher(mockTextWatcher);
+        mDialerFilter.append(null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetDigitsWatcher() {
-        final MockTextWatcher tw = new MockTextWatcher("9");
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
 
         Spannable span = (Spannable) mDialerFilter.getDigits();
-        assertEquals(-1, span.getSpanStart(tw));
-        assertEquals(-1, span.getSpanEnd(tw));
+        assertEquals(-1, span.getSpanStart(mockTextWatcher));
+        assertEquals(-1, span.getSpanEnd(mockTextWatcher));
 
-        mDialerFilter.setDigitsWatcher(tw);
-        assertEquals(0, span.getSpanStart(tw));
-        assertEquals(mDialerFilter.getDigits().length(), span.getSpanEnd(tw));
+        mDialerFilter.setDigitsWatcher(mockTextWatcher);
+        assertEquals(0, span.getSpanStart(mockTextWatcher));
+        assertEquals(mDialerFilter.getDigits().length(), span.getSpanEnd(mockTextWatcher));
 
         mDialerFilter.setMode(DialerFilter.DIGITS_ONLY);
         mDialerFilter.append("12345");
-        assertEquals("12345", tw.getText());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("12345"), eq(0),
+                eq(0), eq(5));
     }
 
     @UiThreadTest
+    @Test
     public void testSetFilterWatcher() {
-        final MockTextWatcher tw = new MockTextWatcher("A");
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
 
         Spannable span = (Spannable) mDialerFilter.getLetters();
-        assertEquals(-1, span.getSpanStart(tw));
-        assertEquals(-1, span.getSpanEnd(tw));
+        assertEquals(-1, span.getSpanStart(mockTextWatcher));
+        assertEquals(-1, span.getSpanEnd(mockTextWatcher));
 
         mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
-        mDialerFilter.setFilterWatcher(tw);
+        mDialerFilter.setFilterWatcher(mockTextWatcher);
         mDialerFilter.append("ANDROID");
-        assertEquals("ANDROID", tw.getText());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("ANDROID"), eq(0),
+                eq(0), eq(7));
         span = (Spannable) mDialerFilter.getLetters();
 
-        assertEquals(0, span.getSpanStart(tw));
-        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(tw));
+        assertEquals(0, span.getSpanStart(mockTextWatcher));
+        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(mockTextWatcher));
 
         mDialerFilter.setMode(DialerFilter.DIGITS_ONLY);
-        mDialerFilter.setFilterWatcher(tw);
+        mDialerFilter.setFilterWatcher(mockTextWatcher);
         mDialerFilter.append("12345");
-        assertEquals("12345", tw.getText());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("12345"), eq(0),
+                eq(0), eq(5));
     }
 
     @UiThreadTest
+    @Test
     public void testRemoveFilterWatcher() {
-        final MockTextWatcher tw = new MockTextWatcher("A");
+        final TextWatcher mockTextWatcher = mock(TextWatcher.class);
 
         Spannable span = (Spannable) mDialerFilter.getLetters();
-        assertEquals(-1, span.getSpanStart(tw));
-        assertEquals(-1, span.getSpanEnd(tw));
+        assertEquals(-1, span.getSpanStart(mockTextWatcher));
+        assertEquals(-1, span.getSpanEnd(mockTextWatcher));
 
         mDialerFilter.setMode(DialerFilter.LETTERS_ONLY);
-        mDialerFilter.setFilterWatcher(tw);
+        mDialerFilter.setFilterWatcher(mockTextWatcher);
         mDialerFilter.append("ANDROID");
-        assertEquals("ANDROID", tw.getText());
+        verify(mockTextWatcher, times(1)).onTextChanged(sameCharSequence("ANDROID"), eq(0),
+                eq(0), eq(7));
 
         span = (Spannable) mDialerFilter.getLetters();
-        assertEquals(0, span.getSpanStart(tw));
-        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(tw));
+        assertEquals(0, span.getSpanStart(mockTextWatcher));
+        assertEquals(mDialerFilter.getLetters().length(), span.getSpanEnd(mockTextWatcher));
 
-        mDialerFilter.removeFilterWatcher(tw);
+        reset(mockTextWatcher);
+        mDialerFilter.removeFilterWatcher(mockTextWatcher);
         mDialerFilter.append("GOLF");
-        assertEquals("ANDROID", tw.getText());
+        verifyZeroInteractions(mockTextWatcher);
 
-        assertEquals(-1, span.getSpanStart(tw));
-        assertEquals(-1, span.getSpanEnd(tw));
-    }
-
-    public void testOnFinishInflate() {
-        // onFinishInflate() is implementation details, do NOT test
-    }
-
-    public void testOnFocusChanged() {
-        // onFocusChanged() is implementation details, do NOT test
+        assertEquals(-1, span.getSpanStart(mockTextWatcher));
+        assertEquals(-1, span.getSpanEnd(mockTextWatcher));
     }
 
     @UiThreadTest
-    public void testOnModechange() {
+    @Test
+    public void testOnModeChange() {
         final MockDialerFilter dialerFilter = createMyDialerFilter();
         dialerFilter.onFinishInflate();
 
@@ -401,33 +415,6 @@
         return dialerFilter;
     }
 
-    private class MockTextWatcher implements TextWatcher {
-        private String mString;
-
-        public MockTextWatcher(final String s) {
-            mString = s;
-        }
-
-        public void beforeTextChanged(final CharSequence s, final int start, final int count,
-                final int after) {
-            Log.d("DialerFilterTest", "MockTextWatcher beforeTextChanged");
-        }
-
-        public void onTextChanged(final CharSequence s, final int start, final int before,
-                final int count) {
-            Log.d("DialerFilterTest", "MockTextWatcher onTextChanged");
-            mString = s.toString();
-        }
-
-        public void afterTextChanged(final Editable s) {
-            Log.d("DialerFilterTest", "MockTextWatcher afterTextChanged");
-        }
-
-        public String getText() {
-            return mString;
-        }
-    }
-
     /**
      * MockDialerFilter for test
      */
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..6c9f512 100644
--- a/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DigitalClockTest.java
@@ -16,64 +16,70 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.DigitalClock;
 import android.widget.LinearLayout;
 import android.widget.cts.util.XmlUtils;
 
-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.XmlPullParserException;
 
+import java.io.IOException;
 
 /**
  * Test {@link DigitalClock}.
  */
-public class DigitalClockTest extends ActivityInstrumentationTestCase<DigitalClockCtsActivity> {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DigitalClockTest {
     private Activity mActivity;
-    private Context mContext;
 
-    public DigitalClockTest() {
-        super("android.widget.cts", DigitalClockCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<DigitalClockCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DigitalClockCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mContext = getInstrumentation().getContext();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         // new the DigitalClock instance
-        new DigitalClock(mContext);
+        new DigitalClock(mActivity);
 
         // new the DigitalClock instance with null AttributeSet
-        new DigitalClock(mContext, null);
+        new DigitalClock(mActivity, null);
 
         // new the DigitalClock instance with real AttributeSet
-        new DigitalClock(mContext, getAttributeSet(R.layout.digitalclock_layout));
-
-        // Test constructor with null Context, in fact, DigitalClock(mContext) function will
-        //finally invoke this version.
-        try {
-            // Test with null Context
-            new DigitalClock(null, getAttributeSet(R.layout.digitalclock_layout));
-            fail("should throw NullPointerException");
-        } catch (Exception e) {
-        }
+        new DigitalClock(mActivity, getAttributeSet(R.layout.digitalclock_layout));
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext() {
+        new DigitalClock(null, getAttributeSet(R.layout.digitalclock_layout));
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnDetachedFromWindow() {
         final MockDigitalClock digitalClock = createDigitalClock();
 
@@ -88,6 +94,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnAttachedToWindow() {
         final MockDigitalClock digitalClock = createDigitalClock();
 
@@ -105,7 +112,7 @@
     }
 
     private MockDigitalClock createDigitalClock() {
-        MockDigitalClock datePicker = new MockDigitalClock(mContext,
+        MockDigitalClock datePicker = new MockDigitalClock(mActivity,
                 getAttributeSet(R.layout.digitalclock_layout));
 
         return datePicker;
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextCtsActivity.java b/tests/tests/widget/src/android/widget/cts/EditTextCtsActivity.java
new file mode 100644
index 0000000..5915fd6
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/EditTextCtsActivity.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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.EditText;
+
+/**
+ * A minimal application for {@link EditText} test.
+ */
+public class EditTextCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.edittext_layout);
+    }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index acf5f38..5dfefb3 100644
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -16,205 +16,231 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+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 android.app.Activity;
 import android.content.Context;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
 import android.util.Xml;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
-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 EditTextTest extends AndroidTestCase {
-    private Context mContext;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EditTextTest {
+    private Activity mActivity;
+    private EditText mEditText1;
+    private EditText mEditText2;
     private AttributeSet mAttributeSet;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Rule
+    public ActivityTestRule<EditTextCtsActivity> mActivityRule =
+            new ActivityTestRule<>(EditTextCtsActivity.class);
 
-        mContext = getContext();
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.edittext_layout);
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mEditText1 = (EditText) mActivity.findViewById(R.id.edittext_simple1);
+        mEditText2 = (EditText) mActivity.findViewById(R.id.edittext_simple2);
+
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.edittext_layout);
         mAttributeSet = Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructor() {
-        new EditText(mContext);
+        new EditText(mActivity);
 
-        new EditText(mContext, null);
+        new EditText(mActivity, null);
 
-        new EditText(mContext, null, 0);
+        new EditText(mActivity, null, 0);
 
-        new EditText(mContext, mAttributeSet);
+        new EditText(mActivity, mAttributeSet);
 
-        new EditText(mContext, mAttributeSet, 0);
-
-        try {
-            new EditText(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new EditText(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new EditText(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        new EditText(mActivity, mAttributeSet, 0);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new EditText(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new EditText(null, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testAccessText() {
-        EditText editText = new EditText(mContext, mAttributeSet);
+        mEditText1.setText("android", BufferType.NORMAL);
+        assertTrue(TextUtils.equals("android", mEditText1.getText()));
 
-        editText.setText("android", BufferType.NORMAL);
-        assertEquals("android", editText.getText().toString());
+        mEditText1.setText("", BufferType.SPANNABLE);
+        assertEquals(0, mEditText1.getText().length());
 
-        editText.setText("", BufferType.SPANNABLE);
-        assertEquals("", editText.getText().toString());
-
-        editText.setText(null, BufferType.EDITABLE);
-        assertEquals("", editText.getText().toString());
+        mEditText1.setText(null, BufferType.EDITABLE);
+        assertEquals(0, mEditText1.getText().length());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetSelectionIndex() {
-        EditText editText = new EditText(mContext, mAttributeSet);
-
-        String string = "android";
-        editText.setText(string, BufferType.EDITABLE);
+        mEditText1.setText("android", BufferType.EDITABLE);
         int position = 4;
-        editText.setSelection(position);
-        assertEquals(position, editText.getSelectionStart());
-        assertEquals(position, editText.getSelectionEnd());
+        mEditText1.setSelection(position);
+        assertEquals(position, mEditText1.getSelectionStart());
+        assertEquals(position, mEditText1.getSelectionEnd());
 
         position = 0;
-        editText.setSelection(position);
-        assertEquals(position, editText.getSelectionStart());
-        assertEquals(position, editText.getSelectionEnd());
-
-        try {
-            editText.setSelection(-1);
-            fail("An IndexOutOfBoundsException should be thrown out.");
-        } catch (IndexOutOfBoundsException e) {
-            //expected, test success.
-        }
-
-        try {
-            editText.setSelection(string.length() + 1);
-            fail("An IndexOutOfBoundsException should be thrown out.");
-        } catch (IndexOutOfBoundsException e) {
-            //expected, test success.
-        }
+        mEditText1.setSelection(position);
+        assertEquals(position, mEditText1.getSelectionStart());
+        assertEquals(position, mEditText1.getSelectionEnd());
     }
 
-    public void testSetSelectionStartstop() {
-        EditText editText = new EditText(mContext, mAttributeSet);
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetSelectionIndexBeforeFirst() {
+        mEditText1.setText("android", BufferType.EDITABLE);
+        mEditText1.setSelection(-1);
+    }
 
-        String string = "android";
-        editText.setText(string, BufferType.EDITABLE);
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetSelectionIndexAfterLast() {
+        mEditText1.setText("android", BufferType.EDITABLE);
+        mEditText1.setSelection(mEditText1.getText().length() + 1);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetSelectionStartEnd() {
+        mEditText1.setText("android", BufferType.EDITABLE);
         int start = 1;
         int end = 2;
-        editText.setSelection(start, end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
+        mEditText1.setSelection(start, end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
 
         start = 0;
         end = 0;
-        editText.setSelection(start, end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
+        mEditText1.setSelection(start, end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
 
         start = 7;
         end = 1;
-        editText.setSelection(start, end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
-
-        try {
-            editText.setSelection(-5, -1);
-            fail("An IndexOutOfBoundsException should be thrown out.");
-        } catch (IndexOutOfBoundsException e) {
-            //expected, test success.
-        }
-
-        try {
-            editText.setSelection(5, string.length() + 1);
-            fail("An IndexOutOfBoundsException should be thrown out.");
-        } catch (IndexOutOfBoundsException e) {
-            //expected, test success.
-        }
+        mEditText1.setSelection(start, end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetSelectionStartEndBeforeFirst() {
+        mEditText1.setText("android", BufferType.EDITABLE);
+        mEditText1.setSelection(-5, -1);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testSetSelectionStartEndAfterLast() {
+        mEditText1.setText("android", BufferType.EDITABLE);
+        mEditText1.setSelection(5, mEditText1.getText().length() + 1);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSelectAll() {
-        EditText editText = new EditText(mContext, mAttributeSet);
-
         String string = "android";
-        editText.setText(string, BufferType.EDITABLE);
-        editText.selectAll();
-        assertEquals(0, editText.getSelectionStart());
-        assertEquals(string.length(), editText.getSelectionEnd());
+        mEditText1.setText(string, BufferType.EDITABLE);
+        mEditText1.selectAll();
+        assertEquals(0, mEditText1.getSelectionStart());
+        assertEquals(string.length(), mEditText1.getSelectionEnd());
 
-        editText.setText("", BufferType.EDITABLE);
-        editText.selectAll();
-        assertEquals(0, editText.getSelectionStart());
-        assertEquals(0, editText.getSelectionEnd());
+        mEditText1.setText("", BufferType.EDITABLE);
+        mEditText1.selectAll();
+        assertEquals(0, mEditText1.getSelectionStart());
+        assertEquals(0, mEditText1.getSelectionEnd());
 
-        editText.setText(null, BufferType.EDITABLE);
-        editText.selectAll();
-        assertEquals(0, editText.getSelectionStart());
-        assertEquals(0, editText.getSelectionEnd());
+        mEditText1.setText(null, BufferType.EDITABLE);
+        mEditText1.selectAll();
+        assertEquals(0, mEditText1.getSelectionStart());
+        assertEquals(0, mEditText1.getSelectionEnd());
     }
 
+    @UiThreadTest
+    @Test
     public void testExtendSelection() {
-        EditText editText = new EditText(mContext, mAttributeSet);
-
-        editText.setText("android", BufferType.EDITABLE);
+        mEditText1.setText("android", BufferType.EDITABLE);
         int start = 0;
         int end = 0;
-        editText.setSelection(start, end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
+        mEditText1.setSelection(start, end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
 
         end = 6;
-        editText.extendSelection(end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
+        mEditText1.extendSelection(end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
 
         start = 0;
         end = 0;
-        editText.setSelection(start);
-        editText.extendSelection(end);
-        assertEquals(start, editText.getSelectionStart());
-        assertEquals(end, editText.getSelectionEnd());
-
-        try {
-            editText.setSelection(0, 4);
-            editText.extendSelection(10);
-            fail("An IndexOutOfBoundsException should be thrown out.");
-        } catch (IndexOutOfBoundsException e) {
-            //expected, test success.
-        }
+        mEditText1.setSelection(start);
+        mEditText1.extendSelection(end);
+        assertEquals(start, mEditText1.getSelectionStart());
+        assertEquals(end, mEditText1.getSelectionEnd());
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testExtendSelectionBeyondLast() {
+        mEditText1.setText("android", BufferType.EDITABLE);
+        mEditText1.setSelection(0, 4);
+        mEditText1.extendSelection(10);
+    }
+
+    @Test
     public void testGetDefaultEditable() {
-        MockEditText mockEditText = new MockEditText(mContext, mAttributeSet);
+        MockEditText mockEditText = new MockEditText(mActivity, mAttributeSet);
 
         assertTrue(mockEditText.getDefaultEditable());
     }
 
+    @Test
+    public void testAutoSizeNotSupported() {
+        DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+        EditText autoSizeEditText = (EditText) mActivity.findViewById(R.id.edittext_autosize);
+
+        // If auto-size would work then the text size would be less then 50dp (the value set in the
+        // layout file).
+        final float sizeSetInPixels = TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 50f, metrics);
+        assertEquals(sizeSetInPixels, autoSizeEditText.getTextSize(), 0f);
+    }
+
+    @Test
     public void testGetDefaultMovementMethod() {
-        MockEditText mockEditText = new MockEditText(mContext, mAttributeSet);
+        MockEditText mockEditText = new MockEditText(mActivity, mAttributeSet);
         MovementMethod method1 = mockEditText.getDefaultMovementMethod();
         MovementMethod method2 = mockEditText.getDefaultMovementMethod();
 
@@ -224,91 +250,87 @@
         assertSame(method1, method2);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetEllipsize() {
-        EditText editText = new EditText(mContext);
-        assertNull(editText.getEllipsize());
+        assertNull(mEditText1.getEllipsize());
 
-        editText.setEllipsize(TextUtils.TruncateAt.START);
-        assertSame(TextUtils.TruncateAt.START, editText.getEllipsize());
-
-        try {
-            editText.setEllipsize(TextUtils.TruncateAt.MARQUEE);
-            fail("Should throw IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-            // expected, test success.
-        }
+        mEditText1.setEllipsize(TextUtils.TruncateAt.START);
+        assertSame(TextUtils.TruncateAt.START, mEditText1.getEllipsize());
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testSetEllipsizeMarquee() {
+        mEditText1.setEllipsize(TextUtils.TruncateAt.MARQUEE);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnSaveInstanceState_savesTextStateWhenFreezesTextIsTrue() {
-        // prepare TextView for before saveInstanceState
+        // prepare EditText for before saveInstanceState
         final String testStr = "This is a test str";
-        EditText editText1 = new EditText(mContext);
-        editText1.setFreezesText(true);
-        editText1.setText(testStr);
+        mEditText1.setFreezesText(true);
+        mEditText1.setText(testStr);
 
-        // prepare TextView for after saveInstanceState
-        EditText editText2 = new EditText(mContext);
-        editText2.setFreezesText(true);
+        // prepare EditText for after saveInstanceState
+        mEditText2.setFreezesText(true);
 
-        editText2.onRestoreInstanceState(editText1.onSaveInstanceState());
+        mEditText2.onRestoreInstanceState(mEditText1.onSaveInstanceState());
 
-        assertEquals(editText1.getText().toString(), editText2.getText().toString());
+        assertTrue(TextUtils.equals(mEditText1.getText(), mEditText2.getText()));
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testOnSaveInstanceState_savesTextStateWhenFreezesTextIfFalse() {
-        // prepare TextView for before saveInstanceState
+        // prepare EditText for before saveInstanceState
         final String testStr = "This is a test str";
-        EditText editText1 = new EditText(mContext);
-        editText1.setFreezesText(false);
-        editText1.setText(testStr);
+        mEditText1.setFreezesText(false);
+        mEditText1.setText(testStr);
 
-        // prepare TextView for after saveInstanceState
-        EditText editText2 = new EditText(mContext);
-        editText2.setFreezesText(false);
+        // prepare EditText for after saveInstanceState
+        mEditText2.setFreezesText(false);
 
-        editText2.onRestoreInstanceState(editText1.onSaveInstanceState());
+        mEditText2.onRestoreInstanceState(mEditText1.onSaveInstanceState());
 
-        assertEquals(editText1.getText().toString(), editText2.getText().toString());
+        assertTrue(TextUtils.equals(mEditText1.getText(), mEditText2.getText()));
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testOnSaveInstanceState_savesSelectionStateWhenFreezesTextIsFalse() {
-        // prepare TextView for before saveInstanceState
+        // prepare EditText for before saveInstanceState
         final String testStr = "This is a test str";
-        EditText editText1 = new EditText(mContext);
-        editText1.setFreezesText(false);
-        editText1.setText(testStr);
-        editText1.setSelection(2, testStr.length() - 2);
+        mEditText1.setFreezesText(false);
+        mEditText1.setText(testStr);
+        mEditText1.setSelection(2, testStr.length() - 2);
 
-        // prepare TextView for after saveInstanceState
-        EditText editText2 = new EditText(mContext);
-        editText2.setFreezesText(false);
+        // prepare EditText for after saveInstanceState
+        mEditText2.setFreezesText(false);
 
-        editText2.onRestoreInstanceState(editText1.onSaveInstanceState());
+        mEditText2.onRestoreInstanceState(mEditText1.onSaveInstanceState());
 
-        assertEquals(editText1.getSelectionStart(), editText2.getSelectionStart());
-        assertEquals(editText1.getSelectionEnd(), editText2.getSelectionEnd());
+        assertEquals(mEditText1.getSelectionStart(), mEditText2.getSelectionStart());
+        assertEquals(mEditText1.getSelectionEnd(), mEditText2.getSelectionEnd());
     }
 
-    @SmallTest
+    @UiThreadTest
+    @Test
     public void testOnSaveInstanceState_savesSelectionStateWhenFreezesTextIsTrue() {
-        // prepare TextView for before saveInstanceState
+        // prepare EditText for before saveInstanceState
         final String testStr = "This is a test str";
-        EditText editText1 = new EditText(mContext);
-        editText1.setFreezesText(true);
-        editText1.setText(testStr);
-        editText1.setSelection(2, testStr.length() - 2);
+        mEditText1.setFreezesText(true);
+        mEditText1.setText(testStr);
+        mEditText1.setSelection(2, testStr.length() - 2);
 
-        // prepare TextView for after saveInstanceState
-        EditText editText2 = new EditText(mContext);
-        editText2.setFreezesText(true);
+        // prepare EditText for after saveInstanceState
+        mEditText2.setFreezesText(true);
 
-        editText2.onRestoreInstanceState(editText1.onSaveInstanceState());
+        mEditText2.onRestoreInstanceState(mEditText1.onSaveInstanceState());
 
-        assertEquals(editText1.getSelectionStart(), editText2.getSelectionStart());
-        assertEquals(editText1.getSelectionEnd(), editText2.getSelectionEnd());
+        assertEquals(mEditText1.getSelectionStart(), mEditText2.getSelectionStart());
+        assertEquals(mEditText1.getSelectionEnd(), mEditText2.getSelectionEnd());
     }
 
     private class MockEditText extends EditText {
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableList.java b/tests/tests/widget/src/android/widget/cts/ExpandableList.java
new file mode 100644
index 0000000..48fa5e9
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableList.java
@@ -0,0 +1,31 @@
+/*
+ * 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.widget.ExpandableListAdapter;
+
+public class ExpandableList extends ExpandableListBasic {
+    @Override
+    protected ExpandableListAdapter createAdapter() {
+        return null;
+    }
+
+    @Override
+    protected boolean shouldRegisterItemClickListener() {
+        return false;
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java b/tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java
new file mode 100644
index 0000000..b314e15
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListBasic.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.widget.cts;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.cts.util.ExpandableListScenario;
+
+public class ExpandableListBasic extends ExpandableListScenario {
+    private static final int[] CHILD_COUNT = {4, 3, 2, 1, 0};
+
+    @Override
+    protected void init(ExpandableParams params) {
+        params.setNumChildren(CHILD_COUNT).setItemScreenSizeFactor(0.14);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add("Add item").setOnMenuItemClickListener((MenuItem item) -> {
+                mGroups.add(0, new MyGroup(2));
+                if (mAdapter != null) {
+                    ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
+                }
+                return true;
+        });
+
+        return true;
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java b/tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java
deleted file mode 100644
index f2e87ee7..0000000
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListSimple.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.
- */
-
-package android.widget.cts;
-
-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};
-
-    @Override
-    protected void init(ExpandableParams params) {
-        params.setNumChildren(NUM_CHILDREN).setItemScreenSizeFactor(0.14);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add("Add item").setOnMenuItemClickListener(new OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                mGroups.add(0, new MyGroup(2));
-                ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
-                return true;
-            }
-        });
-
-        return true;
-    }
-}
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListTester.java b/tests/tests/widget/src/android/widget/cts/ExpandableListTester.java
index 8175807..296f03f 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListTester.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListTester.java
@@ -17,36 +17,28 @@
 package android.widget.cts;
 
 import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ExpandableListAdapter;
 import android.widget.ExpandableListView;
-import android.widget.cts.util.ExpandableListScenario;
 import android.widget.cts.util.ListUtil;
 
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+
 import junit.framework.Assert;
 
 public class ExpandableListTester {
     private final ExpandableListView mExpandableListView;
     private final ExpandableListAdapter mAdapter;
     private final ListUtil mListUtil;
+    private final Instrumentation mInstrumentation;
 
-    private final ActivityInstrumentationTestCase2<? extends ExpandableListScenario>
-        mActivityInstrumentation;
-
-    Instrumentation mInstrumentation;
-
-    public ExpandableListTester(
-            ExpandableListView expandableListView,
-            ActivityInstrumentationTestCase2<? extends ExpandableListScenario>
-            activityInstrumentation) {
+    public ExpandableListTester(ExpandableListView expandableListView) {
         mExpandableListView = expandableListView;
-        Instrumentation instrumentation = activityInstrumentation.getInstrumentation();
-        mListUtil = new ListUtil(mExpandableListView, instrumentation);
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mListUtil = new ListUtil(mExpandableListView, mInstrumentation);
         mAdapter = mExpandableListView.getExpandableListAdapter();
-        mActivityInstrumentation = activityInstrumentation;
-        mInstrumentation = mActivityInstrumentation.getInstrumentation();
     }
 
     private void expandGroup(final int groupIndex, int flatPosition) {
@@ -54,9 +46,10 @@
                 .isGroupExpanded(groupIndex));
         mListUtil.arrowScrollToSelectedPosition(flatPosition);
         mInstrumentation.waitForIdleSync();
-        mActivityInstrumentation.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        mActivityInstrumentation.getInstrumentation().waitForIdleSync();
-        Assert.assertTrue("Group did not expand " + groupIndex, 
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                KeyEvent.KEYCODE_DPAD_CENTER);
+        mInstrumentation.waitForIdleSync();
+        Assert.assertTrue("Group did not expand " + groupIndex,
                 mExpandableListView.isGroupExpanded(groupIndex));
     }
 
@@ -139,7 +132,7 @@
     }
 
     // This method assumes that NO group is expanded when called
-    void testConvertionBetweenFlatAndPackedOnGroups() {
+    void testConversionBetweenFlatAndPackedOnGroups() {
         final int headerCount = mExpandableListView.getHeaderViewsCount();
 
         for (int i=0; i<headerCount; i++) {
@@ -170,7 +163,7 @@
     }
 
     // This method assumes that NO group is expanded when called
-    void testConvertionBetweenFlatAndPackedOnChildren() {
+    void testConversionBetweenFlatAndPackedOnChildren() {
         // Test with an expanded group
         final int headerCount = mExpandableListView.getHeaderViewsCount();
         final int groupIndex = expandAGroup();
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
index dd8d6a2..1f4270c 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewBasicTest.java
@@ -16,48 +16,57 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
+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.KeyEvent;
 import android.widget.BaseExpandableListAdapter;
 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 com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.List;
 
-public class ExpandableListViewBasicTest extends
-        ActivityInstrumentationTestCase2<ExpandableListSimple> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ExpandableListViewBasicTest {
+    private Instrumentation mInstrumentation;
     private ExpandableListScenario mActivity;
     private ExpandableListView mExpandableListView;
     private ExpandableListAdapter mAdapter;
     private ListUtil mListUtil;
 
-    public ExpandableListViewBasicTest() {
-        super(ExpandableListSimple.class);
-    }
+    @Rule
+    public ActivityTestRule<ExpandableListBasic> mActivityRule =
+            new ActivityTestRule<>(ExpandableListBasic.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
         mExpandableListView = mActivity.getExpandableListView();
         mAdapter = mExpandableListView.getExpandableListAdapter();
-        mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
+        mListUtil = new ListUtil(mExpandableListView, mInstrumentation);
     }
 
-    @MediumTest
+    @Test
     public void testPreconditions() {
         assertNotNull(mActivity);
         assertNotNull(mExpandableListView);
@@ -69,40 +78,43 @@
         assertTrue("Could not find group to expand", groupPos >= 0);
         assertFalse("Group is already expanded", mExpandableListView.isGroupExpanded(groupPos));
         mListUtil.arrowScrollToSelectedPosition(groupPos);
-        getInstrumentation().waitForIdleSync();
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                KeyEvent.KEYCODE_DPAD_CENTER);
+        mInstrumentation.waitForIdleSync();
         assertTrue("Group did not expand", mExpandableListView.isGroupExpanded(groupPos));
 
         return groupPos;
     }
 
-    @MediumTest
+    @Test
     public void testExpandGroup() {
         expandGroup(-1, true);
     }
 
-    @MediumTest
+    @Test
     public void testCollapseGroup() {
         final int groupPos = expandGroup(-1, true);
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                KeyEvent.KEYCODE_DPAD_CENTER);
+        mInstrumentation.waitForIdleSync();
         assertFalse("Group did not collapse", mExpandableListView.isGroupExpanded(groupPos));
     }
 
-    @MediumTest
-    public void testExpandedGroupMovement() {
+    @Test
+    public void testExpandedGroupMovement() throws Throwable {
         // Expand the first group
         mListUtil.arrowScrollToSelectedPosition(0);
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                KeyEvent.KEYCODE_DPAD_CENTER);
+        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 +129,8 @@
                 mAdapter instanceof BaseExpandableListAdapter);
         final BaseExpandableListAdapter adapter = (BaseExpandableListAdapter) mAdapter;
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                adapter.notifyDataSetChanged();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(adapter::notifyDataSetChanged);
+        mInstrumentation.waitForIdleSync();
 
         // Make sure the right group is expanded
         assertTrue("The expanded state didn't stay with the proper group",
@@ -131,22 +139,22 @@
                 mExpandableListView.isGroupExpanded(0));
     }
 
-    @MediumTest
+    @Test
     public void testContextMenus() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
         tester.testContextMenus();
     }
 
-    @MediumTest
+    @Test
     public void testConvertionBetweenFlatAndPacked() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
-        tester.testConvertionBetweenFlatAndPackedOnGroups();
-        tester.testConvertionBetweenFlatAndPackedOnChildren();
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
+        tester.testConversionBetweenFlatAndPackedOnGroups();
+        tester.testConversionBetweenFlatAndPackedOnChildren();
     }
 
-    @MediumTest
+    @Test
     public void testSelectedPosition() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
         tester.testSelectedPositionOnGroups();
         tester.testSelectedPositionOnChildren();
     }
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
index e773ebf..796073f 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
@@ -16,290 +16,417 @@
 
 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.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.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.verifyZeroInteractions;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
+import android.app.Instrumentation;
 import android.content.Context;
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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 com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ExpandableListViewTest {
+    private Instrumentation mInstrumentation;
+    private ExpandableListScenario mActivity;
+    private ExpandableListView mExpandableListView;
+
+    @Rule
+    public ActivityTestRule<ExpandableList> mActivityRule =
+            new ActivityTestRule<>(ExpandableList.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
+        mExpandableListView = mActivity.getExpandableListView();
+    }
+
+    @Test
     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);
-
-        try {
-            new ExpandableListView(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ExpandableListView(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ExpandableListView(null, null, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        new ExpandableListView(mActivity, attrs);
+        new ExpandableListView(mActivity, attrs, 0);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new ExpandableListView(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new ExpandableListView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new ExpandableListView(null, null, 0);
+    }
+
+    @Test
     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);
-            fail("setAdapter(ListAdapter) should throw RuntimeException here.");
-        } catch (RuntimeException e) {
-        }
+    @Test(expected=RuntimeException.class)
+    public void testSetAdapterOfWrongType() {
+        mExpandableListView.setAdapter((ListAdapter) null);
     }
 
+    @UiThreadTest
+    @Test
     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
+    @Test
     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
+    @Test
     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));
     }
 
+    @Test
     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
+    @Test
     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) {
         }
     }
 
+    @Test
+    public void testExpandGroupSmooth() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> mExpandableListView.setAdapter(new MockExpandableListAdapter()));
+
+        ExpandableListView.OnGroupExpandListener mockOnGroupExpandListener =
+                mock(ExpandableListView.OnGroupExpandListener.class);
+        mExpandableListView.setOnGroupExpandListener(mockOnGroupExpandListener);
+
+        verifyZeroInteractions(mockOnGroupExpandListener);
+        mActivityRule.runOnUiThread(() -> assertTrue(mExpandableListView.expandGroup(0, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        mActivityRule.runOnUiThread(() -> assertFalse(mExpandableListView.expandGroup(0, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(0);
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+
+        reset(mockOnGroupExpandListener);
+        mActivityRule.runOnUiThread(() -> assertTrue(mExpandableListView.expandGroup(1, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        mActivityRule.runOnUiThread(() -> assertFalse(mExpandableListView.expandGroup(1, true)));
+        mInstrumentation.waitForIdleSync();
+        verify(mockOnGroupExpandListener, times(1)).onGroupExpand(1);
+        assertTrue(mExpandableListView.isGroupExpanded(1));
+
+        reset(mockOnGroupExpandListener);
+        mActivityRule.runOnUiThread(() -> {
+            mExpandableListView.setAdapter((ExpandableListAdapter) null);
+            try {
+                mExpandableListView.expandGroup(0);
+                fail("should throw NullPointerException");
+            } catch (NullPointerException e) {
+            }
+        });
+    }
+
+    @UiThreadTest
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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));
     }
 
+    @Test
     public void testGetPackedPositionType() {
         assertEquals(ExpandableListView.PACKED_POSITION_TYPE_NULL,
                 ExpandableListView.getPackedPositionType(
@@ -314,6 +441,7 @@
                 ExpandableListView.getPackedPositionType(0x8000000000000000L));
     }
 
+    @Test
     public void testGetPackedPositionGroup() {
         assertEquals(-1, ExpandableListView.getPackedPositionGroup(
                 ExpandableListView.PACKED_POSITION_VALUE_NULL));
@@ -327,6 +455,7 @@
         assertEquals(0x7FFFFFFF, ExpandableListView.getPackedPositionGroup(0x7FFFFFFF00000000L));
     }
 
+    @Test
     public void testGetPackedPositionChild() {
         assertEquals(-1, ExpandableListView.getPackedPositionChild(
                 ExpandableListView.PACKED_POSITION_VALUE_NULL));
@@ -340,6 +469,7 @@
         assertEquals(0xffffffff, ExpandableListView.getPackedPositionChild(0x80000000ffffffffL));
     }
 
+    @Test
     public void testGetPackedPositionForChild() {
         assertEquals(0x8000000000000000L,
                 ExpandableListView.getPackedPositionForChild(0, 0));
@@ -348,6 +478,7 @@
                 ExpandableListView.getPackedPositionForChild(Integer.MAX_VALUE, 0xffffffff));
     }
 
+    @Test
     public void testGetPackedPositionForGroup() {
         assertEquals(0, ExpandableListView.getPackedPositionForGroup(0));
 
@@ -355,32 +486,43 @@
                 ExpandableListView.getPackedPositionForGroup(Integer.MAX_VALUE));
     }
 
+    @Test
     public void testSetChildIndicator() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setChildIndicator(null);
+        mExpandableListView.setChildIndicator(null);
     }
 
+    @Test
     public void testSetChildIndicatorBounds() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setChildIndicatorBounds(10, 10);
+        mExpandableListView.setChildIndicatorBounds(10, 20);
     }
 
+    @Test
+    public void testSetChildIndicatorBoundsRelative() {
+        mExpandableListView.setChildIndicatorBoundsRelative(10, 20);
+    }
+
+    @Test
     public void testSetGroupIndicator() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
         Drawable drawable = new BitmapDrawable();
-        expandableListView.setGroupIndicator(drawable);
+        mExpandableListView.setGroupIndicator(drawable);
     }
 
+    @Test
     public void testSetIndicatorBounds() {
-        ExpandableListView expandableListView = new ExpandableListView(mContext);
-        expandableListView.setIndicatorBounds(10,10);
+        mExpandableListView.setIndicatorBounds(10, 30);
     }
 
+    @Test
+    public void testSetIndicatorBoundsRelative() {
+        mExpandableListView.setIndicatorBoundsRelative(10, 30);
+    }
+
+    @Test
     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();
 
@@ -388,12 +530,19 @@
         assertNotNull(p2);
     }
 
+    @Test
     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 +592,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 +639,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..77cf1b6 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewWithHeadersTest.java
@@ -16,77 +16,90 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.KeyEvent;
 import android.widget.ExpandableListView;
 import android.widget.cts.util.ListUtil;
 
-public class ExpandableListViewWithHeadersTest extends
-        ActivityInstrumentationTestCase2<ExpandableListWithHeaders> {
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ExpandableListViewWithHeadersTest {
+    private Instrumentation mInstrumentation;
+    private ExpandableListWithHeaders mActivity;
     private ExpandableListView mExpandableListView;
     private ListUtil mListUtil;
 
-    public ExpandableListViewWithHeadersTest() {
-        super(ExpandableListWithHeaders.class);
+    @Rule
+    public ActivityTestRule<ExpandableListWithHeaders> mActivityRule =
+            new ActivityTestRule<>(ExpandableListWithHeaders.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
+        mExpandableListView = mActivity.getExpandableListView();
+        mListUtil = new ListUtil(mExpandableListView, mInstrumentation);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        final ExpandableListWithHeaders activity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return activity.hasWindowFocus();
-            }
-        }.run();
-        mExpandableListView = activity.getExpandableListView();
-        mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
-    }
-
-    @MediumTest
+    @Test
     public void testPreconditions() {
         assertNotNull(mExpandableListView);
     }
 
-    @MediumTest
+    @Test
     public void testExpandOnFirstPosition() {
         // Should be a header, and hence the first group should NOT have expanded
         mListUtil.arrowScrollToSelectedPosition(0);
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                (KeyEvent.KEYCODE_DPAD_CENTER));
+        mInstrumentation.waitForIdleSync();
         assertFalse(mExpandableListView.isGroupExpanded(0));
     }
 
     @LargeTest
+    @Test
     public void testExpandOnFirstGroup() {
-        mListUtil.arrowScrollToSelectedPosition(getActivity().getNumOfHeadersAndFooters());
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-        getInstrumentation().waitForIdleSync();
+        mListUtil.arrowScrollToSelectedPosition(mActivity.getNumOfHeadersAndFooters());
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mExpandableListView,
+                (KeyEvent.KEYCODE_DPAD_CENTER));
+        mInstrumentation.waitForIdleSync();
         assertTrue(mExpandableListView.isGroupExpanded(0));
     }
 
-    @MediumTest
+    @Test
     public void testContextMenus() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
         tester.testContextMenus();
     }
 
-    @MediumTest
+    @Test
     public void testConvertionBetweenFlatAndPacked() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
-        tester.testConvertionBetweenFlatAndPackedOnGroups();
-        tester.testConvertionBetweenFlatAndPackedOnChildren();
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
+        tester.testConversionBetweenFlatAndPackedOnGroups();
+        tester.testConversionBetweenFlatAndPackedOnChildren();
     }
 
-    @MediumTest
+    @Test
     public void testSelectedPosition() {
-        ExpandableListTester tester = new ExpandableListTester(mExpandableListView, this);
+        ExpandableListTester tester = new ExpandableListTester(mExpandableListView);
         tester.testSelectedPositionOnGroups();
         tester.testSelectedPositionOnChildren();
     }
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..693ff7e 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListView_ExpandableListContextMenuInfoTest.java
@@ -17,18 +17,29 @@
 
 package android.widget.cts;
 
-import android.test.AndroidTestCase;
-import android.view.View;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.ExpandableListView;
-import android.widget.ListView;
 import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.ListView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link ExpandableListContextMenuInfo}.
  */
-public class ExpandableListView_ExpandableListContextMenuInfoTest extends AndroidTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ExpandableListView_ExpandableListContextMenuInfoTest {
+    @Test
     public void testConstructor() {
-        ListView listview = new ListView(getContext());
+        ListView listview = new ListView(InstrumentationRegistry.getTargetContext());
         ExpandableListContextMenuInfo expandableListContextMenuInfo =
             new ExpandableListView.ExpandableListContextMenuInfo(listview, 100L, 80L);
         assertNotNull(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..f8f577e 100644
--- a/tests/tests/widget/src/android/widget/cts/FilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FilterTest.java
@@ -16,107 +16,102 @@
 
 package android.widget.cts;
 
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
 
-import android.cts.util.PollingCheck;
-import android.cts.util.ReadElf;
-import android.cts.util.TestThread;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
 import android.os.Looper;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.Filter;
-import android.widget.Filter.FilterListener;
 
-public class FilterTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.TestThread;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FilterTest {
     private static final long TIME_OUT = 10000;
     private static final long RUN_TIME = 1000;
     private static final String TEST_CONSTRAINT = "filter test";
+
+    private Instrumentation mInstrumentation;
     private MockFilter mMockFilter;
 
-    public FilterTest() {
-        super("android.widget.cts", CtsActivity.class);
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule =
+            new ActivityTestRule<>(CtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
+    @Test
     public void testConstructor() throws Throwable {
-        TestThread t = new TestThread(new Runnable() {
-            public void run() {
-                Looper.prepare();
-                new MockFilter();
-            }
-        });
-        t.runTest(RUN_TIME);
-    }
-
-    public void testConvertResultToString() throws Throwable {
-        final String testStr = "Test";
-        new TestThread(new Runnable() {
-            public void run() {
-                Looper.prepare();
-                MockFilter filter = new MockFilter();
-                assertEquals("", filter.convertResultToString(null));
-                assertEquals(testStr, filter.convertResultToString(testStr));
-            }
+        new TestThread(() -> {
+            Looper.prepare();
+            new MockFilter();
         }).runTest(RUN_TIME);
     }
 
-    public void testFilter1() {
-        getActivity().runOnUiThread(new Runnable() {
-            public void run() {
-                mMockFilter = new MockFilter();
-                mMockFilter.filter(TEST_CONSTRAINT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+    @Test
+    public void testConvertResultToString() throws Throwable {
+        final String testStr = "Test";
+        new TestThread(() -> {
+            Looper.prepare();
+            MockFilter filter = new MockFilter();
+            assertEquals("", filter.convertResultToString(null));
+            assertEquals(testStr, filter.convertResultToString(testStr));
+        }).runTest(RUN_TIME);
+    }
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPerformedFiltering();
-            }
-        }.run();
+    @Test
+    public void testFilter1() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mMockFilter = new MockFilter();
+            mMockFilter.filter(TEST_CONSTRAINT);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        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();
-        getActivity().runOnUiThread(new Runnable() {
-            public void run() {
-                mMockFilter = new MockFilter();
-                mMockFilter.filter(TEST_CONSTRAINT, mockFilterListener);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+    @Test
+    public void testFilter2() throws Throwable {
+        final Filter.FilterListener mockFilterListener = mock(Filter.FilterListener.class);
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mMockFilter.hadPerformedFiltering();
-            }
-        }.run();
+        mActivityRule.runOnUiThread(() -> {
+            mMockFilter = new MockFilter();
+            mMockFilter.filter(TEST_CONSTRAINT, mockFilterListener);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        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();
+        verify(mockFilterListener, within(TIME_OUT)).onFilterComplete(anyInt());
     }
 
     private static class MockFilter extends Filter {
@@ -185,16 +180,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..ee321e4 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayoutTest.java
@@ -16,24 +16,35 @@
 
 package android.widget.cts;
 
-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.mockito.Matchers.any;
+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 android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
@@ -44,32 +55,39 @@
 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 com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
-public class FrameLayoutTest extends ActivityInstrumentationTestCase2<FrameLayoutCtsActivity> {
-    private Activity mActivity;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FrameLayoutTest {
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private FrameLayout mFrameLayout;
 
-    public FrameLayoutTest() {
-        super("android.widget.cts", FrameLayoutCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<FrameLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(FrameLayoutCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mFrameLayout = (FrameLayout) mActivity.findViewById(R.id.framelayout);
-        assertNotNull(mActivity);
-        assertNotNull(mInstrumentation);
-        assertNotNull(mFrameLayout);
     }
 
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         AttributeSet attrs = getAttributeSet();
 
@@ -78,39 +96,35 @@
         new FrameLayout(mActivity, attrs, 0);
     }
 
-    public void testSetForegroundGravity() {
+    @Test
+    public void testSetForegroundGravity() throws Throwable {
         final BitmapDrawable foreground
                 = (BitmapDrawable) mActivity.getResources().getDrawable(R.drawable.size_48x48);
-        compareScaledPixels(48, foreground.getIntrinsicHeight());
-        compareScaledPixels(48, foreground.getIntrinsicWidth());
+        WidgetTestUtils.assertScaledPixels(48, foreground.getIntrinsicHeight(), mActivity);
+        WidgetTestUtils.assertScaledPixels(48, foreground.getIntrinsicWidth(), mActivity);
         assertTrue(mFrameLayout.getHeight() > foreground.getIntrinsicHeight());
         assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
         assertNull(mFrameLayout.getForeground());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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);
-        compareScaledPixels(48, newForeground.getIntrinsicHeight());
-        compareScaledPixels(48, newForeground.getIntrinsicWidth());
+                (BitmapDrawable) mActivity.getDrawable(R.drawable.size_48x48);
+        WidgetTestUtils.assertScaledPixels(48, newForeground.getIntrinsicHeight(), mActivity);
+        WidgetTestUtils.assertScaledPixels(48, newForeground.getIntrinsicWidth(), mActivity);
         assertTrue(mFrameLayout.getHeight() > newForeground.getIntrinsicHeight());
         assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout, () -> {
             mFrameLayout.setForeground(newForeground);
             mFrameLayout.setForegroundGravity(Gravity.CENTER);
         });
@@ -124,11 +138,12 @@
         assertCenterAligned(mFrameLayout, newForeground);
     }
 
-    public void testGatherTransparentRegion() {
+    @Test
+    public void testGatherTransparentRegion() throws Throwable {
         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(mActivityRule, mFrameLayout, () -> {
             mFrameLayout.setForeground(foreground);
             mFrameLayout.setForegroundGravity(Gravity.CENTER);
         });
@@ -136,56 +151,52 @@
         Region region = new Region(foreground.getBounds());
         assertTrue(mFrameLayout.gatherTransparentRegion(region));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mFrameLayout,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout,
                 () -> container.requestTransparentRegion(mFrameLayout));
         mInstrumentation.waitForIdleSync();
         region = new Region(foreground.getBounds());
         assertTrue(mFrameLayout.gatherTransparentRegion(region));
     }
 
-    public void testAccessMeasureAllChildren() {
+    @Test
+    public void testAccessMeasureAllChildren() throws Throwable {
         final FrameLayout frameLayout
                 = (FrameLayout) mActivity.findViewById(R.id.framelayout_measureall);
         assertFalse(frameLayout.getConsiderGoneChildrenWhenMeasuring());
 
         // text view and button are VISIBLE, they should be measured
         final TextView textView = (TextView) frameLayout.findViewById(R.id.framelayout_textview);
-        compareScaledPixels(30, textView.getMeasuredHeight());
-        compareScaledPixels(60, textView.getMeasuredWidth());
+        WidgetTestUtils.assertScaledPixels(30, textView.getMeasuredHeight(), mActivity);
+        WidgetTestUtils.assertScaledPixels(60, textView.getMeasuredWidth(), mActivity);
         assertEquals(textView.getMeasuredHeight(), frameLayout.getMeasuredHeight());
         assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth());
 
         // measureAll is false and text view is GONE, text view will NOT be measured
-        mActivity.runOnUiThread(() -> {
+        mActivityRule.runOnUiThread(() -> {
             textView.setVisibility(View.GONE);
             frameLayout.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
         assertFalse(frameLayout.getConsiderGoneChildrenWhenMeasuring());
         Button button = (Button) frameLayout.findViewById(R.id.framelayout_button);
-        compareScaledPixels(15, button.getMeasuredHeight());
-        compareScaledPixels(50, button.getMeasuredWidth());
+        WidgetTestUtils.assertScaledPixels(15, button.getMeasuredHeight(), mActivity);
+        WidgetTestUtils.assertScaledPixels(50, button.getMeasuredWidth(), mActivity);
         assertEquals(button.getMeasuredHeight(), frameLayout.getMeasuredHeight());
         assertEquals(button.getMeasuredWidth(), frameLayout.getMeasuredWidth());
 
         // measureAll is true and text view is GONE, text view will be measured
-        mActivity.runOnUiThread(() -> {
+        mActivityRule.runOnUiThread(() -> {
             frameLayout.setMeasureAllChildren(true);
             frameLayout.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(frameLayout.getMeasureAllChildren());
         assertTrue(frameLayout.getConsiderGoneChildrenWhenMeasuring());
         assertEquals(textView.getMeasuredHeight(), frameLayout.getMeasuredHeight());
         assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth());
     }
 
-    /**
-     * Helper method to compare expected pixels, scaled to device density, with actual
-     */
-    private void compareScaledPixels(int expected, int actual) {
-        WidgetTestUtils.assertScaledPixels(expected, actual, getActivity());
-    }
-
+    @Test
     public void testGenerateLayoutParams1() {
         MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity);
         ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
@@ -198,6 +209,7 @@
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, params.height);
     }
 
+    @Test
     public void testGenerateLayoutParams2() throws XmlPullParserException, IOException {
         AttributeSet attrs = getAttributeSet();
 
@@ -208,6 +220,7 @@
         assertEquals(Gravity.BOTTOM, params.gravity);
     }
 
+    @Test
     public void testCheckLayoutParams() {
         MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity);
         assertFalse(myFrameLayout.checkLayoutParams(null));
@@ -221,6 +234,7 @@
         assertTrue(myFrameLayout.checkLayoutParams(params2));
     }
 
+    @Test
     public void testGenerateLayoutParamsFromMarginParams() {
         MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity);
         ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5);
@@ -239,10 +253,7 @@
         assertEquals(4, generated.bottomMargin);
     }
 
-    public void testDrawableStateChanged() {
-        // drawableStateChanged() is implementation details, do NOT test
-    }
-
+    @Test
     public void testGenerateDefaultLayoutParams() {
         MyFrameLayout frameLayout = new MyFrameLayout(mActivity);
         FrameLayout.LayoutParams params = frameLayout.generateDefaultLayoutParams();
@@ -252,18 +263,7 @@
         assertEquals(LayoutParams.MATCH_PARENT, params.height);
     }
 
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
-
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testOnSizeChanged() {
-        // onSizeChanged() is implementation details, do NOT test
-    }
-
+    @Test
     public void testVerifyDrawable() {
         MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity);
 
@@ -277,6 +277,8 @@
         assertTrue(myFrameLayout.verifyDrawable(null));
     }
 
+    @UiThreadTest
+    @Test
     public void testForegroundTint() {
         FrameLayout inflatedView = (FrameLayout) mActivity.findViewById(R.id.foreground_tint);
 
@@ -285,21 +287,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 +325,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..0aca2cd 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
@@ -16,25 +16,39 @@
 
 package android.widget.cts;
 
-import android.view.Gravity;
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
 
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 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 com.android.compatibility.common.util.WidgetTestUtils;
+
+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;
 
-public class FrameLayout_LayoutParamsTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FrameLayout_LayoutParamsTest {
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
 
     private AttributeSet getAttributeSet() throws XmlPullParserException, IOException {
         XmlPullParser parser = mContext.getResources().getLayout(R.layout.framelayout_layout);
@@ -42,6 +56,7 @@
         return Xml.asAttributeSet(parser);
     }
 
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         AttributeSet attrs = getAttributeSet();
 
@@ -52,31 +67,26 @@
         new LayoutParams(new LayoutParams(mContext, attrs));
         new LayoutParams(new MarginLayoutParams(mContext, attrs));
 
-        try {
-            new LayoutParams(null, null);
-            fail("did not throw NullPointerException when context and attrs are null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
         new LayoutParams(-1, -1);
         new LayoutParams(-1, -1, -1);
-
-        try {
-            new LayoutParams((ViewGroup.LayoutParams) null);
-            fail("did not throw NullPointerException when ViewGroup.LayoutParams is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new LayoutParams((ViewGroup.MarginLayoutParams) null);
-            fail("did not throw NullPointerException when ViewGroup.MarginLayoutParams is null.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new LayoutParams(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullViewGroupParams() {
+        new LayoutParams((ViewGroup.LayoutParams) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullViewGroupMarginParams() {
+        new LayoutParams((ViewGroup.MarginLayoutParams) null);
+    }
+
+    @Test
     public void testCopyConstructor() {
         FrameLayout.LayoutParams copy;
 
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..acbe1e7 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
@@ -16,118 +16,107 @@
 
 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.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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 com.android.compatibility.common.util.WidgetTestUtils;
+
+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;
 
 /**
  * Test {@link Gallery}.
  */
-public class GalleryTest extends ActivityInstrumentationTestCase2<GalleryCtsActivity>  {
-    private Gallery mGallery;
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private Context mContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class GalleryTest  {
     private final static float DELTA = 0.01f;
 
-    public GalleryTest() {
-        super("android.widget.cts", GalleryCtsActivity.class);
-    }
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private Gallery mGallery;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getContext();
+    @Rule
+    public ActivityTestRule<GalleryCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GalleryCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mGallery = (Gallery) mActivity.findViewById(R.id.gallery_test);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-        new Gallery(mContext);
+        new Gallery(mActivity);
 
-        new Gallery(mContext, null);
+        new Gallery(mActivity, null);
 
-        new Gallery(mContext, null, 0);
+        new Gallery(mActivity, null, 0);
 
-        XmlPullParser parser = getActivity().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);
-
-        try {
-            new Gallery(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            new Gallery(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected
-        }
-
-        try {
-            new Gallery(null, null, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        new Gallery(mActivity, attrs);
+        new Gallery(mActivity, attrs, 0);
     }
 
-    public void testSetAnimationDuration() {
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new Gallery(null);
     }
 
-    public void testSetSpacing() throws Throwable {
-        setSpacingAndCheck(0);
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new Gallery(null, null);
+    }
 
-        setSpacingAndCheck(5);
-
-        setSpacingAndCheck(-1);
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        new Gallery(null, null, 0);
     }
 
     private void setSpacingAndCheck(final int spacing) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mGallery.setSpacing(spacing);
-                mGallery.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGallery.setSpacing(spacing);
+            mGallery.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
 
@@ -136,65 +125,62 @@
         assertEquals(v0.getRight() + spacing, v1.getLeft());
     }
 
-    public void testSetUnselectedAlpha() {
-        final MyGallery gallery = (MyGallery) mActivity.findViewById(R.id.gallery_test);
+    @Test
+    public void testSetSpacing() throws Throwable {
+        setSpacingAndCheck(0);
 
-        checkUnselectedAlpha(gallery, 0.0f);
+        setSpacingAndCheck(5);
 
-        checkUnselectedAlpha(gallery, 0.5f);
+        setSpacingAndCheck(-1);
     }
 
-    private void checkUnselectedAlpha(MyGallery gallery, float alpha) {
+    private void checkUnselectedAlpha(float alpha) {
         final float DEFAULT_ALPHA = 1.0f;
-        View v0 = gallery.getChildAt(0);
-        View v1 = gallery.getChildAt(1);
+        View v0 = mGallery.getChildAt(0);
+        View v1 = mGallery.getChildAt(1);
 
-        gallery.setUnselectedAlpha(alpha);
+        mGallery.setUnselectedAlpha(alpha);
         Transformation t = new Transformation();
-        gallery.getChildStaticTransformation(v0, t);
+        ((MyGallery) mGallery).getChildStaticTransformation(v0, t);
         // v0 is selected by default.
         assertEquals(DEFAULT_ALPHA, t.getAlpha(), DELTA);
-        gallery.getChildStaticTransformation(v1, t);
+        ((MyGallery) mGallery).getChildStaticTransformation(v1, t);
         assertEquals(alpha, t.getAlpha(), DELTA);
     }
 
     @UiThreadTest
+    @Test
+    public void testSetUnselectedAlpha() {
+        checkUnselectedAlpha(0.0f);
+
+        checkUnselectedAlpha(0.5f);
+    }
+
+    @UiThreadTest
+    @Test
     public void testGenerateLayoutParams() throws XmlPullParserException, IOException {
         final int width = 320;
         final int height = 240;
         LayoutParams lp = new LayoutParams(width, height);
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
         LayoutParams layoutParams = gallery.generateLayoutParams(lp);
         assertEquals(width, layoutParams.width);
         assertEquals(height, layoutParams.height);
 
-        XmlPullParser parser = getActivity().getResources().getXml(R.layout.gallery_test);
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.gallery_test);
         WidgetTestUtils.beginDocument(parser, "LinearLayout");
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        mGallery = new Gallery(mContext, attrs);
+        mGallery = new Gallery(mActivity, attrs);
 
         layoutParams = mGallery.generateLayoutParams(attrs);
         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.width);
         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.height);
     }
 
-    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 testShowContextMenuForChild() {
-        // how to check whether the context menu for child is showing.
-    }
-
-    public void testShowContextMenu() {
-        // how to check whether the context menu is showing.
-    }
-
     @UiThreadTest
+    @Test
     public void testDispatchKeyEvent() {
-        mGallery = new Gallery(mContext);
+        mGallery = new Gallery(mActivity);
         final KeyEvent validKeyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER);
         assertTrue(mGallery.dispatchKeyEvent(validKeyEvent));
         final long time = SystemClock.uptimeMillis();
@@ -203,6 +189,16 @@
         assertFalse(mGallery.dispatchKeyEvent(invalidKeyEvent));
     }
 
+    private void setGalleryGravity(final int gravity) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mGallery.setGravity(gravity);
+            mGallery.invalidate();
+            mGallery.requestLayout();
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    @Test
     public void testSetGravity() throws Throwable {
         setGalleryGravity(Gravity.CENTER_HORIZONTAL);
         View v0 = mGallery.getChildAt(0);
@@ -217,20 +213,10 @@
         ViewAsserts.assertBottomAligned(mGallery, v0, mGallery.getPaddingBottom());
     }
 
-    private void setGalleryGravity(final int gravity) throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mGallery.setGravity(gravity);
-                mGallery.invalidate();
-                mGallery.requestLayout();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
     @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
         ViewGroup.LayoutParams p1 = new ViewGroup.LayoutParams(320, 480);
         assertFalse(gallery.checkLayoutParams(p1));
 
@@ -239,16 +225,18 @@
     }
 
     @UiThreadTest
+    @Test
     public void testComputeHorizontalScrollExtent() {
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
 
         // only one item is considered to be selected.
         assertEquals(1, gallery.computeHorizontalScrollExtent());
     }
 
     @UiThreadTest
+    @Test
     public void testComputeHorizontalScrollOffset() {
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
         assertEquals(AdapterView.INVALID_POSITION, gallery.computeHorizontalScrollOffset());
         gallery.setAdapter(new ImageAdapter(mActivity));
 
@@ -257,8 +245,9 @@
     }
 
     @UiThreadTest
+    @Test
     public void testComputeHorizontalScrollRange() {
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
         ImageAdapter adapter = new ImageAdapter(mActivity);
         gallery.setAdapter(adapter);
 
@@ -267,22 +256,22 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchSetPressed() {
-        final MyGallery gallery = (MyGallery) getActivity().findViewById(R.id.gallery_test);
+        mGallery.setSelection(0);
+        ((MyGallery) mGallery).dispatchSetPressed(true);
+        assertTrue(mGallery.getSelectedView().isPressed());
+        assertFalse(mGallery.getChildAt(1).isPressed());
 
-        gallery.setSelection(0);
-        gallery.dispatchSetPressed(true);
-        assertTrue(gallery.getSelectedView().isPressed());
-        assertFalse(gallery.getChildAt(1).isPressed());
-
-        gallery.dispatchSetPressed(false);
-        assertFalse(gallery.getSelectedView().isPressed());
-        assertFalse(gallery.getChildAt(1).isPressed());
+        ((MyGallery) mGallery).dispatchSetPressed(false);
+        assertFalse(mGallery.getSelectedView().isPressed());
+        assertFalse(mGallery.getChildAt(1).isPressed());
     }
 
     @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        MyGallery gallery = new MyGallery(mContext);
+        MyGallery gallery = new MyGallery(mActivity);
         ViewGroup.LayoutParams p = gallery.generateDefaultLayoutParams();
         assertNotNull(p);
         assertTrue(p instanceof Gallery.LayoutParams);
@@ -290,21 +279,20 @@
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, p.height);
     }
 
+    @Test
     public void testGetChildDrawingOrder() {
-        final MyGallery gallery = (MyGallery) getActivity().findViewById(R.id.gallery_test);
-
         int childCount = 3;
         int index = 2;
-        assertEquals(gallery.getSelectedItemPosition(),
-                gallery.getChildDrawingOrder(childCount, index));
+        assertEquals(mGallery.getSelectedItemPosition(),
+                ((MyGallery) mGallery).getChildDrawingOrder(childCount, index));
 
         childCount = 5;
         index = 2;
-        assertEquals(index + 1, gallery.getChildDrawingOrder(childCount, index));
+        assertEquals(index + 1, ((MyGallery) mGallery).getChildDrawingOrder(childCount, index));
 
         childCount = 5;
         index = 3;
-        assertEquals(index + 1, gallery.getChildDrawingOrder(childCount, index));
+        assertEquals(index + 1, ((MyGallery) mGallery).getChildDrawingOrder(childCount, index));
     }
 
     private static class ImageAdapter extends BaseAdapter {
@@ -349,36 +337,86 @@
         };
     }
 
-    private static class MockOnItemSelectedListener implements OnItemSelectedListener {
-        private boolean mIsItemSelected;
-        private boolean mNothingSelected;
-        private int mItemSelectedCalledCount;
+    public static class MyGallery extends Gallery {
+        private ContextMenu.ContextMenuInfo mContextMenuInfo;
 
-        public boolean isItemSelected() {
-            return mIsItemSelected;
+        public MyGallery(Context context) {
+            super(context);
         }
 
-        public boolean hasNothingSelected() {
-            return mNothingSelected;
+        public MyGallery(Context context, AttributeSet attrs) {
+            super(context, attrs);
         }
 
-        public int getItemSelectedCalledCount() {
-            return mItemSelectedCalledCount;
+        public MyGallery(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
         }
 
-        public void reset() {
-            mIsItemSelected = false;
-            mNothingSelected = true;
-            mItemSelectedCalledCount = 0;
+        @Override
+        protected boolean getChildStaticTransformation(View child, Transformation t) {
+            return super.getChildStaticTransformation(child, t);
         }
 
-        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-            mIsItemSelected = true;
-            mItemSelectedCalledCount++;
+        @Override
+        protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+            return super.checkLayoutParams(p);
         }
 
-        public void onNothingSelected(AdapterView<?> parent) {
-            mNothingSelected = true;
+        @Override
+        protected int computeHorizontalScrollExtent() {
+            return super.computeHorizontalScrollExtent();
+        }
+
+        @Override
+        protected int computeHorizontalScrollOffset() {
+            return super.computeHorizontalScrollOffset();
+        }
+
+        @Override
+        protected int computeHorizontalScrollRange() {
+            return super.computeHorizontalScrollRange();
+        }
+
+        @Override
+        protected void dispatchSetPressed(boolean pressed) {
+            super.dispatchSetPressed(pressed);
+        }
+
+        @Override
+        protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+            return super.generateDefaultLayoutParams();
+        }
+
+        @Override
+        protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+            return super.generateLayoutParams(p);
+        }
+
+        @Override
+        protected int getChildDrawingOrder(int childCount, int i) {
+            return super.getChildDrawingOrder(childCount, i);
+        }
+
+        @Override
+        protected ContextMenu.ContextMenuInfo getContextMenuInfo() {
+            if (mContextMenuInfo == null) {
+                mContextMenuInfo = new MyContextMenuInfo();
+            }
+            return mContextMenuInfo;
+        }
+
+        @Override
+        protected void onFocusChanged(boolean gainFocus, int direction,
+                Rect previouslyFocusedRect) {
+            super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            super.onLayout(changed, l, t, r, b);
+        }
+
+        private static class MyContextMenuInfo implements ContextMenu.ContextMenuInfo {
         }
     }
 }
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..61c447b 100644
--- a/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/Gallery_LayoutParamsTest.java
@@ -16,28 +16,35 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.cts.util.WidgetTestUtils;
-import android.test.AndroidTestCase;
-import android.widget.Gallery.LayoutParams;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.widget.Gallery;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
 /**
- * Test {@link LayoutParams}.
+ * Test {@link Gallery.LayoutParams}.
  */
-public class Gallery_LayoutParamsTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Gallery_LayoutParamsTest {
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
-        XmlResourceParser p = mContext.getResources().getLayout(R.layout.gallery_test);
+        Context context = InstrumentationRegistry.getTargetContext();
+        XmlResourceParser p = context.getResources().getLayout(R.layout.gallery_test);
         WidgetTestUtils.beginDocument(p, "LinearLayout");
-        new LayoutParams(getContext(), p);
+        new Gallery.LayoutParams(context, p);
 
-        LayoutParams params = new LayoutParams(320, 480);
-        new LayoutParams(params);
+        Gallery.LayoutParams params = new Gallery.LayoutParams(320, 480);
+        new Gallery.LayoutParams(params);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
index 65e86b3..4924407 100644
--- a/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridLayoutTest.java
@@ -16,8 +16,18 @@
 
 package android.widget.cts;
 
+import static android.widget.GridLayout.spec;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
 import android.content.Context;
-import android.test.ActivityInstrumentationTestCase;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
@@ -27,16 +37,19 @@
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.TextView;
-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;
 
-import static android.view.ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS;
-import static android.widget.GridLayout.spec;
-
 /**
- * Test {@link android.widget.GridLayout}.
+ * Test {@link GridLayout}.
  */
-public class GridLayoutTest extends ActivityInstrumentationTestCase<GridLayoutCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class GridLayoutTest {
 
     // The size of the off-screen test container in which we we will testing layout.
     public static final int MAX_X = 2000;
@@ -114,56 +127,58 @@
             }
     };
 
-    private Context mContext;
+    private Activity mActivity;
+    private GridLayout mGridLayout;
 
-    public GridLayoutTest() {
-        super("android.widget.cts", GridLayoutCtsActivity.class);
+    @Rule
+    public ActivityTestRule<GridLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GridLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mGridLayout = (GridLayout) mActivity.findViewById(R.id.gridlayout);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
-    }
-
+    @Test
     public void testConstructor() {
-        new GridLayout(mContext);
+        new GridLayout(mActivity);
 
-        new GridLayout(mContext, null);
+        new GridLayout(mActivity, null);
 
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.gridlayout_layout);
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.gridlayout_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        new GridLayout(mContext, attrs);
-
-        try {
-            new GridLayout(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        new GridLayout(mActivity, attrs);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new GridLayout(null, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
-        GridLayout gridLayout = new GridLayout(mContext);
+        mGridLayout.addView(new TextView(mActivity),
+                new AbsoluteLayout.LayoutParams(0, 0, 0, 0));
 
-        gridLayout.addView(new TextView(mContext), new AbsoluteLayout.LayoutParams(0, 0, 0, 0));
-
-        gridLayout.addView(new TextView(mContext), new GridLayout.LayoutParams(
-                GridLayout.spec(0),
-                GridLayout.spec(0)));
-
+        mGridLayout.addView(new TextView(mActivity),
+                new GridLayout.LayoutParams(GridLayout.spec(0), GridLayout.spec(0)));
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        GridLayout gridLayout = new GridLayout(mContext);
-        ViewGroup.LayoutParams lp = gridLayout.generateLayoutParams(null);
+        ViewGroup.LayoutParams lp = mGridLayout.generateLayoutParams(null);
         assertNotNull(lp);
         assertTrue(lp instanceof GridLayout.LayoutParams);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, lp.width);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, lp.height);
     }
 
+    @Test
     public void testGenerateLayoutParamsFromMarginParams() {
-        MyGridLayout gridLayout = new MyGridLayout(mContext);
+        MyGridLayout gridLayout = new MyGridLayout(mActivity);
         ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5);
         lp.leftMargin = 1;
         lp.topMargin = 2;
@@ -234,7 +249,8 @@
         return table;
     }
 
-    private void testAlignment(int row, int col, Alignment a, View v0, View v1, String group) {
+    private void verifyCellAlignment(int row, int col, Alignment a, View v0, View v1,
+            String group) {
         int a0 = a.getValue(v0);
         int a1 = a.getValue(v1);
         assertEquals("View at row " + row + ", column " + col + " was not " + a.name +
@@ -242,7 +258,7 @@
                 a0, a1);
     }
 
-    private void test(GridLayout p, View[][] table) {
+    private void verifyGridAlignment(GridLayout p, View[][] table) {
         p.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
         p.layout(0, 0, MAX_X, MAX_Y);
 
@@ -256,7 +272,7 @@
             Alignment alignment = HORIZONTAL_ALIGNMENTS[j];
             for (int i = 0; i < N; i++) {
                 int row = i + 1;
-                testAlignment(row, col, alignment, v0, table[row][col], "column");
+                verifyCellAlignment(row, col, alignment, v0, table[row][col], "column");
             }
         }
 
@@ -267,16 +283,16 @@
             Alignment alignment = VERTICAL_ALIGNMENTS[i];
             for (int j = 0; j < M; j++) {
                 int col = j + 1;
-                testAlignment(row, col, alignment, v0, table[row][col], "row");
+                verifyCellAlignment(row, col, alignment, v0, table[row][col], "row");
             }
         }
     }
+
+    @UiThreadTest
+    @Test
     public void testAlignment() {
-        GridLayout p = new GridLayout(mContext);
-        View[][] table = populate(p);
-        test(p, table);
-        //p.setLayoutMode(ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
-        //test(p, table);
+        View[][] table = populate(mGridLayout);
+        verifyGridAlignment(mGridLayout, table);
     }
 
     private static class MyGridLayout extends 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..810e1d9 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
@@ -16,22 +16,35 @@
 
 package android.widget.cts;
 
-import android.test.suitebuilder.annotation.MediumTest;
-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.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
+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 android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.ViewAsserts;
 import android.util.AttributeSet;
 import android.util.Xml;
@@ -47,39 +60,44 @@
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.cts.util.ViewTestUtils;
+
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test {@link GridView}.
  */
-public class GridViewTest extends ActivityInstrumentationTestCase<GridViewCtsActivity> {
-    private GridView mGridView;
-    private Activity mActivity;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GridViewTest {
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private GridView mGridView;
 
-    public GridViewTest() {
-        super("android.widget.cts", GridViewCtsActivity.class);
+    @Rule
+    public ActivityTestRule<GridViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(GridViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mGridView = (GridView) mActivity.findViewById(R.id.gridview);
+
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
     }
 
-    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();
-    }
-
+    @Test
     public void testConstructor() {
         new GridView(mActivity);
 
@@ -87,32 +105,38 @@
 
         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);
         new GridView(mActivity, attrs, 0);
-
-        try {
-            new GridView(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new GridView(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new GridView(null, null, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new GridView(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new GridView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        new GridView(null, null, 0);
+    }
+
+    @UiThreadTest
+    @Test
     public void testAccessAdapter() {
-        mGridView = new GridView(mActivity);
         // set Adapter
         ImageAdapter adapter = new ImageAdapter(mActivity);
         mGridView.setAdapter(adapter);
@@ -122,8 +146,9 @@
         assertNull(mGridView.getAdapter());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetSelection() {
-        mGridView = new GridView(mActivity);
         mGridView.setSelection(0);
         assertEquals(0, mGridView.getSelectedItemPosition());
 
@@ -134,22 +159,21 @@
         assertEquals(mGridView.getCount(), mGridView.getSelectedItemPosition());
     }
 
-    public void testPressKey() {
+    @Test
+    public void testPressKey() throws Throwable {
         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() {
-            public void run() {
-                mGridView.setAdapter(new ImageAdapter(mActivity));
-                mGridView.setNumColumns(NUM_COLUMNS);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-                mGridView.requestFocus();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setAdapter(new ImageAdapter(mActivity));
+            mGridView.setNumColumns(NUM_COLUMNS);
+            mGridView.invalidate();
+            mGridView.requestLayout();
+            mGridView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
@@ -172,100 +196,88 @@
         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;
+    @Test
+    public void testSetGravity() throws Throwable {
         final int NUM_COLUMNS = 1;
         // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new ImageAdapter(mActivity));
-                mGridView.setNumColumns(NUM_COLUMNS);
-                mGridView.setHorizontalSpacing(0);
-                mGridView.setVerticalSpacing(0);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setAdapter(new ImageAdapter(mActivity));
+            mGridView.setNumColumns(NUM_COLUMNS);
+            mGridView.setHorizontalSpacing(0);
+            mGridView.setVerticalSpacing(0);
         });
         mInstrumentation.waitForIdleSync();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setGravity(Gravity.CENTER_HORIZONTAL);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setGravity(Gravity.CENTER_HORIZONTAL);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         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() {
-                mGridView.setGravity(Gravity.LEFT);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setGravity(Gravity.LEFT);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         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() {
-                mGridView.setGravity(Gravity.RIGHT);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setGravity(Gravity.RIGHT);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         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);
+    @Test
+    public void testAccessHorizontalSpacing() throws Throwable {
+        verifyAccessHorizontalSpacing(View.LAYOUT_DIRECTION_LTR);
     }
 
-    public void testSetHorizontalSpacingRTL() {
-        testSetHorizontalSpacing(View.LAYOUT_DIRECTION_RTL);
+    @Test
+    public void testAccessHorizontalSpacingRTL() throws Throwable {
+        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) throws Throwable {
+        mActivityRule.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);
-            }
+        mActivityRule.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 +286,11 @@
             assertEquals(0, child0.getLeft() - child1.getRight());
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setHorizontalSpacing(5);
-            }
-        });
+        mActivityRule.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,50 +300,42 @@
         }
     }
 
-    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);
-            }
+    @Test
+    public void testAccessVerticalSpacing() throws Throwable {
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.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);
+    @Test
+    public void testAccessStretchMode() throws Throwable {
         View child;
 
         final int NUM_COLUMNS = 8;
         // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new ImageAdapter(mActivity));
-                mGridView.setColumnWidth(10);
-                mGridView.setNumColumns(NUM_COLUMNS);
-                mGridView.setHorizontalSpacing(0);
-                mGridView.setVerticalSpacing(0);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setAdapter(new ImageAdapter(mActivity));
+            mGridView.setColumnWidth(10);
+            mGridView.setNumColumns(NUM_COLUMNS);
+            mGridView.setHorizontalSpacing(0);
+            mGridView.setVerticalSpacing(0);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
 
@@ -345,13 +347,11 @@
         int INDEX_0 = 1;
         int INDEX_1 = 2;
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setColumnWidth(15);
-                mGridView.setStretchMode(GridView.STRETCH_SPACING);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setColumnWidth(15);
+            mGridView.setStretchMode(GridView.STRETCH_SPACING);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(GridView.STRETCH_SPACING, mGridView.getStretchMode());
@@ -364,13 +364,11 @@
         child = mGridView.getChildAt(1);
         childRight[STRETCH_SPACING][INDEX_1] = child.getRight();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setColumnWidth(15);
-                mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setColumnWidth(15);
+            mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(GridView.STRETCH_COLUMN_WIDTH, mGridView.getStretchMode());
@@ -383,13 +381,11 @@
         child = mGridView.getChildAt(1);
         childRight[STRETCH_COLUMN_WIDTH][INDEX_1] = child.getRight();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setColumnWidth(15);
-                mGridView.setStretchMode(GridView.STRETCH_SPACING_UNIFORM);
-                mGridView.invalidate();
-                mGridView.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setColumnWidth(15);
+            mGridView.setStretchMode(GridView.STRETCH_SPACING_UNIFORM);
+            mGridView.invalidate();
+            mGridView.requestLayout();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(GridView.STRETCH_SPACING_UNIFORM, mGridView.getStretchMode());
@@ -416,17 +412,14 @@
                 < childRight[STRETCH_SPACING_UNIFORM][INDEX_1]);
     }
 
-    public void testSetNumColumns() {
-        mGridView = findGridViewById(R.id.gridview);
-
+    @Test
+    public void testSetNumColumns() throws Throwable {
         // this test case can not be ran in UI thread.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new MockGridViewAdapter(10));
-                mGridView.setHorizontalSpacing(0);
-                mGridView.setVerticalSpacing(0);
-                mGridView.setNumColumns(10);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setAdapter(new MockGridViewAdapter(10));
+            mGridView.setHorizontalSpacing(0);
+            mGridView.setVerticalSpacing(0);
+            mGridView.setNumColumns(10);
         });
         mInstrumentation.waitForIdleSync();
 
@@ -434,11 +427,7 @@
         View child9 = mGridView.getChildAt(9);
         assertEquals(child0.getBottom(), child9.getBottom());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setNumColumns(9);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mGridView.setNumColumns(9));
         mInstrumentation.waitForIdleSync();
 
         child0 = mGridView.getChildAt(0);
@@ -446,11 +435,7 @@
         assertEquals(child0.getBottom(), child9.getTop());
         assertEquals(child0.getLeft(), child9.getLeft());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setNumColumns(1);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mGridView.setNumColumns(1));
         mInstrumentation.waitForIdleSync();
 
         for (int i = 0; i < mGridView.getChildCount(); i++) {
@@ -459,43 +444,35 @@
         }
     }
 
-    public void testGetNumColumns() {
-        mGridView = new GridView(mActivity);
+    @Test
+    public void testDefaultNumColumns() {
+        final GridView gridView = new GridView(mActivity);
+        assertEquals(gridView.getNumColumns(), GridView.AUTO_FIT);
+    }
 
-        assertEquals(mGridView.getNumColumns(), GridView.AUTO_FIT);
-
-        mGridView = findGridViewById(R.id.gridview);
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setAdapter(new MockGridViewAdapter(10));
-                mGridView.setNumColumns(10);
-            }
+    @Test
+    public void testGetNumColumns() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mGridView.setAdapter(new MockGridViewAdapter(10));
+            mGridView.setNumColumns(10);
         });
         mInstrumentation.waitForIdleSync();
 
         assertEquals(mGridView.getNumColumns(), 10);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setNumColumns(1);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mGridView.setNumColumns(1));
         mInstrumentation.waitForIdleSync();
 
         assertEquals(mGridView.getNumColumns(), 1);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setNumColumns(0);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mGridView.setNumColumns(0));
         mInstrumentation.waitForIdleSync();
 
         //although setNumColumns(0) was called, the number of columns should be 1
         assertEquals(mGridView.getNumColumns(), 1);
     }
 
+    @Test
     public void testAttachLayoutAnimationParameters() {
         MockGridView mockGridView = new MockGridView(mActivity);
         ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(320, 480);
@@ -505,12 +482,14 @@
         assertEquals(2, animationParams.count);
     }
 
+    @Test
     public void testLayoutChildren() {
         MockGridView mockGridView = new MockGridView(mActivity);
         mockGridView.layoutChildren();
     }
 
     @UiThreadTest
+    @Test
     public void testOnFocusChanged() {
         final MockGridView mockGridView = new MockGridView(mActivity);
 
@@ -528,40 +507,34 @@
         assertTrue(mockGridView.hasCalledOnFocusChanged());
     }
 
-    public void testOnMeasure() {
-        // 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);
-            }
+    @Test
+    public void testAccessColumnWidth() throws Throwable {
+        mActivityRule.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);
-            }
+        mActivityRule.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());
@@ -569,21 +542,21 @@
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnScroll() {
-        mGridView = findGridViewById(R.id.gridview);
+    @Test
+    public void testFullyDetachUnusedViewOnScroll() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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);
@@ -595,21 +568,21 @@
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnReLayout() {
-        mGridView = findGridViewById(R.id.gridview);
+    @Test
+    public void testFullyDetachUnusedViewOnReLayout() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, mGridView, () -> {
             mGridView.setSelection(0);
         });
         assertNotNull("test sanity, view should be re-added", theView.getParent());
@@ -619,44 +592,84 @@
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnScrollForFocus() {
-        mGridView = findGridViewById(R.id.gridview);
+    @Test
+    public void testFullyDetachUnusedViewOnScrollForFocus() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mGridView, () -> {
             mGridView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
         while(theView.getParent() != null) {
             assertEquals("the view should NOT be detached", 0, theView.mOnDetachCount);
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mGridView, null);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mGridView, KeyEvent.KEYCODE_DPAD_DOWN);
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mGridView, KeyEvent.KEYCODE_DPAD_UP);
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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
+    @Test
+    public void testSmoothScrollByOffset() throws Throwable {
+        final int itemCount = 300;
+        mActivityRule.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();
+        mActivityRule.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 +697,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 +711,6 @@
             mCount = count;
         }
 
-        MockGridViewAdapter() {
-            this(1);
-        }
-
         public boolean areAllItemsEnabled() {
             return true;
         }
@@ -812,7 +784,7 @@
         }
     }
 
-    public class ImageAdapter implements ListAdapter {
+    private class ImageAdapter implements ListAdapter {
         public ImageAdapter(Context c) {
             mContext = c;
         }
@@ -872,14 +844,6 @@
             mDataSetObservable.unregisterObserver(observer);
         }
 
-        public void notifyDataSetChanged() {
-            mDataSetObservable.notifyChanged();
-        }
-
-        public void notifyDataSetInvalidated() {
-            mDataSetObservable.notifyInvalidated();
-        }
-
         public boolean areAllItemsEnabled() {
             return true;
         }
@@ -888,10 +852,6 @@
             return true;
         }
 
-        public View getDropDownView(int position, View convertView, ViewGroup parent) {
-            return getView(position, convertView, parent);
-        }
-
         public int getItemViewType(int position) {
             return 0;
         }
diff --git a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
index 2b92a4d..dcfd7d2 100644
--- a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
@@ -16,10 +16,19 @@
 
 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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
 import android.content.Context;
 import android.database.DataSetObserver;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
@@ -29,29 +38,41 @@
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 
 /**
  * Test {@link HeaderViewListAdapter}.
  */
-public class HeaderViewListAdapterTest extends InstrumentationTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HeaderViewListAdapterTest {
     private Context mContext;
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    private HeaderViewFullAdapter mFullAdapter;
+    private HeaderViewEmptyAdapter mEmptyAdapter;
+
+    @UiThreadTest
+    @Before
+    public void setup() throws Throwable {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mFullAdapter = new HeaderViewFullAdapter();
+        mEmptyAdapter = new HeaderViewEmptyAdapter();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>();
         ArrayList<ListView.FixedViewInfo> footer = new ArrayList<ListView.FixedViewInfo>(5);
         new HeaderViewListAdapter(header, footer, null);
 
-        new HeaderViewListAdapter(header, footer, new HeaderViewEmptyAdapter());
+        new HeaderViewListAdapter(header, footer, mEmptyAdapter);
     }
 
+    @Test
     public void testGetHeadersCount() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertEquals(0, headerViewListAdapter.getHeadersCount());
@@ -63,6 +84,7 @@
         assertEquals(1, headerViewListAdapter.getHeadersCount());
     }
 
+    @Test
     public void testGetFootersCount() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertEquals(0, headerViewListAdapter.getFootersCount());
@@ -75,19 +97,19 @@
     }
 
     @UiThreadTest
+    @Test
     public void testIsEmpty() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertTrue(headerViewListAdapter.isEmpty());
 
-        HeaderViewEmptyAdapter emptyAdapter = new HeaderViewEmptyAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, emptyAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mEmptyAdapter);
         assertTrue(headerViewListAdapter.isEmpty());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertFalse(headerViewListAdapter.isEmpty());
     }
 
+    @Test
     public void testRemoveHeader() {
         ListView lv = new ListView(mContext);
         ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
@@ -105,15 +127,10 @@
         assertTrue(headerViewListAdapter.removeHeader(lv1));
         assertEquals(1, headerViewListAdapter.getHeadersCount());
 
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
-        try {
-            headerViewListAdapter.removeHeader(null);
-            //fail("Removing from null header should result in NullPointerException");
-        } catch (NullPointerException e) {
-            // expected.
-        }
+        headerViewListAdapter.removeHeader(null);
     }
 
+    @Test
     public void testRemoveFooter() {
         ListView lv = new ListView(mContext);
         ArrayList<ListView.FixedViewInfo> footer = new ArrayList<ListView.FixedViewInfo>(4);
@@ -131,16 +148,11 @@
         assertTrue(headerViewListAdapter.removeFooter(lv1));
         assertEquals(1, headerViewListAdapter.getFootersCount());
 
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
-        try {
-            headerViewListAdapter.removeFooter(null);
-            //fail("Removing from null footer should result in NullPointerException");
-        } catch (NullPointerException e) {
-            // expected.
-        }
+        headerViewListAdapter.removeFooter(null);
     }
 
     @UiThreadTest
+    @Test
     public void testGetCount() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertEquals(0, headerViewListAdapter.getCount());
@@ -165,59 +177,56 @@
         footer.add(info3);
         footer.add(info4);
 
-        HeaderViewEmptyAdapter emptyAdapter = new HeaderViewEmptyAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(header, footer, emptyAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(header, footer, mEmptyAdapter);
         // 4 is header's count + footer's count + emptyAdapter's count
         assertEquals(4, headerViewListAdapter.getCount());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(header, footer, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(header, footer, mFullAdapter);
         // 5 is header's count + footer's count + fullAdapter's count
         assertEquals(5, headerViewListAdapter.getCount());
     }
 
-    @UiThreadTest
+    @Test
     public void testAreAllItemsEnabled() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertTrue(headerViewListAdapter.areAllItemsEnabled());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertTrue(headerViewListAdapter.areAllItemsEnabled());
 
-        HeaderViewEmptyAdapter emptyAdapter = new HeaderViewEmptyAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, emptyAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mEmptyAdapter);
         assertFalse(headerViewListAdapter.areAllItemsEnabled());
     }
 
+    @Test
     public void testIsEnabled() {
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
-            new HeaderViewListAdapter(null, null, fullAdapter);
+            new HeaderViewListAdapter(null, null, mFullAdapter);
         assertTrue(headerViewListAdapter.isEnabled(0));
-        
+
         ListView lv = new ListView(mContext);
         ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
         header.add(lv.new FixedViewInfo());
-        headerViewListAdapter = new HeaderViewListAdapter(header, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(header, null, mFullAdapter);
         assertFalse(headerViewListAdapter.isEnabled(0));
         assertTrue(headerViewListAdapter.isEnabled(1));
 
         ArrayList<ListView.FixedViewInfo> footer = new ArrayList<ListView.FixedViewInfo>(4);
         footer.add(lv.new FixedViewInfo());
         footer.add(lv.new FixedViewInfo());
-        headerViewListAdapter = new HeaderViewListAdapter(header, footer, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(header, footer, mFullAdapter);
         assertFalse(headerViewListAdapter.isEnabled(0));
         assertTrue(headerViewListAdapter.isEnabled(1));
         assertFalse(headerViewListAdapter.isEnabled(2));
         assertFalse(headerViewListAdapter.isEnabled(3));
 
-        headerViewListAdapter = new HeaderViewListAdapter(null, footer, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, footer, mFullAdapter);
         assertTrue(headerViewListAdapter.isEnabled(0));
         assertFalse(headerViewListAdapter.isEnabled(1));
         assertFalse(headerViewListAdapter.isEnabled(2));
     }
 
+    @Test
     public void testGetItem() {
         ListView lv = new ListView(mContext);
         ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
@@ -239,16 +248,16 @@
         footer.add(info3);
         footer.add(info4);
 
-        HeaderViewFullAdapter headerViewFullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
-            new HeaderViewListAdapter(header, footer, headerViewFullAdapter);
+            new HeaderViewListAdapter(header, footer, mFullAdapter);
         assertSame(data1, headerViewListAdapter.getItem(0));
         assertSame(data2, headerViewListAdapter.getItem(1));
-        assertSame(headerViewFullAdapter.getItem(0), headerViewListAdapter.getItem(2));
+        assertSame(mFullAdapter.getItem(0), headerViewListAdapter.getItem(2));
         assertSame(data3, headerViewListAdapter.getItem(3));
         assertSame(data4, headerViewListAdapter.getItem(4));
     }
 
+    @Test
     public void testGetItemId() {
         ListView lv = new ListView(mContext);
         ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
@@ -261,25 +270,25 @@
         header.add(info1);
         header.add(info2);
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
-            new HeaderViewListAdapter(header, null, fullAdapter);
+            new HeaderViewListAdapter(header, null, mFullAdapter);
         assertEquals(-1, headerViewListAdapter.getItemId(0));
-        assertEquals(fullAdapter.getItemId(0), headerViewListAdapter.getItemId(2));
+        assertEquals(mFullAdapter.getItemId(0), headerViewListAdapter.getItemId(2));
     }
 
+    @Test
     public void testHasStableIds() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertFalse(headerViewListAdapter.hasStableIds());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertTrue(headerViewListAdapter.hasStableIds());
     }
 
+    @Test
     public void testGetView() {
         ListView lv = new ListView(mContext);
-        ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
+        ArrayList<ListView.FixedViewInfo> header = new ArrayList<>(4);
         ListView lv1 = new ListView(mContext);
         ListView lv2 = new ListView(mContext);
         ListView.FixedViewInfo info1 = lv.new FixedViewInfo();
@@ -295,25 +304,24 @@
         assertSame(lv2, headerViewListAdapter.getView(1, null, null));
 
         // Adapter only
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        View expected = fullAdapter.getView(0, null, null);
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        View expected = mFullAdapter.getView(0, null, null);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertSame(expected, headerViewListAdapter.getView(0, null, null));
 
         // Header and adapter
-        headerViewListAdapter = new HeaderViewListAdapter(header, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(header, null, mFullAdapter);
         assertSame(lv1, headerViewListAdapter.getView(0, null, null));
         assertSame(lv2, headerViewListAdapter.getView(1, null, null));
         assertSame(expected, headerViewListAdapter.getView(2, null, null));
     }
 
+    @Test
     public void testGetItemViewType() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertEquals(AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER,
                 headerViewListAdapter.getItemViewType(0));
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertEquals(AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER,
                 headerViewListAdapter.getItemViewType(-1));
         assertEquals(0, headerViewListAdapter.getItemViewType(0));
@@ -321,58 +329,57 @@
                 headerViewListAdapter.getItemViewType(2));
     }
 
+    @Test
     public void testGetViewTypeCount() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertEquals(1, headerViewListAdapter.getViewTypeCount());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
-        assertEquals(fullAdapter.getViewTypeCount(), headerViewListAdapter.getViewTypeCount());
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
+        assertEquals(mFullAdapter.getViewTypeCount(), headerViewListAdapter.getViewTypeCount());
     }
 
+    @Test
     public void testRegisterDataSetObserver() {
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
-            new HeaderViewListAdapter(null, null, fullAdapter);
-        DataSetObserver observer = new HeaderViewDataSetObserver();
-        headerViewListAdapter.registerDataSetObserver(observer);
-        assertSame(observer, fullAdapter.getDataSetObserver());
+            new HeaderViewListAdapter(null, null, mFullAdapter);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        headerViewListAdapter.registerDataSetObserver(mockDataSetObserver);
+        assertSame(mockDataSetObserver, mFullAdapter.getDataSetObserver());
     }
 
+    @Test
     public void testUnregisterDataSetObserver() {
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         HeaderViewListAdapter headerViewListAdapter =
-            new HeaderViewListAdapter(null, null, fullAdapter);
-        DataSetObserver observer = new HeaderViewDataSetObserver();
-        headerViewListAdapter.registerDataSetObserver(observer);
+            new HeaderViewListAdapter(null, null, mFullAdapter);
+        DataSetObserver mockDataSetObserver = mock(DataSetObserver.class);
+        headerViewListAdapter.registerDataSetObserver(mockDataSetObserver);
 
         headerViewListAdapter.unregisterDataSetObserver(null);
-        assertSame(observer, fullAdapter.getDataSetObserver());
-        headerViewListAdapter.unregisterDataSetObserver(observer);
-        assertNull(fullAdapter.getDataSetObserver());
+        assertSame(mockDataSetObserver, mFullAdapter.getDataSetObserver());
+        headerViewListAdapter.unregisterDataSetObserver(mockDataSetObserver);
+        assertNull(mFullAdapter.getDataSetObserver());
     }
 
     @UiThreadTest
+    @Test
     public void testGetFilter() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertNull(headerViewListAdapter.getFilter());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
         assertNull(headerViewListAdapter.getFilter());
 
-        HeaderViewEmptyAdapter emptyAdapter = new HeaderViewEmptyAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, emptyAdapter);
-        assertSame(emptyAdapter.getFilter(), headerViewListAdapter.getFilter());
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mEmptyAdapter);
+        assertSame(mEmptyAdapter.getFilter(), headerViewListAdapter.getFilter());
     }
 
+    @Test
     public void testGetWrappedAdapter() {
         HeaderViewListAdapter headerViewListAdapter = new HeaderViewListAdapter(null, null, null);
         assertNull(headerViewListAdapter.getWrappedAdapter());
 
-        HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
-        headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
-        assertSame(fullAdapter, headerViewListAdapter.getWrappedAdapter());
+        headerViewListAdapter = new HeaderViewListAdapter(null, null, mFullAdapter);
+        assertSame(mFullAdapter, headerViewListAdapter.getWrappedAdapter());
     }
 
     private class HeaderViewEmptyAdapter implements ListAdapter, Filterable {
@@ -504,16 +511,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..88aa357 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -16,55 +16,78 @@
 
 package android.widget.cts;
 
-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;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
-import android.util.Xml;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
-import android.widget.HorizontalScrollView;
-import android.widget.TextView;
+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.junit.Assert.fail;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link HorizontalScrollView}.
  */
-public class HorizontalScrollViewTest
-        extends ActivityInstrumentationTestCase2<HorizontalScrollViewCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class HorizontalScrollViewTest {
     private static final int ITEM_WIDTH  = 250;
     private static final int ITEM_HEIGHT = 100;
     private static final int ITEM_COUNT  = 15;
     private static final int PAGE_WIDTH  = 100;
     private static final int PAGE_HEIGHT = 100;
     private static final int SCROLL_RIGHT = ITEM_WIDTH * ITEM_COUNT - PAGE_WIDTH;
-    private MyHorizontalScrollView mScrollView;
+
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
+    private HorizontalScrollView mScrollViewRegular;
+    private HorizontalScrollView mScrollViewCustom;
+    private MyHorizontalScrollView mScrollViewCustomEmpty;
 
-    public HorizontalScrollViewTest() {
-        super("android.widget.cts", HorizontalScrollViewCtsActivity.class);
+    @Rule
+    public ActivityTestRule<HorizontalScrollViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(HorizontalScrollViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mScrollViewRegular = (HorizontalScrollView) mActivity.findViewById(
+                R.id.horizontal_scroll_view_regular);
+        mScrollViewCustom = (MyHorizontalScrollView) mActivity.findViewById(
+                R.id.horizontal_scroll_view_custom);
+        mScrollViewCustomEmpty = (MyHorizontalScrollView) mActivity.findViewById(
+                R.id.horizontal_scroll_view_custom_empty);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mScrollView = (MyHorizontalScrollView) mActivity.findViewById(R.id.horizontal_scroll_view);
-    }
-
+    @Test
     public void testConstructor() {
         XmlPullParser parser = mActivity.getResources().getLayout(R.layout.horizontal_scrollview);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -75,224 +98,215 @@
         new HorizontalScrollView(mActivity, attrs, 0);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetMaxScrollAmount() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
-        scrollView.layout(0, 0, 100, 200);
-        assertEquals((100 - 0) / 2, scrollView.getMaxScrollAmount());
+        mScrollViewRegular.layout(0, 0, 100, 200);
+        assertEquals((100 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
 
-        scrollView.layout(0, 0, 150, 100);
-        assertEquals((150 - 0) / 2, scrollView.getMaxScrollAmount());
+        mScrollViewRegular.layout(0, 0, 150, 100);
+        assertEquals((150 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddView() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1);
+            mScrollViewRegular.addView(child1);
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithIndex() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, 0);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, 0);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, 1);
+            mScrollViewRegular.addView(child1, 1);
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
-        scrollView.addView(child0, -1);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.removeAllViews();
 
-        assertEquals(1, scrollView.getChildCount());
+        mScrollViewRegular.addView(child0, -1);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
+
+        assertEquals(1, mScrollViewRegular.getChildCount());
         child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, -1);
+            mScrollViewRegular.addView(child1, -1);
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
+
         try {
-            scrollView.addView(child0, 1);
+            mScrollViewRegular.addView(child0, 1);
             fail("did not throw IndexOutOfBoundsException when index is larger than 0");
         } catch (IndexOutOfBoundsException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithLayoutParams() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, new ViewGroup.LayoutParams(200, 100));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(200, child0.getLayoutParams().width);
         assertEquals(100, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, new ViewGroup.LayoutParams(200, 100));
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
         child0 = new TextView(mActivity);
+
         try {
-            scrollView.addView(child0, null);
+            mScrollViewRegular.addView(child0, null);
             fail("did not throw NullPointerException when LayoutParams is null.");
         } catch (NullPointerException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithIndexAndLayoutParams() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(200, child0.getLayoutParams().width);
         assertEquals(100, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
+
         child0 = new TextView(mActivity);
         try {
-            scrollView.addView(child0, null);
+            mScrollViewRegular.addView(child0, null);
             fail("did not throw NullPointerException when LayoutParams is null.");
         } catch (NullPointerException e) {
             // expected
         }
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
-        scrollView.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.removeAllViews();
+
+        mScrollViewRegular.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(300, child0.getLayoutParams().width);
         assertEquals(150, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
             fail("did not throw IllegalStateException when add more than one child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new HorizontalScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
+
         try {
-            scrollView.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
             fail("did not throw IndexOutOfBoundsException when index is larger than 0");
         } catch (IndexOutOfBoundsException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessFillViewport() {
-        HorizontalScrollView scrollView = new HorizontalScrollView(mActivity);
-        assertFalse(scrollView.isFillViewport());
-        scrollView.layout(0, 0, 100, 100);
-        assertFalse(scrollView.isLayoutRequested());
+        assertFalse(mScrollViewRegular.isFillViewport());
+        mScrollViewRegular.layout(0, 0, 100, 100);
+        assertFalse(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.setFillViewport(false);
-        assertFalse(scrollView.isFillViewport());
-        assertFalse(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(false);
+        assertFalse(mScrollViewRegular.isFillViewport());
+        assertFalse(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.setFillViewport(true);
-        assertTrue(scrollView.isFillViewport());
-        assertTrue(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(true);
+        assertTrue(mScrollViewRegular.isFillViewport());
+        assertTrue(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.layout(0, 0, 100, 100);
-        assertFalse(mScrollView.isLayoutRequested());
+        mScrollViewRegular.layout(0, 0, 100, 100);
+        assertFalse(mScrollViewCustom.isLayoutRequested());
 
-        scrollView.setFillViewport(false);
-        assertFalse(scrollView.isFillViewport());
-        assertTrue(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(false);
+        assertFalse(mScrollViewRegular.isFillViewport());
+        assertTrue(mScrollViewRegular.isLayoutRequested());
     }
 
+    @Test
     public void testAccessSmoothScrollingEnabled() throws Throwable {
-        assertTrue(mScrollView.isSmoothScrollingEnabled());
+        assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
 
         // scroll immediately
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertFalse(mScrollView.isSmoothScrollingEnabled());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertFalse(mScrollViewCustom.isSmoothScrollingEnabled());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_RIGHT);
-            }
-        });
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_LEFT);
-            }
-        });
-        assertEquals(0, mScrollView.getScrollX());
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
         // smooth scroll
-        mScrollView.setSmoothScrollingEnabled(true);
-        assertTrue(mScrollView.isSmoothScrollingEnabled());
+        mScrollViewCustom.setSmoothScrollingEnabled(true);
+        assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_RIGHT);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_RIGHT));
         pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_LEFT);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_LEFT));
         pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
-        assertEquals(0, mScrollView.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChild() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-
         MyView child = new MyView(mActivity);
         child.setBackgroundDrawable(null);
         child.setPadding(0, 0, 0, 0);
@@ -304,16 +318,17 @@
         assertEquals(100, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        ((MyHorizontalScrollView) mScrollViewCustom).measureChild(
+                child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
 
         assertEquals(100, child.getMeasuredHeight());
         assertEquals(30, child.getMeasuredWidth());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChildWithMargins() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-
         MyView child = new MyView(mActivity);
         child.setBackgroundDrawable(null);
         child.setPadding(0, 0, 0, 0);
@@ -325,7 +340,7 @@
         assertEquals(100, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
 
-        scrollView.measureChildWithMargins(child,
+        ((MyHorizontalScrollView) mScrollViewCustom).measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5);
 
@@ -333,37 +348,42 @@
         assertEquals(30, child.getMeasuredWidth());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecs() {
         MyView child = spy(new MyView(mActivity));
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewCustomEmpty.measureChild(child,
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
         verify(child).onMeasure(
                 eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)),
                 eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithPadding() {
         MyView child = spy(new MyView(mActivity));
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setPadding(3, 5, 7, 11);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewCustomEmpty.measureChild(child,
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
         verify(child).onMeasure(
                 eq(MeasureSpec.makeMeasureSpec(90, MeasureSpec.UNSPECIFIED)),
                 eq(MeasureSpec.makeMeasureSpec(134, MeasureSpec.EXACTLY)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMargins() {
         MyView child = spy(new MyView(mActivity));
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
         verify(child).onMeasure(
@@ -371,13 +391,14 @@
                 eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMarginsAndPadding() {
         MyView child = spy(new MyView(mActivity));
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setPadding(3, 5, 7, 11);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
         verify(child).onMeasure(
@@ -385,12 +406,13 @@
                 eq(MeasureSpec.makeMeasureSpec(114, MeasureSpec.EXACTLY)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMarginsAndNoHintWidth() {
         MyView child = spy(new MyView(mActivity));
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
         verify(child).onMeasure(
@@ -398,50 +420,52 @@
                 eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)));
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewport() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-
         MyView child = new MyView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
         child.setLayoutParams(new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT
         ));
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
 
         assertEquals(150, child.getMeasuredWidth());
         assertEquals(100, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 150, 100);
+        mScrollViewRegular.layout(0, 0, 150, 100);
         assertEquals(0, child.getLeft());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithScrollViewPadding() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setFillViewport(true);
-        scrollView.setPadding(3, 10, 5, 7);
+        mScrollViewRegular.setFillViewport(true);
+        mScrollViewRegular.setPadding(3, 10, 5, 7);
 
         MyView child = new MyView(mActivity);
         child.setLayoutParams(new ViewGroup.LayoutParams(10,10));
         child.setDesiredWidth(30);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(92, child.getMeasuredWidth());
         assertEquals(10, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(3, child.getLeft());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithChildMargins() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
 
         MyView child = new MyView(mActivity);
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10);
@@ -452,40 +476,42 @@
         child.setDesiredWidth(30);
         child.setLayoutParams(lp);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(92, child.getMeasuredWidth());
         assertEquals(10, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(3, child.getLeft());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithScrollViewPaddingAlreadyFills() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setFillViewport(true);
-        scrollView.setPadding(3, 10, 5, 7);
+        mScrollViewRegular.setFillViewport(true);
+        mScrollViewRegular.setPadding(3, 10, 5, 7);
 
         MyView child = new MyView(mActivity);
         child.setDesiredWidth(175);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
 
         assertEquals(175, child.getMeasuredWidth());
         assertEquals(133, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(3, child.getLeft());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithChildMarginsAlreadyFills() {
-        MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
         MyView child = new MyView(mActivity);
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -498,146 +524,140 @@
         child.setLayoutParams(lp);
         child.setDesiredWidth(175);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(175, child.getMeasuredWidth());
         assertEquals(133, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(3, child.getLeft());
     }
 
     @UiThreadTest
+    @Test
     public void testPageScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_RIGHT));
-        assertEquals(PAGE_WIDTH, mScrollView.getScrollX());
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_RIGHT));
+        assertEquals(PAGE_WIDTH, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(SCROLL_RIGHT, PAGE_HEIGHT);
-        assertFalse(mScrollView.pageScroll(View.FOCUS_RIGHT));
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(SCROLL_RIGHT, PAGE_HEIGHT);
+        assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_LEFT));
-        assertEquals(SCROLL_RIGHT - PAGE_WIDTH, mScrollView.getScrollX());
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_LEFT));
+        assertEquals(SCROLL_RIGHT - PAGE_WIDTH, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(0, PAGE_HEIGHT);
-        assertFalse(mScrollView.pageScroll(View.FOCUS_LEFT));
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(0, PAGE_HEIGHT);
+        assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
     @UiThreadTest
+    @Test
     public void testFullScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
-        assertTrue(mScrollView.fullScroll(View.FOCUS_RIGHT));
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        assertFalse(mScrollView.fullScroll(View.FOCUS_RIGHT));
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        assertTrue(mScrollView.fullScroll(View.FOCUS_LEFT));
-        assertEquals(0, mScrollView.getScrollX());
+        assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
-        assertFalse(mScrollView.fullScroll(View.FOCUS_LEFT));
-        assertEquals(0, mScrollView.getScrollX());
+        assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
     @UiThreadTest
+    @Test
     public void testArrowScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
-        int x = mScrollView.getScrollX();
+        int x = mScrollViewCustom.getScrollX();
         while (SCROLL_RIGHT != x) {
-            assertTrue(mScrollView.arrowScroll(View.FOCUS_RIGHT));
-            assertTrue(x <= mScrollView.getScrollX());
-            x = mScrollView.getScrollX();
+            assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_RIGHT));
+            assertTrue(x <= mScrollViewCustom.getScrollX());
+            x = mScrollViewCustom.getScrollX();
         }
 
-        assertFalse(mScrollView.arrowScroll(View.FOCUS_RIGHT));
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_RIGHT));
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
-        x = mScrollView.getScrollX();
+        x = mScrollViewCustom.getScrollX();
         while (0 != x) {
-            assertTrue(mScrollView.arrowScroll(View.FOCUS_LEFT));
-            assertTrue(x >= mScrollView.getScrollX());
-            x = mScrollView.getScrollX();
+            assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_LEFT));
+            assertTrue(x >= mScrollViewCustom.getScrollX());
+            x = mScrollViewCustom.getScrollX();
         }
 
-        assertFalse(mScrollView.arrowScroll(View.FOCUS_LEFT));
-        assertEquals(0, mScrollView.getScrollX());
+        assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_LEFT));
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
+    @Test
     public void testSmoothScrollBy() throws Throwable {
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollBy(SCROLL_RIGHT, 0);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollBy(SCROLL_RIGHT, 0));
         pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollBy(-SCROLL_RIGHT, 0);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollBy(-SCROLL_RIGHT, 0));
         pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
+    @Test
     public void testSmoothScrollTo() throws Throwable {
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollTo(SCROLL_RIGHT, 0);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollTo(SCROLL_RIGHT, 0));
         pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollTo(0, 0);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.smoothScrollTo(0, 0));
         pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
+    @Test
     public void testComputeScrollDeltaToGetChildRectOnScreen() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        int edge = mScrollView.getHorizontalFadingEdgeLength();
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        int edge = mScrollViewCustom.getHorizontalFadingEdgeLength();
+
+        MyHorizontalScrollView myScrollViewCustom = (MyHorizontalScrollView) mScrollViewCustom;
 
         // Rect's width is smaller than scroll view
         Rect rect = new Rect(0, 0, 0, 0);
-        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(0, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect));
 
         rect = new Rect(edge, 0, PAGE_WIDTH, 0);
-        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(0, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect));
 
-        mScrollView.scrollTo(0, 0);
+        mScrollViewCustom.scrollTo(0, 0);
         rect = new Rect(edge + 1, 0, PAGE_WIDTH, 0);
-        assertEquals(edge, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(edge, myScrollViewCustom.computeScrollDeltaToGetChildRectOnScreen(rect));
     }
 
+    @Test
     public void testComputeHorizontalScrollRange() {
-        assertTrue(mScrollView.getChildCount() > 0);
-        assertEquals(ITEM_WIDTH * ITEM_COUNT, mScrollView.computeHorizontalScrollRange());
+        assertTrue(mScrollViewCustom.getChildCount() > 0);
+        assertEquals(ITEM_WIDTH * ITEM_COUNT,
+                ((MyHorizontalScrollView) mScrollViewCustom).computeHorizontalScrollRange());
 
         MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
         assertEquals(0, scrollView.getChildCount());
@@ -645,144 +665,108 @@
     }
 
     @UiThreadTest
+    @Test
     public void testRequestChildFocus() {
-        mScrollView.setSmoothScrollingEnabled(false);
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
 
-        View firstChild = mScrollView.findViewById(R.id.first_horizontal_child);
-        View lastChild = mScrollView.findViewById(R.id.last_horizontal_child);
+        View firstChild = mScrollViewCustom.findViewById(R.id.first_horizontal_child);
+        View lastChild = mScrollViewCustom.findViewById(R.id.last_horizontal_child);
         firstChild.requestFocus();
 
-        int scrollX = mScrollView.getScrollX();
-        mScrollView.requestChildFocus(lastChild, lastChild);
+        int scrollX = mScrollViewCustom.getScrollX();
+        mScrollViewCustom.requestChildFocus(lastChild, lastChild);
         // check scrolling to the child which wants focus
-        assertTrue(mScrollView.getScrollX() > scrollX);
+        assertTrue(mScrollViewCustom.getScrollX() > scrollX);
 
-        scrollX = mScrollView.getScrollX();
-        mScrollView.requestChildFocus(firstChild, firstChild);
+        scrollX = mScrollViewCustom.getScrollX();
+        mScrollViewCustom.requestChildFocus(firstChild, firstChild);
         // check scrolling to the child which wants focus
-        assertTrue(mScrollView.getScrollX() < scrollX);
+        assertTrue(mScrollViewCustom.getScrollX() < scrollX);
     }
 
     @UiThreadTest
+    @Test
     public void testRequestChildRectangleOnScreen() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        int edge = mScrollView.getHorizontalFadingEdgeLength();
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        int edge = mScrollViewCustom.getHorizontalFadingEdgeLength();
 
-        View child = mScrollView.findViewById(R.id.first_horizontal_child);
+        View child = mScrollViewCustom.findViewById(R.id.first_horizontal_child);
         final Rect originalRect = new Rect(0, 0, 10, 10);
         final Rect newRect = new Rect(ITEM_WIDTH - 10, ITEM_HEIGHT - 10, ITEM_WIDTH, ITEM_HEIGHT);
 
-        assertFalse(mScrollView.requestChildRectangleOnScreen(child, originalRect, true));
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.requestChildRectangleOnScreen(child, originalRect, true));
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        assertTrue(mScrollView.requestChildRectangleOnScreen(child, newRect, true));
-        assertEquals(ITEM_WIDTH - mScrollView.getWidth() + edge, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertTrue(mScrollViewCustom.requestChildRectangleOnScreen(child, newRect, true));
+        assertEquals(ITEM_WIDTH - mScrollViewCustom.getWidth() + edge, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
     @UiThreadTest
+    @Test
     public void testRequestLayout() {
-        mScrollView.requestLayout();
+        mScrollViewCustom.requestLayout();
 
-        assertTrue(mScrollView.isLayoutRequested());
+        assertTrue(mScrollViewCustom.isLayoutRequested());
     }
 
+    @Test
     public void testFling() throws Throwable {
-        mScrollView.setSmoothScrollingEnabled(true);
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.setSmoothScrollingEnabled(true);
+        assertEquals(0, mScrollViewCustom.getScrollX());
 
-        final int velocityX = WidgetTestUtils.convertDipToPixels(getActivity(), 2000);
+        final int velocityX = WidgetTestUtils.convertDipToPixels(mActivity, 2000);
 
         // fling towards right
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fling(velocityX);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(velocityX));
         pollingCheckFling(0, true);
 
-        final int currentX = mScrollView.getScrollX();
+        final int currentX = mScrollViewCustom.getScrollX();
         // fling towards left
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fling(-velocityX);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(-velocityX));
         pollingCheckFling(currentX, false);
     }
 
     @UiThreadTest
+    @Test
     public void testScrollTo() {
-        mScrollView.setSmoothScrollingEnabled(false);
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
 
-        mScrollView.scrollTo(10, 10);
-        assertEquals(0, mScrollView.getScrollY());
-        assertEquals(10, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(10, 10);
+        assertEquals(0, mScrollViewCustom.getScrollY());
+        assertEquals(10, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(PAGE_WIDTH, PAGE_HEIGHT);
-        assertEquals(0, mScrollView.getScrollY());
-        assertEquals(PAGE_WIDTH, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(PAGE_WIDTH, PAGE_HEIGHT);
+        assertEquals(0, mScrollViewCustom.getScrollY());
+        assertEquals(PAGE_WIDTH, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(SCROLL_RIGHT, 0);
-        assertEquals(0, mScrollView.getScrollY());
-        assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(SCROLL_RIGHT, 0);
+        assertEquals(0, mScrollViewCustom.getScrollY());
+        assertEquals(SCROLL_RIGHT, mScrollViewCustom.getScrollX());
 
         // reach the top and left
-        mScrollView.scrollTo(-10, -10);
-        assertEquals(0, mScrollView.getScrollY());
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(-10, -10);
+        assertEquals(0, mScrollViewCustom.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
+    @Test
     public void testGetHorizontalFadingEdgeStrengths() {
-        assertTrue(mScrollView.getChildCount() > 0);
-        assertTrue(mScrollView.getLeftFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getLeftFadingEdgeStrength() >= 0.0f);
-        assertTrue(mScrollView.getRightFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getRightFadingEdgeStrength() >= 0.0f);
+        MyHorizontalScrollView myScrollViewCustom = (MyHorizontalScrollView) mScrollViewCustom;
+
+        assertTrue(mScrollViewCustom.getChildCount() > 0);
+        assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() >= 0.0f);
+        assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() >= 0.0f);
 
         MyHorizontalScrollView myScrollView = new MyHorizontalScrollView(mActivity);
         assertEquals(0, myScrollView.getChildCount());
-        assertTrue(mScrollView.getLeftFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getLeftFadingEdgeStrength() >= 0.0f);
-        assertTrue(mScrollView.getRightFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getRightFadingEdgeStrength() >= 0.0f);
-    }
-
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
-
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testExecuteKeyEvent() {
-        // executeKeyEvent() is implementation details, do NOT test
-    }
-
-    public void testOnRequestFocusInDescendants() {
-        // onRequestFocusInDescendants() is implementation details, do NOT test
-    }
-
-    public void testOnSizeChanged() {
-        // onSizeChanged() is implementation details, do NOT test
-    }
-
-    public void testDispatchKeyEvent() {
-        // dispatchKeyEvent() is implementation details, do NOT test
-    }
-
-    public void testOnInterceptTouchEvent() {
-        // onInterceptTouchEvent() is implementation details, do NOT test
-    }
-
-    public void testOnTouchEvent() {
-        // onTouchEvent() is implementation details, do NOT test
-    }
-
-    public void testComputeScroll() {
-        // computeScroll() is implementation details, do NOT test
+        assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getLeftFadingEdgeStrength() >= 0.0f);
+        assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getRightFadingEdgeStrength() >= 0.0f);
     }
 
     private boolean isInRange(int current, int from, int to) {
@@ -800,55 +784,34 @@
         }
 
         if (fromY != toY) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollY(), fromY, toY);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollY(), fromY, toY));
         }
 
         if (fromX != toX) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollX(), fromX, toX);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollX(), fromX, toX));
         }
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
-            }
-        }.run();
+        PollingCheck.waitFor(
+                () -> toX == mScrollViewCustom.getScrollX() && toY == mScrollViewCustom.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 mScrollViewCustom.getScrollX() > startPosition;
             }
-        }.run();
+            return mScrollViewCustom.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[] { mScrollViewCustom.getScrollX() };
+        PollingCheck.waitFor(() -> {
+            if (mScrollViewCustom.getScrollX() == previousScrollX[0]) {
+                return true;
+            } else {
+                previousScrollX[0] = mScrollViewCustom.getScrollX();
+                return false;
             }
-        }.run();
+        });
     }
 
     public static class MyView extends View {
@@ -878,4 +841,66 @@
             }
         }
     }
+
+    public static class MyHorizontalScrollView extends HorizontalScrollView {
+        public MyHorizontalScrollView(Context context) {
+            super(context);
+        }
+
+        public MyHorizontalScrollView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        protected int computeHorizontalScrollRange() {
+            return super.computeHorizontalScrollRange();
+        }
+
+        @Override
+        protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
+            return super.computeScrollDeltaToGetChildRectOnScreen(rect);
+        }
+
+        @Override
+        protected float getLeftFadingEdgeStrength() {
+            return super.getLeftFadingEdgeStrength();
+        }
+
+        @Override
+        protected float getRightFadingEdgeStrength() {
+            return super.getRightFadingEdgeStrength();
+        }
+
+        @Override
+        protected void measureChild(View child, int parentWidthMeasureSpec,
+                int parentHeightMeasureSpec) {
+            super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
+        }
+
+        @Override
+        protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+                int parentHeightMeasureSpec, int heightUsed) {
+            super.measureChildWithMargins(child, parentWidthMeasureSpec,
+                    widthUsed, parentHeightMeasureSpec, heightUsed);
+        }
+
+        @Override
+        public int computeVerticalScrollRange() {
+            return super.computeVerticalScrollRange();
+        }
+
+        @Override
+        public int computeVerticalScrollOffset() {
+            return super.computeVerticalScrollOffset();
+        }
+
+        @Override
+        public int computeVerticalScrollExtent() {
+            return super.computeVerticalScrollExtent();
+        }
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
new file mode 100644
index 0000000..5f91950
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.ImageButton;
+
+/**
+ * A minimal application for {@link ImageButton} test.
+ */
+public class ImageButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..c433be6 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
@@ -16,48 +16,81 @@
 
 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.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.ImageButton;
+import android.widget.cts.util.TestUtils;
 
-public class ImageButtonTest extends AndroidTestCase {
-    public void testConstructor() {
-        XmlPullParser parser = getContext().getResources().getXml(R.layout.imagebutton_test);
-        AttributeSet attrs = Xml.asAttributeSet(parser);
-        assertNotNull(attrs);
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-        new ImageButton(getContext());
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImageButtonTest {
+    private Activity mActivity;
+    private ImageButton mImageButton;
 
-        new ImageButton(getContext(), attrs);
+    @Rule
+    public ActivityTestRule<ImageButtonCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ImageButtonCtsActivity.class);
 
-        new ImageButton(getContext(), attrs, 0);
-
-        try {
-            new ImageButton(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ImageButton(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ImageButton(null, null, -1);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mImageButton = (ImageButton) mActivity.findViewById(R.id.image_button);
     }
 
-    public void testOnSetAlpha() {
-        // Do not test, it's controlled by View. Implementation details.
+    @Test
+    public void testConstructor() {
+        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);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new ImageButton(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new ImageButton(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        new ImageButton(null, null, -1);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testImageSource() {
+        Drawable imageButtonDrawable = mImageButton.getDrawable();
+        TestUtils.assertAllPixelsOfColor("Default source is red", imageButtonDrawable,
+                imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+                true, Color.RED, 1, false);
+
+        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);
+
+        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/ImageSwitcherCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherCtsActivity.java
new file mode 100644
index 0000000..f67974a
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherCtsActivity.java
@@ -0,0 +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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ImageSwitcherCtsActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.imageswitcher_layout);
+    }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
index a7bca5c..ea79796 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
@@ -16,163 +16,177 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
 
-
-import org.xmlpull.v1.XmlPullParser;
-
+import android.app.Activity;
 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;
-import android.test.AndroidTestCase;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.widget.ImageSwitcher;
 import android.widget.ImageView;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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;
 
-public class ImageSwitcherTest extends AndroidTestCase {
-    public void testConstructor() {
-        new ImageSwitcher(getContext());
+/**
+ * Test {@link ImageSwitcher}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ImageSwitcherTest {
+    private Activity mActivity;
+    private ImageSwitcher mImageSwitcher;
 
-        new ImageSwitcher(getContext(), null);
+    @Rule
+    public ActivityTestRule<ImageSwitcherCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ImageSwitcherCtsActivity.class);
 
-        XmlPullParser parser = getContext().getResources().getXml(R.layout.imageswitcher_test);
-        AttributeSet attrs = Xml.asAttributeSet(parser);
-        assertNotNull(attrs);
-        new ImageSwitcher(getContext(), attrs);
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mImageSwitcher = (ImageSwitcher) mActivity.findViewById(R.id.switcher);
     }
 
-    public void testSetImageResource() {
-        // new the ImageSwitcher instance
-        ImageSwitcher imageSwitcher = new ImageSwitcher(getContext());
-        ImageView iv = new ImageView(getContext());
-        imageSwitcher.addView(iv);
-        ImageView iv1 = new ImageView(getContext());
-        imageSwitcher.addView(iv1);
+    @Test
+    public void testConstructor() {
+        new ImageSwitcher(mActivity);
 
-        assertSame(iv, imageSwitcher.getCurrentView());
-        imageSwitcher.setImageResource(R.drawable.scenery);
-        assertSame(iv1, imageSwitcher.getCurrentView());
-        Resources resources = getContext().getResources();
+        new ImageSwitcher(mActivity, null);
+
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.imageswitcher_layout);
+        AttributeSet attrs = Xml.asAttributeSet(parser);
+        assertNotNull(attrs);
+        new ImageSwitcher(mActivity, attrs);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetImageResource() {
+        ImageView iv = new ImageView(mActivity);
+        mImageSwitcher.addView(iv);
+        ImageView iv1 = new ImageView(mActivity);
+        mImageSwitcher.addView(iv1);
+
+        assertSame(iv, mImageSwitcher.getCurrentView());
+        mImageSwitcher.setImageResource(R.drawable.scenery);
+        assertSame(iv1, mImageSwitcher.getCurrentView());
+        Resources resources = mActivity.getResources();
         Drawable drawable = resources.getDrawable(R.drawable.scenery);
         BitmapDrawable sceneryBitmap = (BitmapDrawable) drawable;
         BitmapDrawable currViewBitmap =
-            (BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
+            (BitmapDrawable) ((ImageView) mImageSwitcher.getCurrentView()).getDrawable();
         WidgetTestUtils.assertEquals(sceneryBitmap.getBitmap(), currViewBitmap.getBitmap());
 
-        imageSwitcher.setImageResource(R.drawable.testimage);
-        assertSame(iv, imageSwitcher.getCurrentView());
+        mImageSwitcher.setImageResource(R.drawable.testimage);
+        assertSame(iv, mImageSwitcher.getCurrentView());
         drawable = resources.getDrawable(R.drawable.testimage);
         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
         currViewBitmap =
-            (BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
+            (BitmapDrawable) ((ImageView) mImageSwitcher.getCurrentView()).getDrawable();
         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), currViewBitmap.getBitmap());
 
-        imageSwitcher.setImageResource(-1);
-        assertNull(((ImageView) imageSwitcher.getCurrentView()).getDrawable());
+        mImageSwitcher.setImageResource(-1);
+        assertNull(((ImageView) mImageSwitcher.getCurrentView()).getDrawable());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetImageURI() {
-        // new the ImageSwitcher instance
-        ImageSwitcher imageSwitcher = new ImageSwitcher(getContext());
-        ImageView iv = new ImageView(getContext());
-        imageSwitcher.addView(iv);
-        ImageView iv1 = new ImageView(getContext());
-        imageSwitcher.addView(iv1);
+        ImageView iv = new ImageView(mActivity);
+        mImageSwitcher.addView(iv);
+        ImageView iv1 = new ImageView(mActivity);
+        mImageSwitcher.addView(iv1);
 
-        File dbDir = getContext().getDir("tests", Context.MODE_PRIVATE);
+        File dbDir = mActivity.getDir("tests", Context.MODE_PRIVATE);
         File imagefile = new File(dbDir, "tempimage.jpg");
         if (imagefile.exists()) {
             imagefile.delete();
         }
         createSampleImage(imagefile, R.raw.testimage);
 
-        assertSame(iv, imageSwitcher.getCurrentView());
+        assertSame(iv, mImageSwitcher.getCurrentView());
         Uri uri = Uri.parse(imagefile.getPath());
-        imageSwitcher.setImageURI(uri);
-        assertSame(iv1, imageSwitcher.getCurrentView());
+        mImageSwitcher.setImageURI(uri);
+        assertSame(iv1, mImageSwitcher.getCurrentView());
 
         BitmapDrawable currViewBitmap =
-            (BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
+            (BitmapDrawable) ((ImageView) mImageSwitcher.getCurrentView()).getDrawable();
         Bitmap testImageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
-                getContext().getResources(), R.raw.testimage,
+                mActivity.getResources(), R.raw.testimage,
                 currViewBitmap.getBitmap().getConfig());
         WidgetTestUtils.assertEquals(testImageBitmap, currViewBitmap.getBitmap());
 
         createSampleImage(imagefile, R.raw.scenery);
         uri = Uri.parse(imagefile.getPath());
-        imageSwitcher.setImageURI(uri);
-        assertSame(iv, imageSwitcher.getCurrentView());
+        mImageSwitcher.setImageURI(uri);
+        assertSame(iv, mImageSwitcher.getCurrentView());
         Bitmap sceneryImageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
-                getContext().getResources(), R.raw.scenery,
+                mActivity.getResources(), R.raw.scenery,
                 currViewBitmap.getBitmap().getConfig());
         currViewBitmap =
-            (BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
+            (BitmapDrawable) ((ImageView) mImageSwitcher.getCurrentView()).getDrawable();
         WidgetTestUtils.assertEquals(sceneryImageBitmap, currViewBitmap.getBitmap());
 
         imagefile.delete();
 
-        imageSwitcher.setImageURI(null);
+        mImageSwitcher.setImageURI(null);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetImageDrawable() {
-        ImageSwitcher imageSwitcher = new ImageSwitcher(getContext());
-        ImageView iv = new ImageView(getContext());
-        imageSwitcher.addView(iv);
-        ImageView iv1 = new ImageView(getContext());
-        imageSwitcher.addView(iv1);
+        ImageView iv = new ImageView(mActivity);
+        mImageSwitcher.addView(iv);
+        ImageView iv1 = new ImageView(mActivity);
+        mImageSwitcher.addView(iv1);
 
-        Resources resources = getContext().getResources();
-        assertSame(iv, imageSwitcher.getCurrentView());
+        Resources resources = mActivity.getResources();
+        assertSame(iv, mImageSwitcher.getCurrentView());
         Drawable drawable = resources.getDrawable(R.drawable.scenery);
-        imageSwitcher.setImageDrawable(drawable);
-        assertSame(iv1, imageSwitcher.getCurrentView());
-        assertSame(drawable, ((ImageView) imageSwitcher.getCurrentView()).getDrawable());
+        mImageSwitcher.setImageDrawable(drawable);
+        assertSame(iv1, mImageSwitcher.getCurrentView());
+        assertSame(drawable, ((ImageView) mImageSwitcher.getCurrentView()).getDrawable());
 
         drawable = resources.getDrawable(R.drawable.testimage);
-        imageSwitcher.setImageDrawable(drawable);
-        assertSame(iv, imageSwitcher.getCurrentView());
-        assertSame(drawable, ((ImageView) imageSwitcher.getCurrentView()).getDrawable());
+        mImageSwitcher.setImageDrawable(drawable);
+        assertSame(iv, mImageSwitcher.getCurrentView());
+        assertSame(drawable, ((ImageView) mImageSwitcher.getCurrentView()).getDrawable());
 
-        imageSwitcher.setImageDrawable(null);
+        mImageSwitcher.setImageDrawable(null);
     }
 
     private void createSampleImage(File imagefile, int resid) {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = getContext().getResources().openRawResource(resid);
-            target = new FileOutputStream(imagefile);
-
+        try (InputStream source = mActivity.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);
             }
         } catch (IOException e) {
             fail(e.getMessage());
-        } 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/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..2b55ed5 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -16,60 +16,80 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+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 android.app.Activity;
+import android.content.Context;
+import android.content.res.ColorStateList;
+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.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.cts.util.TestUtils;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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;
 
-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 android.app.Activity;
-import android.content.Context;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.BitmapDrawable;
-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.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 static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
-
-
 /**
  * Test {@link ImageView}.
  */
-@SmallTest
-public class ImageViewTest extends ActivityInstrumentationTestCase<ImageViewCtsActivity> {
-    private ImageView mImageView;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ImageViewTest {
     private Activity mActivity;
+    private ImageView mImageViewRegular;
 
-    public ImageViewTest() {
-        super("android.widget.cts", ImageViewCtsActivity.class);
+    @Rule
+    public ActivityTestRule<ImageViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ImageViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mImageViewRegular = (ImageView) mActivity.findViewById(R.id.imageview_regular);
     }
 
     /**
@@ -83,40 +103,18 @@
     }
 
     private void createSampleImage(File imagefile, int resid) {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = mActivity.getResources().openRawResource(resid);
-            target = new FileOutputStream(imagefile);
-
+        try (InputStream source = mActivity.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);
             }
         } catch (IOException e) {
             fail(e.getMessage());
-        } finally {
-            try {
-                if (source != null) {
-                    source.close();
-                }
-                if (target != null) {
-                    target.close();
-                }
-            } catch (IOException ignored) {
-                // Ignore the IOException.
-            }
         }
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mImageView = null;
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new ImageView(mActivity);
 
@@ -130,114 +128,122 @@
         AttributeSet attrs = Xml.asAttributeSet(parser);
         new ImageView(mActivity, attrs);
         new ImageView(mActivity, attrs, 0);
-
-        try {
-            new ImageView(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ImageView(null, null, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new ImageView(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new ImageView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        new ImageView(null, null, -1);
+    }
+
+    @UiThreadTest
+    @Test
     public void testInvalidateDrawable() {
-        ImageView imageView = new ImageView(mActivity);
-        imageView.invalidateDrawable(null);
+        mImageViewRegular.invalidateDrawable(null);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetAdjustViewBounds() {
-        ImageView imageView = new ImageView(mActivity);
-        imageView.setScaleType(ScaleType.FIT_XY);
+        mImageViewRegular.setScaleType(ScaleType.FIT_XY);
 
-        imageView.setAdjustViewBounds(false);
-        assertFalse(imageView.getAdjustViewBounds());
-        assertEquals(ScaleType.FIT_XY, imageView.getScaleType());
+        mImageViewRegular.setAdjustViewBounds(false);
+        assertFalse(mImageViewRegular.getAdjustViewBounds());
+        assertEquals(ScaleType.FIT_XY, mImageViewRegular.getScaleType());
 
-        imageView.setAdjustViewBounds(true);
-        assertTrue(imageView.getAdjustViewBounds());
-        assertEquals(ScaleType.FIT_CENTER, imageView.getScaleType());
+        mImageViewRegular.setAdjustViewBounds(true);
+        assertTrue(mImageViewRegular.getAdjustViewBounds());
+        assertEquals(ScaleType.FIT_CENTER, mImageViewRegular.getScaleType());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetMaxWidth() {
-        ImageView imageView = new ImageView(mActivity);
-        imageView.setMaxWidth(120);
-        imageView.setMaxWidth(-1);
+        mImageViewRegular.setMaxWidth(120);
+        mImageViewRegular.setMaxWidth(-1);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetMaxHeight() {
-        ImageView imageView = new ImageView(mActivity);
-        imageView.setMaxHeight(120);
-        imageView.setMaxHeight(-1);
+        mImageViewRegular.setMaxHeight(120);
+        mImageViewRegular.setMaxHeight(-1);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetDrawable() {
-        final ImageView imageView = new ImageView(mActivity);
         final PaintDrawable drawable1 = new PaintDrawable();
         final PaintDrawable drawable2 = new PaintDrawable();
 
-        assertNull(imageView.getDrawable());
+        assertNull(mImageViewRegular.getDrawable());
 
-        imageView.setImageDrawable(drawable1);
-        assertEquals(drawable1, imageView.getDrawable());
-        assertNotSame(drawable2, imageView.getDrawable());
+        mImageViewRegular.setImageDrawable(drawable1);
+        assertEquals(drawable1, mImageViewRegular.getDrawable());
+        assertNotSame(drawable2, mImageViewRegular.getDrawable());
     }
 
     @UiThreadTest
+    @Test
     public void testSetImageIcon() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.setImageIcon(null);
-        assertNull(mImageView.getDrawable());
+        mImageViewRegular.setImageIcon(null);
+        assertNull(mImageViewRegular.getDrawable());
 
         Icon icon = Icon.createWithResource(mActivity, R.drawable.testimage);
-        mImageView.setImageIcon(icon);
-        assertTrue(mImageView.isLayoutRequested());
-        assertNotNull(mImageView.getDrawable());
+        mImageViewRegular.setImageIcon(icon);
+        assertTrue(mImageViewRegular.isLayoutRequested());
+        assertNotNull(mImageViewRegular.getDrawable());
         Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
-        Drawable imageViewDrawable = mImageView.getDrawable();
+        Drawable imageViewDrawable = mImageViewRegular.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
     }
 
     @UiThreadTest
+    @Test
     public void testSetImageResource() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.setImageResource(-1);
-        assertNull(mImageView.getDrawable());
+        mImageViewRegular.setImageResource(-1);
+        assertNull(mImageViewRegular.getDrawable());
 
-        mImageView.setImageResource(R.drawable.testimage);
-        assertTrue(mImageView.isLayoutRequested());
-        assertNotNull(mImageView.getDrawable());
+        mImageViewRegular.setImageResource(R.drawable.testimage);
+        assertTrue(mImageViewRegular.isLayoutRequested());
+        assertNotNull(mImageViewRegular.getDrawable());
         Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
-        Drawable imageViewDrawable = mImageView.getDrawable();
+        Drawable imageViewDrawable = mImageViewRegular.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
     }
 
     @UiThreadTest
+    @Test
     public void testSetImageURI() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.setImageURI(null);
-        assertNull(mImageView.getDrawable());
+        mImageViewRegular.setImageURI(null);
+        assertNull(mImageViewRegular.getDrawable());
 
-        File dbDir = getInstrumentation().getTargetContext().getDir("tests",
-                Context.MODE_PRIVATE);
+        File dbDir = mActivity.getDir("tests", Context.MODE_PRIVATE);
         File imagefile = new File(dbDir, "tempimage.jpg");
         if (imagefile.exists()) {
             imagefile.delete();
         }
         createSampleImage(imagefile, R.raw.testimage);
         final String path = imagefile.getPath();
-        mImageView.setImageURI(Uri.parse(path));
-        assertTrue(mImageView.isLayoutRequested());
-        assertNotNull(mImageView.getDrawable());
+        mImageViewRegular.setImageURI(Uri.parse(path));
+        assertTrue(mImageViewRegular.isLayoutRequested());
+        assertNotNull(mImageViewRegular.getDrawable());
 
-        Drawable imageViewDrawable = mImageView.getDrawable();
+        Drawable imageViewDrawable = mImageViewRegular.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
         Bitmap.Config viewConfig = imageViewBitmap.getBitmap().getConfig();
         Bitmap testimageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
@@ -247,179 +253,178 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetImageDrawable() {
-        mImageView = findImageViewById(R.id.imageview);
-
-        mImageView.setImageDrawable(null);
-        assertNull(mImageView.getDrawable());
+        mImageViewRegular.setImageDrawable(null);
+        assertNull(mImageViewRegular.getDrawable());
 
         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
-        mImageView.setImageDrawable(drawable);
-        assertTrue(mImageView.isLayoutRequested());
-        assertNotNull(mImageView.getDrawable());
+        mImageViewRegular.setImageDrawable(drawable);
+        assertTrue(mImageViewRegular.isLayoutRequested());
+        assertNotNull(mImageViewRegular.getDrawable());
         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
-        Drawable imageViewDrawable = mImageView.getDrawable();
+        Drawable imageViewDrawable = mImageViewRegular.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
     }
 
     @UiThreadTest
+    @Test
     public void testSetImageBitmap() {
-        mImageView = findImageViewById(R.id.imageview);
-
-        mImageView.setImageBitmap(null);
+        mImageViewRegular.setImageBitmap(null);
         // A BitmapDrawable is always created for the ImageView.
-        assertNotNull(mImageView.getDrawable());
+        assertNotNull(mImageViewRegular.getDrawable());
 
         final Bitmap bitmap =
             BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.testimage);
-        mImageView.setImageBitmap(bitmap);
-        assertTrue(mImageView.isLayoutRequested());
-        assertNotNull(mImageView.getDrawable());
-        Drawable imageViewDrawable = mImageView.getDrawable();
+        mImageViewRegular.setImageBitmap(bitmap);
+        assertTrue(mImageViewRegular.isLayoutRequested());
+        assertNotNull(mImageViewRegular.getDrawable());
+        Drawable imageViewDrawable = mImageViewRegular.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
         WidgetTestUtils.assertEquals(bitmap, imageViewBitmap.getBitmap());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetImageState() {
-        mImageView = new ImageView(mActivity);
         int[] state = new int[8];
-        mImageView.setImageState(state, false);
-        assertSame(state, mImageView.onCreateDrawableState(0));
+        mImageViewRegular.setImageState(state, false);
+        assertSame(state, mImageViewRegular.onCreateDrawableState(0));
     }
 
+    @UiThreadTest
+    @Test
     public void testSetSelected() {
-        mImageView = new ImageView(mActivity);
-        assertFalse(mImageView.isSelected());
+        assertFalse(mImageViewRegular.isSelected());
 
-        mImageView.setSelected(true);
-        assertTrue(mImageView.isSelected());
+        mImageViewRegular.setSelected(true);
+        assertTrue(mImageViewRegular.isSelected());
 
-        mImageView.setSelected(false);
-        assertFalse(mImageView.isSelected());
+        mImageViewRegular.setSelected(false);
+        assertFalse(mImageViewRegular.isSelected());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetImageLevel() {
         PaintDrawable drawable = new PaintDrawable();
         drawable.setLevel(0);
 
-        ImageView imageView = new ImageView(mActivity);
-        imageView.setImageDrawable(drawable);
-        imageView.setImageLevel(1);
+        mImageViewRegular.setImageDrawable(drawable);
+        mImageViewRegular.setImageLevel(1);
         assertEquals(1, drawable.getLevel());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessScaleType() {
-        final ImageView imageView = new ImageView(mActivity);
+        assertNotNull(mImageViewRegular.getScaleType());
 
-        try {
-            imageView.setScaleType(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-        assertNotNull(imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER);
+        assertEquals(ImageView.ScaleType.CENTER, mImageViewRegular.getScaleType());
 
-        imageView.setScaleType(ImageView.ScaleType.CENTER);
-        assertEquals(ImageView.ScaleType.CENTER, imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.MATRIX);
+        assertEquals(ImageView.ScaleType.MATRIX, mImageViewRegular.getScaleType());
 
-        imageView.setScaleType(ImageView.ScaleType.MATRIX);
-        assertEquals(ImageView.ScaleType.MATRIX, imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.FIT_START);
+        assertEquals(ImageView.ScaleType.FIT_START, mImageViewRegular.getScaleType());
 
-        imageView.setScaleType(ImageView.ScaleType.FIT_START);
-        assertEquals(ImageView.ScaleType.FIT_START, imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.FIT_END);
+        assertEquals(ImageView.ScaleType.FIT_END, mImageViewRegular.getScaleType());
 
-        imageView.setScaleType(ImageView.ScaleType.FIT_END);
-        assertEquals(ImageView.ScaleType.FIT_END, imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER_CROP);
+        assertEquals(ImageView.ScaleType.CENTER_CROP, mImageViewRegular.getScaleType());
 
-        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
-        assertEquals(ImageView.ScaleType.CENTER_CROP, imageView.getScaleType());
-
-        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        assertEquals(ImageView.ScaleType.CENTER_INSIDE, imageView.getScaleType());
+        mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        assertEquals(ImageView.ScaleType.CENTER_INSIDE, mImageViewRegular.getScaleType());
     }
 
-    public void testAccessImageMatrix() {
-        final ImageView imageView = new ImageView(mActivity);
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testSetNullScaleType() {
+        mImageViewRegular.setScaleType(null);
+    }
 
-        imageView.setImageMatrix(null);
-        assertNotNull(imageView.getImageMatrix());
+    @UiThreadTest
+    @Test
+    public void testAccessImageMatrix() {
+        mImageViewRegular.setImageMatrix(null);
+        assertNotNull(mImageViewRegular.getImageMatrix());
 
         final Matrix matrix = new Matrix();
-        imageView.setImageMatrix(matrix);
-        assertEquals(matrix, imageView.getImageMatrix());
+        mImageViewRegular.setImageMatrix(matrix);
+        assertEquals(matrix, mImageViewRegular.getImageMatrix());
     }
 
     @UiThreadTest
+    @Test
     public void testAccessBaseline() {
-        mImageView = findImageViewById(R.id.imageview);
-
-        mImageView.setImageDrawable(null);
-        assertNull(mImageView.getDrawable());
+        mImageViewRegular.setImageDrawable(null);
+        assertNull(mImageViewRegular.getDrawable());
 
         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
-        mImageView.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(drawable);
 
-        assertEquals(-1, mImageView.getBaseline());
+        assertEquals(-1, mImageViewRegular.getBaseline());
 
-        mImageView.setBaseline(50);
-        assertEquals(50, mImageView.getBaseline());
+        mImageViewRegular.setBaseline(50);
+        assertEquals(50, mImageViewRegular.getBaseline());
 
-        mImageView.setBaselineAlignBottom(true);
-        assertTrue(mImageView.getBaselineAlignBottom());
-        assertEquals(mImageView.getMeasuredHeight(), mImageView.getBaseline());
+        mImageViewRegular.setBaselineAlignBottom(true);
+        assertTrue(mImageViewRegular.getBaselineAlignBottom());
+        assertEquals(mImageViewRegular.getMeasuredHeight(), mImageViewRegular.getBaseline());
 
-        mImageView.setBaselineAlignBottom(false);
-        assertFalse(mImageView.getBaselineAlignBottom());
-        assertEquals(50, mImageView.getBaseline());
+        mImageViewRegular.setBaselineAlignBottom(false);
+        assertFalse(mImageViewRegular.getBaselineAlignBottom());
+        assertEquals(50, mImageViewRegular.getBaseline());
     }
 
     @UiThreadTest
+    @Test
     public void testSetColorFilter1() {
-        mImageView = findImageViewById(R.id.imageview);
-
         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
-        mImageView.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(drawable);
 
-        mImageView.setColorFilter(null);
+        mImageViewRegular.setColorFilter(null);
         assertNull(drawable.getColorFilter());
 
-        mImageView.setColorFilter(0, PorterDuff.Mode.CLEAR);
+        mImageViewRegular.setColorFilter(0, PorterDuff.Mode.CLEAR);
         assertNotNull(drawable.getColorFilter());
-        assertNotNull(mImageView.getColorFilter());
+        assertNotNull(mImageViewRegular.getColorFilter());
     }
 
     @UiThreadTest
+    @Test
     public void testClearColorFilter() {
-        mImageView = findImageViewById(R.id.imageview);
-
         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
-        mImageView.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(drawable);
 
         ColorFilter cf = new ColorFilter();
-        mImageView.setColorFilter(cf);
+        mImageViewRegular.setColorFilter(cf);
 
-        mImageView.clearColorFilter();
+        mImageViewRegular.clearColorFilter();
         assertNull(drawable.getColorFilter());
-        assertNull(mImageView.getColorFilter());
+        assertNull(mImageViewRegular.getColorFilter());
     }
 
     @UiThreadTest
+    @Test
     public void testSetColorFilter2() {
-        mImageView = findImageViewById(R.id.imageview);
-
         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
-        mImageView.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(drawable);
 
-        mImageView.setColorFilter(null);
+        mImageViewRegular.setColorFilter(null);
         assertNull(drawable.getColorFilter());
-        assertNull(mImageView.getColorFilter());
+        assertNull(mImageViewRegular.getColorFilter());
 
         ColorFilter cf = new ColorFilter();
-        mImageView.setColorFilter(cf);
+        mImageViewRegular.setColorFilter(cf);
         assertSame(cf, drawable.getColorFilter());
-        assertSame(cf, mImageView.getColorFilter());
+        assertSame(cf, mImageViewRegular.getColorFilter());
     }
 
+    @Test
     public void testDrawableStateChanged() {
         MockImageView imageView = spy(new MockImageView(mActivity));
         Drawable selectorDrawable = mActivity.getDrawable(R.drawable.statelistdrawable);
@@ -433,28 +438,35 @@
         // Test that our image view has indeed called its own drawableStateChanged()
         verify(imageView, times(1)).drawableStateChanged();
         // And verify that image view's state matches that of our drawable
-        Assert.assertArrayEquals(imageView.getDrawableState(), selectorDrawable.getState());
+        assertArrayEquals(imageView.getDrawableState(), selectorDrawable.getState());
     }
 
+    @Test
     public void testOnCreateDrawableState() {
         MockImageView mockImageView = new MockImageView(mActivity);
 
-        assertEquals(MockImageView.getEnabledStateSet(), mockImageView.onCreateDrawableState(0));
+        assertArrayEquals(MockImageView.getEnabledStateSet(),
+                mockImageView.onCreateDrawableState(0));
 
         int[] expected = new int[]{1, 2, 3};
         mockImageView.setImageState(expected, false);
-        assertSame(expected, mockImageView.onCreateDrawableState(1));
+        assertArrayEquals(expected, mockImageView.onCreateDrawableState(1));
 
         mockImageView.setImageState(expected, true);
-        try {
-            mockImageView.onCreateDrawableState(-1);
-            fail("should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testOnCreateDrawableStateInvalid() {
+        MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
+        mockImageView.setImageState(new int[] {1, 2, 3}, true);
+        mockImageView.onCreateDrawableState(-1);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnDraw() {
-        MockImageView mockImageView = new MockImageView(mActivity);
+        MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
+
         Drawable drawable = spy(mActivity.getDrawable(R.drawable.icon_red));
         mockImageView.setImageDrawable(drawable);
         mockImageView.onDraw(new Canvas());
@@ -462,13 +474,15 @@
         verify(drawable, atLeastOnce()).draw(any(Canvas.class));
     }
 
+    @UiThreadTest
+    @Test
     public void testOnMeasure() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.measure(200, 150);
-        assertTrue(mImageView.getMeasuredWidth() <= 200);
-        assertTrue(mImageView.getMeasuredHeight() <= 150);
+        mImageViewRegular.measure(200, 150);
+        assertTrue(mImageViewRegular.getMeasuredWidth() <= 200);
+        assertTrue(mImageViewRegular.getMeasuredHeight() <= 150);
     }
 
+    @Test
     public void testSetFrame() {
         MockImageView mockImageView = spy(new MockImageView(mActivity));
         verify(mockImageView, never()).onSizeChanged(anyInt(), anyInt(), anyInt(), anyInt());
@@ -486,8 +500,11 @@
         verify(mockImageView, times(1)).onSizeChanged(anyInt(), anyInt(), anyInt(), anyInt());
     }
 
+    @UiThreadTest
+    @Test
     public void testVerifyDrawable() {
-        MockImageView mockImageView = new MockImageView(mActivity);
+        MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
+
         Drawable drawable = new ColorDrawable(0xFFFF0000);
         mockImageView.setImageDrawable(drawable);
         Drawable backgroundDrawable = new ColorDrawable(0xFF0000FF);
@@ -500,109 +517,114 @@
     }
 
     @UiThreadTest
+    @Test
     public void testImageTintBasics() {
-        mImageView = findImageViewById(R.id.image_tint);
+        ImageView imageViewTinted = (ImageView) mActivity.findViewById(R.id.imageview_tint);
 
         assertEquals("Image tint inflated correctly",
-                Color.WHITE, mImageView.getImageTintList().getDefaultColor());
+                Color.WHITE, imageViewTinted.getImageTintList().getDefaultColor());
         assertEquals("Image tint mode inflated correctly",
-                PorterDuff.Mode.SRC_OVER, mImageView.getImageTintMode());
+                PorterDuff.Mode.SRC_OVER, imageViewTinted.getImageTintMode());
 
-        mImageView.setImageTintMode(PorterDuff.Mode.SRC_IN);
-        assertEquals(PorterDuff.Mode.SRC_IN, mImageView.getImageTintMode());
+        imageViewTinted.setImageTintMode(PorterDuff.Mode.SRC_IN);
+        assertEquals(PorterDuff.Mode.SRC_IN, imageViewTinted.getImageTintMode());
     }
 
+    @UiThreadTest
+    @Test
     public void testImageTintDrawableUpdates() {
         Drawable drawable = spy(mActivity.getDrawable(R.drawable.icon_red));
 
-        ImageView view = new ImageView(mActivity);
-        view.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(drawable);
         // No image tint applied by default
         verify(drawable, never()).setTintList(any(ColorStateList.class));
 
-        view.setImageTintList(ColorStateList.valueOf(Color.WHITE));
+        mImageViewRegular.setImageTintList(ColorStateList.valueOf(Color.WHITE));
         // Image tint applied when setImageTintList() called after setImageDrawable()
         verify(drawable, times(1)).setTintList(any(ColorStateList.class));
 
-        view.setImageDrawable(null);
-        view.setImageDrawable(drawable);
+        mImageViewRegular.setImageDrawable(null);
+        mImageViewRegular.setImageDrawable(drawable);
         // Image tint applied when setImageTintList() called before setImageDrawable()
         verify(drawable, times(2)).setTintList(any(ColorStateList.class));
     }
 
     @UiThreadTest
+    @Test
     public void testImageTintVisuals() {
-        mImageView = findImageViewById(R.id.image_tint_with_source);
-        TestUtils.assertAllPixelsOfColor("All pixels should be white", mImageView,
+        ImageView imageViewTinted = (ImageView) mActivity.findViewById(
+                R.id.imageview_tint_with_source);
+
+        TestUtils.assertAllPixelsOfColor("All pixels should be white", imageViewTinted,
                 0xFFFFFFFF, 1, false);
 
         // Use translucent white tint. Together with SRC_OVER mode (defined in XML) the end
         // result should be a fully opaque image view with solid fill color in between red
         // and white.
-        mImageView.setImageTintList(ColorStateList.valueOf(0x80FFFFFF));
-        TestUtils.assertAllPixelsOfColor("All pixels should be light red", mImageView,
+        imageViewTinted.setImageTintList(ColorStateList.valueOf(0x80FFFFFF));
+        TestUtils.assertAllPixelsOfColor("All pixels should be light red", imageViewTinted,
                 0xFFFF8080, 1, false);
 
         // Switch to SRC_IN mode. This should completely ignore the original drawable set on
         // the image view and use the last set tint color (50% alpha white).
-        mImageView.setImageTintMode(PorterDuff.Mode.SRC_IN);
-        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha white", mImageView,
+        imageViewTinted.setImageTintMode(PorterDuff.Mode.SRC_IN);
+        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha white", imageViewTinted,
                 0x80FFFFFF, 1, false);
 
         // Switch to DST mode. This should completely ignore the last set tint color and use the
         // the original drawable set on the image view.
-        mImageView.setImageTintMode(PorterDuff.Mode.DST);
-        TestUtils.assertAllPixelsOfColor("All pixels should be red", mImageView,
+        imageViewTinted.setImageTintMode(PorterDuff.Mode.DST);
+        TestUtils.assertAllPixelsOfColor("All pixels should be red", imageViewTinted,
                 0xFFFF0000, 1, false);
     }
 
     @UiThreadTest
+    @Test
     public void testAlpha() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.setImageResource(R.drawable.blue_fill);
+        mImageViewRegular.setImageResource(R.drawable.blue_fill);
 
-        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageView,
+        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
                 0xFF0000FF, 1, false);
 
-        mImageView.setAlpha(128);
-        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageView,
+        mImageViewRegular.setAlpha(128);
+        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageViewRegular,
                 0x800000FF, 1, false);
 
-        mImageView.setAlpha(0);
-        TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageView,
+        mImageViewRegular.setAlpha(0);
+        TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageViewRegular,
                 0x00000000, 1, false);
 
-        mImageView.setAlpha(255);
-        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageView,
+        mImageViewRegular.setAlpha(255);
+        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
                 0xFF0000FF, 1, false);
     }
 
     @UiThreadTest
+    @Test
     public void testImageAlpha() {
-        mImageView = findImageViewById(R.id.imageview);
-        mImageView.setImageResource(R.drawable.blue_fill);
+        mImageViewRegular.setImageResource(R.drawable.blue_fill);
 
-        assertEquals(255, mImageView.getImageAlpha());
-        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageView,
+        assertEquals(255, mImageViewRegular.getImageAlpha());
+        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
                 0xFF0000FF, 1, false);
 
-        mImageView.setImageAlpha(128);
-        assertEquals(128, mImageView.getImageAlpha());
-        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageView,
+        mImageViewRegular.setImageAlpha(128);
+        assertEquals(128, mImageViewRegular.getImageAlpha());
+        TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageViewRegular,
                 0x800000FF, 1, false);
 
-        mImageView.setImageAlpha(0);
-        assertEquals(0, mImageView.getImageAlpha());
-        TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageView,
+        mImageViewRegular.setImageAlpha(0);
+        assertEquals(0, mImageViewRegular.getImageAlpha());
+        TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageViewRegular,
                 0x00000000, 1, false);
 
-        mImageView.setImageAlpha(255);
-        assertEquals(255, mImageView.getImageAlpha());
-        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageView,
+        mImageViewRegular.setImageAlpha(255);
+        assertEquals(255, mImageViewRegular.getImageAlpha());
+        TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
                 0xFF0000FF, 1, false);
     }
 
-    protected static class MockImageView extends ImageView {
+    public static class MockImageView extends ImageView {
         public MockImageView(Context context) {
             super(context);
         }
@@ -619,29 +641,31 @@
             return ENABLED_STATE_SET;
         }
 
-        public static int[] getPressedEnabledStateSet() {
-            return PRESSED_ENABLED_STATE_SET;
-        }
         @Override
         protected void drawableStateChanged() {
             super.drawableStateChanged();
         }
+
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
         }
+
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         }
+
         @Override
         protected boolean onSetAlpha(int alpha) {
             return super.onSetAlpha(alpha);
         }
+
         @Override
         protected boolean setFrame(int l, int t, int r, int b) {
             return super.setFrame(l, t, r, b);
         }
+
         @Override
         protected boolean verifyDrawable(Drawable dr) {
             return super.verifyDrawable(dr);
diff --git a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
index 2369c5a..76c2ef6 100644
--- a/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LayoutDirectionTest.java
@@ -16,21 +16,42 @@
 
 package android.widget.cts;
 
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.ViewGroup;
-import android.widget.*;
-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;
+import static android.view.View.LAYOUT_DIRECTION_LTR;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
 
-public class LayoutDirectionTest extends ActivityInstrumentationTestCase2<LayoutDirectionCtsActivity> {
+import static org.junit.Assert.assertEquals;
 
-    public LayoutDirectionTest() {
-        super(LayoutDirectionCtsActivity.class);
+import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.GridLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TableLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LayoutDirectionTest {
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<LayoutDirectionCtsActivity> mActivityRule =
+            new ActivityTestRule<>(LayoutDirectionCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     private void checkDefaultDirectionForOneLayoutWithCode(ViewGroup vg) {
@@ -38,15 +59,16 @@
     }
 
     @UiThreadTest
+    @Test
     public void testLayoutDirectionDefaults() {
-        checkDefaultDirectionForOneLayoutWithCode(new LinearLayout(getActivity()));
-        checkDefaultDirectionForOneLayoutWithCode(new FrameLayout(getActivity()));
-        checkDefaultDirectionForOneLayoutWithCode(new TableLayout(getActivity()));
-        checkDefaultDirectionForOneLayoutWithCode(new RelativeLayout(getActivity()));
-        checkDefaultDirectionForOneLayoutWithCode(new GridLayout(getActivity()));
+        checkDefaultDirectionForOneLayoutWithCode(new LinearLayout(mActivity));
+        checkDefaultDirectionForOneLayoutWithCode(new FrameLayout(mActivity));
+        checkDefaultDirectionForOneLayoutWithCode(new TableLayout(mActivity));
+        checkDefaultDirectionForOneLayoutWithCode(new RelativeLayout(mActivity));
+        checkDefaultDirectionForOneLayoutWithCode(new GridLayout(mActivity));
     }
 
-    private void checkDirectionForOneLayoutWithCode(ViewGroup vg) {
+    private void verifyDirectionForOneLayoutWithCode(ViewGroup vg) {
         vg.setLayoutDirection(LAYOUT_DIRECTION_LTR);
         assertEquals(LAYOUT_DIRECTION_LTR, vg.getLayoutDirection());
 
@@ -63,16 +85,17 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDirectionForAllLayoutsWithCode() {
-        checkDirectionForOneLayoutWithCode(new LinearLayout(getActivity()));
-        checkDirectionForOneLayoutWithCode(new FrameLayout(getActivity()));
-        checkDirectionForOneLayoutWithCode(new TableLayout(getActivity()));
-        checkDirectionForOneLayoutWithCode(new RelativeLayout(getActivity()));
-        checkDirectionForOneLayoutWithCode(new GridLayout(getActivity()));
+        verifyDirectionForOneLayoutWithCode(new LinearLayout(mActivity));
+        verifyDirectionForOneLayoutWithCode(new FrameLayout(mActivity));
+        verifyDirectionForOneLayoutWithCode(new TableLayout(mActivity));
+        verifyDirectionForOneLayoutWithCode(new RelativeLayout(mActivity));
+        verifyDirectionForOneLayoutWithCode(new GridLayout(mActivity));
     }
 
-    private void checkDirectionInheritanceForOneLayoutWithCode(ViewGroup parent) {
-        LinearLayout child = new LinearLayout(getActivity());
+    private void verifyDirectionInheritanceForOneLayoutWithCode(ViewGroup parent) {
+        LinearLayout child = new LinearLayout(mActivity);
         child.setLayoutDirection(LAYOUT_DIRECTION_INHERIT);
         parent.addView(child);
 
@@ -90,74 +113,87 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDirectionInheritanceForAllLayoutsWithCode() {
-        checkDirectionInheritanceForOneLayoutWithCode(new LinearLayout(getActivity()));
-        checkDirectionInheritanceForOneLayoutWithCode(new FrameLayout(getActivity()));
-        checkDirectionInheritanceForOneLayoutWithCode(new TableLayout(getActivity()));
-        checkDirectionInheritanceForOneLayoutWithCode(new RelativeLayout(getActivity()));
-        checkDirectionInheritanceForOneLayoutWithCode(new GridLayout(getActivity()));
+        verifyDirectionInheritanceForOneLayoutWithCode(new LinearLayout(mActivity));
+        verifyDirectionInheritanceForOneLayoutWithCode(new FrameLayout(mActivity));
+        verifyDirectionInheritanceForOneLayoutWithCode(new TableLayout(mActivity));
+        verifyDirectionInheritanceForOneLayoutWithCode(new RelativeLayout(mActivity));
+        verifyDirectionInheritanceForOneLayoutWithCode(new GridLayout(mActivity));
     }
 
-    private void checkDirectionForOneLayoutFromXml(int parentId, int parentDir, int parentResDir,
-                                                   int child1Id, int child1Dir, int child1ResDir,
-                                                   int child2Id, int child2Dir, int child2ResDir,
-                                                   int child3Id, int child3Dir, int child3ResDir,
-                                                   int child4Id, int child4Dir, int child4ResDir) {
-        ViewGroup ll = (ViewGroup) getActivity().findViewById(parentId);
+    private void verifyDirectionForOneLayoutFromXml(
+            int parentId, int parentDir, int parentResDir,
+            int child1Id, int child1Dir, int child1ResDir,
+            int child2Id, int child2Dir, int child2ResDir,
+            int child3Id, int child3Dir, int child3ResDir,
+            int child4Id, int child4Dir, int child4ResDir) {
+        ViewGroup ll = (ViewGroup) mActivity.findViewById(parentId);
         assertEquals(parentResDir, ll.getLayoutDirection());
 
-        ViewGroup child1 = (ViewGroup) getActivity().findViewById(child1Id);
+        ViewGroup child1 = (ViewGroup) mActivity.findViewById(child1Id);
         assertEquals(child1ResDir, child1.getLayoutDirection());
 
-        ViewGroup child2 = (ViewGroup) getActivity().findViewById(child2Id);
+        ViewGroup child2 = (ViewGroup) mActivity.findViewById(child2Id);
         assertEquals(child2ResDir, child2.getLayoutDirection());
 
-        ViewGroup child3 = (ViewGroup) getActivity().findViewById(child3Id);
+        ViewGroup child3 = (ViewGroup) mActivity.findViewById(child3Id);
         assertEquals(child3ResDir, child3.getLayoutDirection());
 
-        ViewGroup child4 = (ViewGroup) getActivity().findViewById(child4Id);
+        ViewGroup child4 = (ViewGroup) mActivity.findViewById(child4Id);
         assertEquals(child4ResDir, child4.getLayoutDirection());
     }
 
     @UiThreadTest
+    @Test
     public void testDirectionFromXml() {
         // We only test LinearLayout as the others would be the same (they extend ViewGroup / View)
-        checkDirectionForOneLayoutFromXml(
+        verifyDirectionForOneLayoutFromXml(
                 R.id.layout_linearlayout_ltr, LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_LTR,
                 R.id.layout_linearlayout_ltr_child_1, LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_LTR,
                 R.id.layout_linearlayout_ltr_child_2, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_RTL,
                 // parent is LTR
-                R.id.layout_linearlayout_ltr_child_3, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LTR,
+                R.id.layout_linearlayout_ltr_child_3, LAYOUT_DIRECTION_INHERIT,
+                    LAYOUT_DIRECTION_LTR,
                 // running with English locale
-                R.id.layout_linearlayout_ltr_child_4, LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR);
+                R.id.layout_linearlayout_ltr_child_4, LAYOUT_DIRECTION_LOCALE,
+                    LAYOUT_DIRECTION_LTR);
 
-        checkDirectionForOneLayoutFromXml(
+        verifyDirectionForOneLayoutFromXml(
                 R.id.layout_linearlayout_rtl, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_RTL,
                 R.id.layout_linearlayout_rtl_child_1, LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_LTR,
                 R.id.layout_linearlayout_rtl_child_2, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_RTL,
                 // parent is RTL
-                R.id.layout_linearlayout_rtl_child_3, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_RTL,
+                R.id.layout_linearlayout_rtl_child_3, LAYOUT_DIRECTION_INHERIT,
+                    LAYOUT_DIRECTION_RTL,
                 // running with English locale
-                R.id.layout_linearlayout_rtl_child_4, LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR);
+                R.id.layout_linearlayout_rtl_child_4, LAYOUT_DIRECTION_LOCALE,
+                    LAYOUT_DIRECTION_LTR);
 
-        checkDirectionForOneLayoutFromXml(
+        verifyDirectionForOneLayoutFromXml(
                 // default is LTR
                 R.id.layout_linearlayout_inherit, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LTR,
-                R.id.layout_linearlayout_inherit_child_1, LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_LTR,
-                R.id.layout_linearlayout_inherit_child_2, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_RTL,
+                R.id.layout_linearlayout_inherit_child_1, LAYOUT_DIRECTION_LTR,
+                    LAYOUT_DIRECTION_LTR,
+                R.id.layout_linearlayout_inherit_child_2, LAYOUT_DIRECTION_RTL,
+                    LAYOUT_DIRECTION_RTL,
                 // parent is LTR
-                R.id.layout_linearlayout_inherit_child_3, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LTR,
+                R.id.layout_linearlayout_inherit_child_3, LAYOUT_DIRECTION_INHERIT,
+                    LAYOUT_DIRECTION_LTR,
                 // running with English locale
-                R.id.layout_linearlayout_inherit_child_4, LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR);
+                R.id.layout_linearlayout_inherit_child_4, LAYOUT_DIRECTION_LOCALE,
+                    LAYOUT_DIRECTION_LTR);
 
-        checkDirectionForOneLayoutFromXml(
+        verifyDirectionForOneLayoutFromXml(
                 // running with English locale
                 R.id.layout_linearlayout_locale, LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR,
                 R.id.layout_linearlayout_locale_child_1, LAYOUT_DIRECTION_LTR, LAYOUT_DIRECTION_LTR,
                 R.id.layout_linearlayout_locale_child_2, LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_RTL,
                 // parent is LTR
-                R.id.layout_linearlayout_locale_child_3, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LTR,
+                R.id.layout_linearlayout_locale_child_3, LAYOUT_DIRECTION_INHERIT,
+                    LAYOUT_DIRECTION_LTR,
                 // running with English locale
-                R.id.layout_linearlayout_locale_child_4, LAYOUT_DIRECTION_LOCALE, LAYOUT_DIRECTION_LTR);
+                R.id.layout_linearlayout_locale_child_4, LAYOUT_DIRECTION_LOCALE,
+                    LAYOUT_DIRECTION_LTR);
     }
 }
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..91d3ebc 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,15 +16,31 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
-import android.test.ActivityInstrumentationTestCase;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.ViewAsserts;
 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 +50,15 @@
 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 com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -42,134 +66,143 @@
 /**
  * Test {@link LinearLayout}.
  */
-public class LinearLayoutTest extends ActivityInstrumentationTestCase<LinearLayoutCtsActivity> {
-    private Context mContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class LinearLayoutTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
-    public LinearLayoutTest() {
-        super("android.widget.cts", LinearLayoutCtsActivity.class);
+    @Rule
+    public ActivityTestRule<LinearLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(LinearLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mContext = getInstrumentation().getTargetContext();
-    }
-
+    @Test
     public void testConstructor() {
-        new LinearLayout(mContext);
+        new LinearLayout(mActivity);
 
-        new LinearLayout(mContext, null);
+        new LinearLayout(mActivity, null);
 
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.linearlayout_layout);
+        XmlPullParser parser = mActivity.getResources().getXml(R.layout.linearlayout_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        new LinearLayout(mContext, attrs);
-
-        try {
-            new LinearLayout(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
+        new LinearLayout(mActivity, attrs);
     }
 
-    public void testAccessBaselineAligned() {
-        LinearLayout linearLayout = new LinearLayout(mContext);
-        linearLayout.setBaselineAligned(true);
-        assertTrue(linearLayout.isBaselineAligned());
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new LinearLayout(null, null);
+    }
 
-        linearLayout.setBaselineAligned(false);
-        assertFalse(linearLayout.isBaselineAligned());
+    @UiThreadTest
+    @Test
+    public void testAccessBaselineAligned() {
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
+        parent.setBaselineAligned(true);
+        assertTrue(parent.isBaselineAligned());
+
+        parent.setBaselineAligned(false);
+        assertFalse(parent.isBaselineAligned());
 
         // android:baselineAligned="false" in LinearLayout weightsum
-        linearLayout = (LinearLayout) mActivity.findViewById(R.id.weightsum);
-        assertFalse(linearLayout.isBaselineAligned());
+        parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
+        assertFalse(parent.isBaselineAligned());
 
         // default mBaselineAligned is true.
-        linearLayout = (LinearLayout) mActivity.findViewById(R.id.horizontal);
-        assertTrue(linearLayout.isBaselineAligned());
+        parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal);
+        assertTrue(parent.isBaselineAligned());
 
         // default mBaselineAligned is true.
         // Only applicable if {@link #mOrientation} is horizontal
-        linearLayout = (LinearLayout) mActivity.findViewById(R.id.vertical);
-        assertTrue(linearLayout.isBaselineAligned());
+        parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical);
+        assertTrue(parent.isBaselineAligned());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetBaseline() {
-        LinearLayout linearLayout = new LinearLayout(mContext);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
 
-        ListView lv1 = new ListView(mContext);
-        linearLayout.addView(lv1);
-        assertEquals(-1, linearLayout.getBaseline());
+        ListView lv1 = new ListView(mActivity);
+        parent.addView(lv1);
+        assertEquals(-1, parent.getBaseline());
 
-        ListView lv2 = new ListView(mContext);
-        linearLayout.addView(lv2);
-        linearLayout.setBaselineAlignedChildIndex(1);
+        ListView lv2 = new ListView(mActivity);
+        parent.addView(lv2);
+        parent.setBaselineAlignedChildIndex(1);
         try {
-            linearLayout.getBaseline();
+            parent.getBaseline();
             fail("LinearLayout.getBaseline() should throw exception here.");
         } catch (RuntimeException e) {
         }
 
-        MockListView lv3 = new MockListView(mContext);
-        linearLayout.addView(lv3);
-        linearLayout.setBaselineAlignedChildIndex(2);
-        assertEquals(lv3.getBaseline(), linearLayout.getBaseline());
+        ListView lv3 = new MockListView(mActivity);
+        parent.addView(lv3);
+        parent.setBaselineAlignedChildIndex(2);
+        assertEquals(lv3.getBaseline(), parent.getBaseline());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessBaselineAlignedChildIndex() {
-        LinearLayout linearLayout = new LinearLayout(mContext);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
+
         // set BaselineAlignedChildIndex
-        ListView lv1 = new ListView(mContext);
-        ListView lv2 = new ListView(mContext);
-        ListView lv3 = new ListView(mContext);
-        linearLayout.addView(lv1);
-        linearLayout.addView(lv2);
-        linearLayout.addView(lv3);
-        linearLayout.setBaselineAlignedChildIndex(1);
-        assertEquals(1, linearLayout.getBaselineAlignedChildIndex());
+        ListView lv1 = new ListView(mActivity);
+        ListView lv2 = new ListView(mActivity);
+        ListView lv3 = new ListView(mActivity);
+        parent.addView(lv1);
+        parent.addView(lv2);
+        parent.addView(lv3);
+        parent.setBaselineAlignedChildIndex(1);
+        assertEquals(1, parent.getBaselineAlignedChildIndex());
 
-        linearLayout.setBaselineAlignedChildIndex(2);
-        assertEquals(2, linearLayout.getBaselineAlignedChildIndex());
+        parent.setBaselineAlignedChildIndex(2);
+        assertEquals(2, parent.getBaselineAlignedChildIndex());
 
         try {
-            linearLayout.setBaselineAlignedChildIndex(-1);
+            parent.setBaselineAlignedChildIndex(-1);
             fail("LinearLayout should throw IllegalArgumentException here.");
         } catch (IllegalArgumentException e) {
         }
         try {
-            linearLayout.setBaselineAlignedChildIndex(3);
+            parent.setBaselineAlignedChildIndex(3);
             fail("LinearLayout should throw IllegalArgumentException here.");
         } catch (IllegalArgumentException e) {
         }
 
-        linearLayout = (LinearLayout) mActivity.findViewById(R.id.baseline_aligned_child_index);
-        assertEquals(1, linearLayout.getBaselineAlignedChildIndex());
+        parent = (LinearLayout) mActivity.findViewById(R.id.linear_baseline_aligned_child_index);
+        assertEquals(1, parent.getBaselineAlignedChildIndex());
     }
 
     /**
      * weightsum is a horizontal LinearLayout. There are three children in it.
      */
+    @Test
     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);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_weightsum);
+        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);
         assertNotNull(weight05);
         assertNotNull(weight03);
 
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_1),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1),
                 weight02.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_2),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2),
                 weight05.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_3),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3),
                 weight03.getText().toString());
 
         assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation());
-        assertEquals(1.0f, parent.getWeightSum());
+        assertEquals(1.0f, parent.getWeightSum(), 0.0f);
 
         int parentWidth = parent.getWidth();
         assertEquals(Math.ceil(parentWidth * 0.2), weight02.getWidth(), 1.0);
@@ -177,109 +210,113 @@
         assertEquals(Math.ceil(parentWidth * 0.3), weight03.getWidth(), 1.0);
     }
 
+    @UiThreadTest
+    @Test
     public void testWeightDistribution() {
-        LinearLayout layout = new LinearLayout(mActivity);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_empty);
+
         for (int i = 0; i < 3; i++) {
-            layout.addView(new View(mActivity), new LayoutParams(0, 0, 1));
+            parent.addView(new View(mActivity), new LayoutParams(0, 0, 1));
         }
 
         int size = 100;
         int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
 
         for (int i = 0; i < 3; i++) {
-            View child = layout.getChildAt(i);
+            View child = parent.getChildAt(i);
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.height = 0;
             lp.width = LayoutParams.MATCH_PARENT;
             child.setLayoutParams(lp);
         }
-        layout.setOrientation(LinearLayout.VERTICAL);
-        layout.measure(spec, spec);
-        layout.layout(0, 0, size, size);
-        assertEquals(100, layout.getWidth());
-        assertEquals(100, layout.getChildAt(0).getWidth());
-        assertEquals(100, layout.getChildAt(1).getWidth());
-        assertEquals(100, layout.getChildAt(2).getWidth());
-        assertEquals(100, layout.getHeight());
-        assertEquals(33, layout.getChildAt(0).getHeight());
-        assertEquals(33, layout.getChildAt(1).getHeight());
-        assertEquals(34, layout.getChildAt(2).getHeight());
+        parent.setOrientation(LinearLayout.VERTICAL);
+        parent.measure(spec, spec);
+        parent.layout(0, 0, size, size);
+        assertEquals(100, parent.getWidth());
+        assertEquals(100, parent.getChildAt(0).getWidth());
+        assertEquals(100, parent.getChildAt(1).getWidth());
+        assertEquals(100, parent.getChildAt(2).getWidth());
+        assertEquals(100, parent.getHeight());
+        assertEquals(33, parent.getChildAt(0).getHeight());
+        assertEquals(33, parent.getChildAt(1).getHeight());
+        assertEquals(34, parent.getChildAt(2).getHeight());
 
         for (int i = 0; i < 3; i++) {
-            View child = layout.getChildAt(i);
+            View child = parent.getChildAt(i);
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.height = LayoutParams.MATCH_PARENT;
             lp.width = 0;
             child.setLayoutParams(lp);
         }
-        layout.setOrientation(LinearLayout.HORIZONTAL);
-        layout.measure(spec, spec);
-        layout.layout(0, 0, size, size);
-        assertEquals(100, layout.getWidth());
-        assertEquals(33, layout.getChildAt(0).getWidth());
-        assertEquals(33, layout.getChildAt(1).getWidth());
-        assertEquals(34, layout.getChildAt(2).getWidth());
-        assertEquals(100, layout.getHeight());
-        assertEquals(100, layout.getChildAt(0).getHeight());
-        assertEquals(100, layout.getChildAt(1).getHeight());
-        assertEquals(100, layout.getChildAt(2).getHeight());
+        parent.setOrientation(LinearLayout.HORIZONTAL);
+        parent.measure(spec, spec);
+        parent.layout(0, 0, size, size);
+        assertEquals(100, parent.getWidth());
+        assertEquals(33, parent.getChildAt(0).getWidth());
+        assertEquals(33, parent.getChildAt(1).getWidth());
+        assertEquals(34, parent.getChildAt(2).getWidth());
+        assertEquals(100, parent.getHeight());
+        assertEquals(100, parent.getChildAt(0).getHeight());
+        assertEquals(100, parent.getChildAt(1).getHeight());
+        assertEquals(100, parent.getChildAt(2).getHeight());
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateLayoutParams() {
         ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(320, 240);
-        MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext);
-        LayoutParams layoutParams1 = mockLinearLayout.generateLayoutParams(lp);
+        MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
+        LayoutParams layoutParams1 = parent.generateLayoutParams(lp);
         assertEquals(320, layoutParams1.width);
         assertEquals(240, layoutParams1.height);
-
-        // generateLayoutParams() always throw  a RuntimeException.
-//        XmlPullParser parser = mContext.getResources().getXml(R.layout.linearlayout_layout);
-//        AttributeSet attrs = Xml.asAttributeSet(parser);
-//        LinearLayout linearLayout = new LinearLayout(mContext, attrs);
-//        LayoutParams layoutParams2 = linearLayout.generateLayoutParams(attrs);
-//        assertEquals(LayoutParams.MATCH_PARENT, layoutParams2.width);
-//        assertEquals(LayoutParams.WRAP_CONTENT, layoutParams2.height);
     }
 
+    @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
-        MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext);
+        MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
 
         ViewGroup.LayoutParams params = new AbsoluteLayout.LayoutParams(240, 320, 0, 0);
-        assertFalse(mockLinearLayout.checkLayoutParams(params));
+        assertFalse(parent.checkLayoutParams(params));
 
         params = new LinearLayout.LayoutParams(240, 320);
-        assertTrue(mockLinearLayout.checkLayoutParams(params));
+        assertTrue(parent.checkLayoutParams(params));
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        MockLinearLayout mockLinearLayout = new MockLinearLayout(mContext);
+        MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
 
-        mockLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
-        ViewGroup.LayoutParams param = mockLinearLayout.generateDefaultLayoutParams();
+        parent.setOrientation(LinearLayout.HORIZONTAL);
+        ViewGroup.LayoutParams param = parent.generateDefaultLayoutParams();
         assertNotNull(param);
         assertTrue(param instanceof LinearLayout.LayoutParams);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.width);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height);
 
-        mockLinearLayout.setOrientation(LinearLayout.VERTICAL);
-        param = mockLinearLayout.generateDefaultLayoutParams();
+        parent.setOrientation(LinearLayout.VERTICAL);
+        param = parent.generateDefaultLayoutParams();
         assertNotNull(param);
         assertTrue(param instanceof LinearLayout.LayoutParams);
         assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, param.width);
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, param.height);
 
-        mockLinearLayout.setOrientation(-1);
-        assertNull(mockLinearLayout.generateDefaultLayoutParams());
+        parent.setOrientation(-1);
+        assertNull(parent.generateDefaultLayoutParams());
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateLayoutParamsFromMarginParams() {
-        MockLinearLayout layout = new MockLinearLayout(mContext);
+        MockLinearLayout parent = (MockLinearLayout) mActivity.findViewById(R.id.linear_custom);
+
         ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5);
         lp.leftMargin = 1;
         lp.topMargin = 2;
         lp.rightMargin = 3;
         lp.bottomMargin = 4;
-        LinearLayout.LayoutParams generated = layout.generateLayoutParams(lp);
+        LinearLayout.LayoutParams generated = parent.generateLayoutParams(lp);
         assertNotNull(generated);
         assertEquals(3, generated.width);
         assertEquals(5, generated.height);
@@ -301,8 +338,9 @@
      * |     parent   |                 | --------------- |
      * ----------------------------------------------------
      */
+    @Test
     public void testLayoutHorizontal() {
-        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.horizontal);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_horizontal);
         TextView topView = (TextView) mActivity.findViewById(R.id.gravity_top);
         TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_vertical);
         TextView bottomView = (TextView) mActivity.findViewById(R.id.gravity_bottom);
@@ -312,11 +350,11 @@
         assertNotNull(centerView);
         assertNotNull(bottomView);
 
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_1),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_1),
                 topView.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_2),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_2),
                 centerView.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.horizontal_text_3),
+        assertEquals(mActivity.getResources().getString(R.string.horizontal_text_3),
                 bottomView.getText().toString());
 
         assertEquals(LinearLayout.HORIZONTAL, parent.getOrientation());
@@ -358,8 +396,9 @@
      * |                  -------------- |
      * -----------------------------------
      */
+    @Test
     public void testLayoutVertical() {
-        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.vertical);
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_vertical);
         TextView leftView = (TextView) mActivity.findViewById(R.id.gravity_left);
         TextView centerView = (TextView) mActivity.findViewById(R.id.gravity_center_horizontal);
         TextView rightView = (TextView) mActivity.findViewById(R.id.gravity_right);
@@ -369,11 +408,11 @@
         assertNotNull(centerView);
         assertNotNull(rightView);
 
-        assertEquals(mContext.getResources().getString(R.string.vertical_text_1),
+        assertEquals(mActivity.getResources().getString(R.string.vertical_text_1),
                 leftView.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.vertical_text_2),
+        assertEquals(mActivity.getResources().getString(R.string.vertical_text_2),
                 centerView.getText().toString());
-        assertEquals(mContext.getResources().getString(R.string.vertical_text_3),
+        assertEquals(mActivity.getResources().getString(R.string.vertical_text_3),
                 rightView.getText().toString());
 
         assertEquals(LinearLayout.VERTICAL, parent.getOrientation());
@@ -399,23 +438,201 @@
         assertEquals(parent.getWidth(), rightView.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) {
-        viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-            @Override
-            public boolean onPreDraw() {
-                assertEquals(left, view.getLeft());
-                assertEquals(top, view.getTop());
-                assertEquals(width, view.getWidth());
-                assertEquals(height, view.getHeight());
-                countDownLatch.countDown();
-                viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
-                return true;
-            }
-        });
+    @Test
+    public void testVerticalCenterGravityOnHorizontalLayout() throws Throwable {
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_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);
+
+        mActivityRule.runOnUiThread(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        mInstrumentation.waitForIdleSync();
+
+        int originalLeftViewRight = leftView.getRight();
+        int originalCenterViewLeft = centerView.getLeft();
+        int originalCenterViewRight = centerView.getRight();
+        int originalRightViewLeft = rightView.getLeft();
+
+        mActivityRule.runOnUiThread(() -> parent.setVerticalGravity(Gravity.CENTER_VERTICAL));
+        mInstrumentation.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());
     }
 
+    @Test
+    public void testBottomGravityOnHorizontalLayout() throws Throwable {
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_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);
+
+        mActivityRule.runOnUiThread(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        mInstrumentation.waitForIdleSync();
+
+        int originalLeftViewRight = leftView.getRight();
+        int originalCenterViewLeft = centerView.getLeft();
+        int originalCenterViewRight = centerView.getRight();
+        int originalRightViewLeft = rightView.getLeft();
+
+        mActivityRule.runOnUiThread(() -> parent.setVerticalGravity(Gravity.BOTTOM));
+        mInstrumentation.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());
+    }
+
+    @Test
+    public void testHorizontalCenterGravityOnVerticalLayout() throws Throwable {
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_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);
+
+        mActivityRule.runOnUiThread(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        mInstrumentation.waitForIdleSync();
+
+        final int parentWidth = parent.getHeight();
+
+        int originalTopViewBottom = topView.getBottom();
+        int originalCenterViewTop = centerView.getTop();
+        int originalCenterViewBottom = centerView.getBottom();
+        int originalBottomViewTop = bottomView.getTop();
+
+        mActivityRule.runOnUiThread(
+                () -> parent.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
+        mInstrumentation.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());
+    }
+
+    @Test
+    public void testRightGravityOnVerticalLayout() throws Throwable {
+        LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.linear_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);
+
+        mActivityRule.runOnUiThread(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        mInstrumentation.waitForIdleSync();
+
+        final int parentWidth = parent.getHeight();
+
+        int originalTopViewBottom = topView.getBottom();
+        int originalCenterViewTop = centerView.getTop();
+        int originalCenterViewBottom = centerView.getBottom();
+        int originalBottomViewTop = bottomView.getTop();
+
+        mActivityRule.runOnUiThread(() -> parent.setHorizontalGravity(Gravity.RIGHT));
+        mInstrumentation.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 verifyBounds(final ViewGroup viewGroup, final View view,
+            final CountDownLatch countDownLatch, final int left, final int top,
+            final int width, final int height) {
+        viewGroup.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        assertEquals(left, view.getLeft());
+                        assertEquals(top, view.getTop());
+                        assertEquals(width, view.getWidth());
+                        assertEquals(height, view.getHeight());
+                        countDownLatch.countDown();
+                        viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+                        return true;
+                    }
+                });
+    }
+
+    @Test
     public void testVisibilityAffectsLayout() throws Throwable {
         // Toggling view visibility between GONE/VISIBLE can affect the position of
         // other children in that container. This test verifies that these changes
@@ -437,38 +654,559 @@
         final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root);
 
         final CountDownLatch countDownLatch1 = new CountDownLatch(1);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                viewGroup.removeAllViews();
-                viewGroup.addView(parent);
-                parent.addView(child1);
-                parent.addView(child2);
-                checkBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
-                checkBounds(viewGroup, child2, countDownLatch1,
-                        childWidth, 0, childWidth, childHeight);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            viewGroup.removeAllViews();
+            viewGroup.addView(parent);
+            parent.addView(child1);
+            parent.addView(child2);
+            verifyBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
+            verifyBounds(viewGroup, child2, countDownLatch1,
+                    childWidth, 0, childWidth, childHeight);
         });
-        countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+        try {
+            assertTrue(countDownLatch1.await(500, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
 
         final CountDownLatch countDownLatch2 = new CountDownLatch(1);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                child1.setVisibility(View.GONE);
-                checkBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            child1.setVisibility(View.GONE);
+            verifyBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
         });
-        countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+        try {
+            assertTrue(countDownLatch2.await(500, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
 
         final CountDownLatch countDownLatch3 = new CountDownLatch(2);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                child1.setVisibility(View.VISIBLE);
-                checkBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
-                checkBounds(viewGroup, child2, countDownLatch3,
-                        childWidth, 0, childWidth, childHeight);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            child1.setVisibility(View.VISIBLE);
+            verifyBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
+            verifyBounds(viewGroup, child2, countDownLatch3,
+                    childWidth, 0, childWidth, childHeight);
         });
-        countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+        try {
+            assertTrue(countDownLatch3.await(500, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+    }
+
+    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.
+     */
+    @Test
+    public void testDividersInVerticalLayout() throws Throwable {
+        final LinearLayout parent =
+                (LinearLayout) mActivity.findViewById(R.id.linear_vertical_with_divider);
+
+        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(mActivityRule, 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(mActivityRule, parent,
+                () -> parent.setDividerDrawable(null));
+        verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                0, Color.TRANSPARENT, 0);
+
+        // Change the divider back to red
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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.
+     */
+    @Test
+    public void testDividersInHorizontalLayout() throws Throwable {
+        final LinearLayout parent =
+                (LinearLayout) mActivity.findViewById(R.id.linear_horizontal_with_divider);
+
+        mActivityRule.runOnUiThread(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+        mInstrumentation.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(mActivityRule, 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(mActivityRule, parent,
+                () -> parent.setDividerDrawable(null));
+        verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+                0, Color.TRANSPARENT, 0);
+
+        // Change the divider back to red
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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 {
@@ -489,11 +1227,15 @@
      * extends from it and override protected methods so that we can access them in
      * our test codes.
      */
-    private class MockLinearLayout extends LinearLayout {
+    public static class MockLinearLayout extends LinearLayout {
         public MockLinearLayout(Context c) {
             super(c);
         }
 
+        public MockLinearLayout(Context context, @Nullable AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         @Override
         protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
             return super.checkLayoutParams(p);
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..b320008 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayout_LayoutParamsTest.java
@@ -16,37 +16,79 @@
 
 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.XmlPullParserException;
-
+import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+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.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
-public class LinearLayout_LayoutParamsTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LinearLayout_LayoutParamsTest {
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
-        XmlResourceParser p = mContext.getResources().getLayout(R.layout.linearlayout_layout);
+        final Context context = InstrumentationRegistry.getTargetContext();
+        XmlResourceParser p = context.getResources().getLayout(R.layout.linearlayout_layout);
 
         XmlUtils.beginDocument(p, "LinearLayout");
-        new LinearLayout.LayoutParams(getContext(), p);
+        LinearLayout.LayoutParams linearLayoutParams =
+                new LinearLayout.LayoutParams(context, p);
+        assertEquals(LayoutParams.MATCH_PARENT, linearLayoutParams.width);
+        assertEquals(LayoutParams.WRAP_CONTENT, linearLayoutParams.height);
+        assertEquals(0.0f, linearLayoutParams.weight, 0.0f);
+        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, 0.0f);
+        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, 0.0f);
+        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, 0.0f);
+        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, 0.0f);
+        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, 0.0f);
+        assertEquals(Gravity.RIGHT, linearLayoutParams.gravity);
     }
 
+    @Test
     public void testDebug() {
         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(320, 240);
         assertNotNull(layoutParams.debug("test: "));
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index 73e2aeb..b5ad7bd 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -16,23 +16,37 @@
 
 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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doCallRealMethod;
+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 android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.KeyEventUtil;
 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;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Display;
 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,17 +57,24 @@
 import android.widget.ListView;
 import android.widget.PopupWindow;
 import android.widget.TextView;
-import android.widget.cts.util.ViewTestUtils;
 
-import static org.mockito.Mockito.*;
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.WidgetTestUtils;
 
-@SmallTest
-public class ListPopupWindowTest extends
-        ActivityInstrumentationTestCase2<ListPopupWindowCtsActivity> {
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ListPopupWindowTest {
     private Instrumentation mInstrumentation;
     private Activity mActivity;
-    private KeyEventUtil mKeyEventUtil;
     private Builder mPopupWindowBuilder;
+    private View promptView;
 
     /** The list popup window. */
     private ListPopupWindow mPopupWindow;
@@ -73,31 +94,26 @@
         }
     }
 
-    /**
-     * Instantiates a new popup window test.
-     */
-    public ListPopupWindowTest() {
-        super(ListPopupWindowCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ListPopupWindowCtsActivity> mActivityRule
+            = new ActivityTestRule<>(ListPopupWindowCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mItemClickListener = new PopupItemClickListener();
-        mKeyEventUtil = new KeyEventUtil(mInstrumentation);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() throws Throwable {
         if ((mPopupWindowBuilder != null) && (mPopupWindow != null)) {
-            mPopupWindowBuilder.dismiss();
+            mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+            mInstrumentation.waitForIdleSync();
         }
-
-        super.tearDown();
     }
 
+    @Test
     public void testConstructor() {
         new ListPopupWindow(mActivity);
 
@@ -105,17 +121,29 @@
 
         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);
     }
 
+    @Test
     public void testNoDefaultVisibility() {
         mPopupWindow = new ListPopupWindow(mActivity);
         assertFalse(mPopupWindow.isShowing());
     }
 
-    public void testAccessBackground() {
+    @Test
+    public void testAccessBackground() throws Throwable {
         mPopupWindowBuilder = new Builder();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         Drawable drawable = new ColorDrawable();
         mPopupWindow.setBackgroundDrawable(drawable);
@@ -125,9 +153,11 @@
         assertNull(mPopupWindow.getBackground());
     }
 
-    public void testAccessAnimationStyle() {
+    @Test
+    public void testAccessAnimationStyle() throws Throwable {
         mPopupWindowBuilder = new Builder();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
         assertEquals(0, mPopupWindow.getAnimationStyle());
 
         mPopupWindow.setAnimationStyle(android.R.style.Animation_Toast);
@@ -138,9 +168,11 @@
         assertEquals(-100, mPopupWindow.getAnimationStyle());
     }
 
-    public void testAccessHeight() {
+    @Test
+    public void testAccessHeight() throws Throwable {
         mPopupWindowBuilder = new Builder();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getHeight());
 
@@ -174,9 +206,11 @@
         return wm.getDefaultDisplay();
     }
 
-    public void testAccessWidth() {
+    @Test
+    public void testAccessWidth() throws Throwable {
         mPopupWindowBuilder = new Builder().ignoreContentWidth();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getWidth());
 
@@ -234,9 +268,11 @@
         assertEquals(expectedListViewOnScreenY, listViewOnScreenXY[1]);
     }
 
-    public void testAnchoring() {
+    @Test
+    public void testAnchoring() throws Throwable {
         mPopupWindowBuilder = new Builder();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(0, mPopupWindow.getHorizontalOffset());
         assertEquals(0, mPopupWindow.getVerticalOffset());
@@ -244,9 +280,11 @@
         verifyAnchoring(0, 0, Gravity.NO_GRAVITY);
     }
 
-    public void testAnchoringWithHorizontalOffset() {
+    @Test
+    public void testAnchoringWithHorizontalOffset() throws Throwable {
         mPopupWindowBuilder = new Builder().withHorizontalOffset(50);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(50, mPopupWindow.getHorizontalOffset());
         assertEquals(0, mPopupWindow.getVerticalOffset());
@@ -254,9 +292,11 @@
         verifyAnchoring(50, 0, Gravity.NO_GRAVITY);
     }
 
-    public void testAnchoringWithVerticalOffset() {
+    @Test
+    public void testAnchoringWithVerticalOffset() throws Throwable {
         mPopupWindowBuilder = new Builder().withVerticalOffset(60);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(0, mPopupWindow.getHorizontalOffset());
         assertEquals(60, mPopupWindow.getVerticalOffset());
@@ -264,9 +304,11 @@
         verifyAnchoring(0, 60, Gravity.NO_GRAVITY);
     }
 
-    public void testAnchoringWithRightGravity() {
+    @Test
+    public void testAnchoringWithRightGravity() throws Throwable {
         mPopupWindowBuilder = new Builder().withDropDownGravity(Gravity.RIGHT);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(0, mPopupWindow.getHorizontalOffset());
         assertEquals(0, mPopupWindow.getVerticalOffset());
@@ -274,9 +316,11 @@
         verifyAnchoring(0, 0, Gravity.RIGHT);
     }
 
-    public void testAnchoringWithEndGravity() {
+    @Test
+    public void testAnchoringWithEndGravity() throws Throwable {
         mPopupWindowBuilder = new Builder().withDropDownGravity(Gravity.END);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(0, mPopupWindow.getHorizontalOffset());
         assertEquals(0, mPopupWindow.getVerticalOffset());
@@ -284,10 +328,12 @@
         verifyAnchoring(0, 0, Gravity.END);
     }
 
-    public void testSetWindowLayoutType() {
+    @Test
+    public void testSetWindowLayoutType() throws Throwable {
         mPopupWindowBuilder = new Builder().withWindowLayoutType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isShowing());
 
         WindowManager.LayoutParams p = (WindowManager.LayoutParams)
@@ -295,39 +341,52 @@
         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, p.type);
     }
 
-    public void testDismiss() {
+    @Test
+    public void testDismiss() throws Throwable {
         mPopupWindowBuilder = new Builder();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isShowing());
 
-        mPopupWindowBuilder.dismiss();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+        mInstrumentation.waitForIdleSync();
         assertFalse(mPopupWindow.isShowing());
 
-        mPopupWindowBuilder.dismiss();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+        mInstrumentation.waitForIdleSync();
         assertFalse(mPopupWindow.isShowing());
     }
 
-    public void testSetOnDismissListener() {
+    @Test
+    public void testSetOnDismissListener() throws Throwable {
         mPopupWindowBuilder = new Builder().withDismissListener();
-        mPopupWindowBuilder.show();
-        mPopupWindowBuilder.dismiss();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+        mInstrumentation.waitForIdleSync();
         verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
 
-        mPopupWindowBuilder.showAgain();
-        mPopupWindowBuilder.dismiss();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::showAgain);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+        mInstrumentation.waitForIdleSync();
         verify(mPopupWindowBuilder.mOnDismissListener, times(2)).onDismiss();
 
         mPopupWindow.setOnDismissListener(null);
-        mPopupWindowBuilder.showAgain();
-        mPopupWindowBuilder.dismiss();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::showAgain);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::dismiss);
+        mInstrumentation.waitForIdleSync();
         // Since we've reset the listener to null, we are not expecting any more interactions
         // on the previously registered listener.
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnDismissListener);
     }
 
-    public void testAccessInputMethodMode() {
+    @Test
+    public void testAccessInputMethodMode() throws Throwable {
         mPopupWindowBuilder = new Builder().withDismissListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertEquals(PopupWindow.INPUT_METHOD_NEEDED, mPopupWindow.getInputMethodMode());
         assertFalse(mPopupWindow.isInputMethodNotNeeded());
@@ -349,9 +408,11 @@
         assertFalse(mPopupWindow.isInputMethodNotNeeded());
     }
 
-    public void testAccessSoftInputMethodMode() {
+    @Test
+    public void testAccessSoftInputMethodMode() throws Throwable {
         mPopupWindowBuilder = new Builder().withDismissListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         mPopupWindow = new ListPopupWindow(mActivity);
         assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED,
@@ -374,55 +435,27 @@
 
         // Configure a list popup window with requested modality
         mPopupWindowBuilder = new Builder().setModal(setupAsModal).withDismissListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         assertTrue("Popup window showing", mPopupWindow.isShowing());
         // 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.emulateTapOnView(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
@@ -434,19 +467,22 @@
         verify(mockContainerClickListener, times(setupAsModal ? 0 : 1)).onClick(mainContainer);
     }
 
+    @Test
     public void testDismissalOutsideNonModal() throws Throwable {
         verifyDismissalViaTouch(false);
     }
 
+    @Test
     public void testDismissalOutsideModal() throws Throwable {
         verifyDismissalViaTouch(true);
     }
 
+    @Test
     public void testItemClicks() throws Throwable {
         mPopupWindowBuilder = new Builder().withItemClickListener().withDismissListener();
-        mPopupWindowBuilder.show();
-
-        runTestOnUiThread(() -> mPopupWindow.performItemClick(2));
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mPopupWindow.performItemClick(2));
         mInstrumentation.waitForIdleSync();
 
         verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -455,8 +491,10 @@
         assertFalse(mPopupWindow.isShowing());
         verify(mPopupWindowBuilder.mOnDismissListener, times(1)).onDismiss();
 
-        mPopupWindowBuilder.showAgain();
-        runTestOnUiThread(() -> mPopupWindow.getListView().performItemClick(null, 1, 1));
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::showAgain);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> mPopupWindow.getListView().performItemClick(null, 1, 1));
         mInstrumentation.waitForIdleSync();
 
         verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -469,12 +507,15 @@
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemClickListener);
     }
 
+    @Test
     public void testPromptViewAbove() throws Throwable {
-        final View promptView = LayoutInflater.from(mActivity).inflate(
-                R.layout.popupwindow_prompt, null);
-        mPopupWindowBuilder = new Builder().withPrompt(
-                promptView, ListPopupWindow.POSITION_PROMPT_ABOVE);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(() -> {
+            promptView = LayoutInflater.from(mActivity).inflate(R.layout.popupwindow_prompt, null);
+            mPopupWindowBuilder = new Builder().withPrompt(
+                    promptView, ListPopupWindow.POSITION_PROMPT_ABOVE);
+            mPopupWindowBuilder.show();
+        });
+        mInstrumentation.waitForIdleSync();
 
         // Verify that our prompt is displayed on the screen and is above the first list item
         assertTrue(promptView.isAttachedToWindow());
@@ -485,7 +526,7 @@
         promptView.getLocationOnScreen(promptViewOnScreenXY);
 
         final ListView listView = mPopupWindow.getListView();
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView, null);
 
         final View firstListChild = listView.getChildAt(0);
         final int[] firstChildOnScreenXY = new int[2];
@@ -494,12 +535,15 @@
         assertTrue(promptViewOnScreenXY[1] + promptView.getHeight() <= firstChildOnScreenXY[1]);
     }
 
+    @Test
     public void testPromptViewBelow() throws Throwable {
-        final View promptView = LayoutInflater.from(mActivity).inflate(
-                R.layout.popupwindow_prompt, null);
-        mPopupWindowBuilder = new Builder().withPrompt(
-                promptView, ListPopupWindow.POSITION_PROMPT_BELOW);
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(() -> {
+            promptView = LayoutInflater.from(mActivity).inflate(R.layout.popupwindow_prompt, null);
+            mPopupWindowBuilder = new Builder().withPrompt(
+                    promptView, ListPopupWindow.POSITION_PROMPT_BELOW);
+            mPopupWindowBuilder.show();
+        });
+        mInstrumentation.waitForIdleSync();
 
         // Verify that our prompt is displayed on the screen and is below the last list item
         assertTrue(promptView.isAttachedToWindow());
@@ -507,7 +551,7 @@
         assertEquals(ListPopupWindow.POSITION_PROMPT_BELOW, mPopupWindow.getPromptPosition());
 
         final ListView listView = mPopupWindow.getListView();
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView, null);
 
         final int[] promptViewOnScreenXY = new int[2];
         promptView.getLocationOnScreen(promptViewOnScreenXY);
@@ -523,14 +567,16 @@
     }
 
     @Presubmit
+    @Test
     public void testAccessSelection() throws Throwable {
         mPopupWindowBuilder = new Builder().withItemSelectedListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         final ListView listView = mPopupWindow.getListView();
 
         // Select an item
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView,
                 () -> mPopupWindow.setSelection(1));
 
         // And verify the current selection state + selection listener invocation
@@ -545,7 +591,7 @@
                 ((TextView) selectedView.findViewById(android.R.id.text1)).getText());
 
         // Select another item
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView,
                 () -> mPopupWindow.setSelection(3));
 
         // And verify the new selection state + selection listener invocation
@@ -560,8 +606,8 @@
                 ((TextView) selectedView.findViewById(android.R.id.text1)).getText());
 
         // Clear selection
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
-                () -> mPopupWindow.clearListSelection());
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView,
+                mPopupWindow::clearListSelection);
 
         // And verify empty selection state + no more selection listener invocation
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onNothingSelected(
@@ -573,9 +619,11 @@
         verifyNoMoreInteractions(mPopupWindowBuilder.mOnItemSelectedListener);
     }
 
+    @Test
     public void testNoDefaultDismissalWithBackButton() throws Throwable {
         mPopupWindowBuilder = new Builder().withDismissListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         // Send BACK key event. As we don't have any custom code that dismisses ListPopupWindow,
         // and ListPopupWindow doesn't track that system-level key event on its own, ListPopupWindow
@@ -585,17 +633,21 @@
         assertTrue(mPopupWindow.isShowing());
     }
 
+    @Test
     public void testCustomDismissalWithBackButton() throws Throwable {
-        mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
-                .withDismissListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(() -> {
+            mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
+                    .withDismissListener();
+            mPopupWindowBuilder.show();
+        });
+        mInstrumentation.waitForIdleSync();
 
         // "Point" our custom extension of EditText to our ListPopupWindow
         final MockViewForListPopupWindow anchor =
                 (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
         anchor.wireTo(mPopupWindow);
         // Request focus on our EditText
-        runTestOnUiThread(() -> anchor.requestFocus());
+        mActivityRule.runOnUiThread(anchor::requestFocus);
         mInstrumentation.waitForIdleSync();
         assertTrue(anchor.isFocused());
 
@@ -607,10 +659,12 @@
         assertFalse(mPopupWindow.isShowing());
     }
 
+    @Test
     public void testListSelectionWithDPad() throws Throwable {
         mPopupWindowBuilder = new Builder().withAnchor(R.id.anchor_upper_left)
                 .withDismissListener().withItemSelectedListener();
-        mPopupWindowBuilder.show();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::show);
+        mInstrumentation.waitForIdleSync();
 
         final View root = mPopupWindow.getListView().getRootView();
 
@@ -619,13 +673,13 @@
                 (MockViewForListPopupWindow) mPopupWindow.getAnchorView();
         anchor.wireTo(mPopupWindow);
         // Request focus on our EditText
-        runTestOnUiThread(() -> anchor.requestFocus());
+        mActivityRule.runOnUiThread(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(mActivityRule, listView,
                 () -> mPopupWindow.setSelection(1));
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
                 any(AdapterView.class), any(View.class), eq(1), eq(1L));
@@ -633,10 +687,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(mActivityRule, root, null);
 
         // At this point we expect that item #2 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
@@ -645,10 +699,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(mActivityRule, root, null);
 
         // At this point we expect that item #1 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(2)).onItemSelected(
@@ -657,10 +711,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(mActivityRule, root, null);
 
         // At this point we expect that item #0 was selected
         verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
@@ -669,7 +723,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();
@@ -679,40 +733,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();
-    }
-
+    @Test
     public void testCreateOnDragListener() throws Throwable {
         // 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
@@ -725,7 +746,8 @@
                 .withItemClickListener().withDismissListener();
 
         // Configure ListPopupWindow without showing it
-        mPopupWindowBuilder.configure();
+        mActivityRule.runOnUiThread(mPopupWindowBuilder::configure);
+        mInstrumentation.waitForIdleSync();
 
         // Get the anchor view and configure it with ListPopupWindow's drag-to-open listener
         final View anchor = mActivity.findViewById(mPopupWindowBuilder.mAnchorId);
@@ -749,7 +771,8 @@
         int swipeAmount = 2 * popupRowHeight;
 
         // Emulate drag-down gesture with a sequence of motion events
-        emulateDragDownGesture(emulatedX, emulatedStartY, swipeAmount);
+        CtsTouchUtils.emulateDragGesture(mInstrumentation, 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(
@@ -963,7 +986,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) {
@@ -1001,35 +1025,22 @@
 
         private void show() {
             configure();
-
-            mInstrumentation.runOnMainSync(
-                    () -> {
-                        mPopupWindow.show();
-                        assertTrue(mPopupWindow.isShowing());
-                    });
-            mInstrumentation.waitForIdleSync();
+            mPopupWindow.show();
+            assertTrue(mPopupWindow.isShowing());
         }
 
         private void showAgain() {
-            mInstrumentation.runOnMainSync(
-                    () -> {
-                        if (mPopupWindow == null || mPopupWindow.isShowing()) {
-                            return;
-                        }
-                        mPopupWindow.show();
-                        assertTrue(mPopupWindow.isShowing());
-                    });
-            mInstrumentation.waitForIdleSync();
+            if (mPopupWindow == null || mPopupWindow.isShowing()) {
+                return;
+            }
+            mPopupWindow.show();
+            assertTrue(mPopupWindow.isShowing());
         }
 
         private void dismiss() {
-            mInstrumentation.runOnMainSync(
-                    () -> {
-                        if (mPopupWindow == null || !mPopupWindow.isShowing())
-                            return;
-                        mPopupWindow.dismiss();
-                    });
-            mInstrumentation.waitForIdleSync();
+            if (mPopupWindow == null || !mPopupWindow.isShowing())
+                return;
+            mPopupWindow.dismiss();
         }
     }
 }
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/tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java
new file mode 100644
index 0000000..f34a452
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ListViewFixedCtsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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.os.Bundle;
+
+public class ListViewFixedCtsActivity extends Activity {
+    @Override
+    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..4b1e6bb 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -16,51 +16,17 @@
 
 package android.widget.cts;
 
-import junit.framework.Assert;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.app.ActionBar.LayoutParams;
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.cts.util.PollingCheck;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.Xml;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup;
-import android.view.animation.LayoutAnimationController;
-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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
+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.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.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -69,113 +35,176 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
-public class ListViewTest extends ActivityInstrumentationTestCase2<ListViewCtsActivity> {
+import android.app.ActionBar.LayoutParams;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.Xml;
+import android.view.KeyEvent;
+import android.view.View;
+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.ListView;
+import android.widget.TextView;
+import android.widget.cts.util.TestUtils;
+
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ListViewTest {
     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 Activity mActivity;
+    private ListView mListView;
+    private TextView mTextView;
+    private TextView mSecondTextView;
+
     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);
-    }
+    @Rule
+    public ActivityTestRule<ListViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ListViewCtsActivity.class);
 
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         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);
     }
 
+    @Test
     public void testConstructor() {
         new ListView(mActivity);
         new ListView(mActivity, mAttributeSet);
         new ListView(mActivity, mAttributeSet, 0);
-
-        try {
-            new ListView(null);
-            fail("There should be a NullPointerException thrown out. ");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new ListView(null, null);
-            fail("There should be a NullPointerException thrown out. ");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new ListView(null, null, -1);
-            fail("There should be a NullPointerException thrown out. ");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
     }
 
-    public void testGetMaxScrollAmount() {
-        setAdapter(mAdapter_empty);
-        int scrollAmount = mListView.getMaxScrollAmount();
-        assertEquals(0, scrollAmount);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new ListView(null);
+    }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        new ListView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        new ListView(null, null, -1);
+    }
+
+    @Test
+    public void testGetMaxScrollAmount() throws Throwable {
         setAdapter(mAdapter_names);
-        scrollAmount = mListView.getMaxScrollAmount();
+        int scrollAmount = mListView.getMaxScrollAmount();
         assertTrue(scrollAmount > 0);
+
+        mActivityRule.runOnUiThread(() -> {
+            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,
+    private void setAdapter(final ArrayAdapter<String> adapter) throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(adapter));
     }
 
-    public void testAccessDividerHeight() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testAccessDividerHeight() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mListView,
                 () -> mListView.setDividerHeight(20));
 
         assertEquals(20, mListView.getDividerHeight());
         assertEquals(20, r.bottom - r.top);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setDividerHeight(10));
 
         assertEquals(10, mListView.getDividerHeight());
         assertEquals(10, r.bottom - r.top);
     }
 
+    @Test
     public void testAccessItemsCanFocus() {
         mListView.setItemsCanFocus(true);
         assertTrue(mListView.getItemsCanFocus());
@@ -186,14 +215,15 @@
         // TODO: how to check?
     }
 
-    public void testAccessAdapter() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testAccessAdapter() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         assertSame(mAdapter_countries, mListView.getAdapter());
         assertEquals(mCountryList.length, mListView.getCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_names));
 
         assertSame(mAdapter_names, mListView.getAdapter());
@@ -201,6 +231,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessItemChecked() {
         // NONE mode
         mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -273,52 +304,74 @@
         assertFalse(mListView.isItemChecked(4));
     }
 
-    public void testAccessFooterView() {
-        final TextView footerView1 = new TextView(mActivity);
-        footerView1.setText("footerview1");
-        final TextView footerView2 = new TextView(mActivity);
-        footerView2.setText("footerview2");
+    @Test
+    public void testAccessFooterView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText("footerview1");
+            mSecondTextView = new TextView(mActivity);
+            mSecondTextView.setText("footerview2");
+        });
+        mInstrumentation.waitForIdleSync();
 
-        mInstrumentation.runOnMainSync(() -> mListView.setFooterDividersEnabled(true));
+        mActivityRule.runOnUiThread(() -> mListView.setFooterDividersEnabled(true));
+        assertTrue(mListView.areFooterDividersEnabled());
         assertEquals(0, mListView.getFooterViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addFooterView(footerView1, null, true));
+        mActivityRule.runOnUiThread(() -> mListView.addFooterView(mTextView, null, true));
+        assertTrue(mListView.areFooterDividersEnabled());
         assertEquals(1, mListView.getFooterViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addFooterView(footerView2));
-
-        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> {
+            mListView.setFooterDividersEnabled(false);
+            mListView.addFooterView(mSecondTextView);
+        });
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(2, mListView.getFooterViewsCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> mListView.removeFooterView(footerView1));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.removeFooterView(mTextView));
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(1, mListView.getFooterViewsCount());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> mListView.removeFooterView(footerView2));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.removeFooterView(mSecondTextView));
+        assertFalse(mListView.areFooterDividersEnabled());
         assertEquals(0, mListView.getFooterViewsCount());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessHeaderView() {
         final TextView headerView1 = (TextView) mActivity.findViewById(R.id.headerview1);
         final TextView headerView2 = (TextView) mActivity.findViewById(R.id.headerview2);
 
-        mInstrumentation.runOnMainSync(() -> mListView.setHeaderDividersEnabled(true));
+        mListView.setHeaderDividersEnabled(true);
+        assertTrue(mListView.areHeaderDividersEnabled());
         assertEquals(0, mListView.getHeaderViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addHeaderView(headerView2, null, true));
+        mListView.addHeaderView(headerView2, null, true);
+        assertTrue(mListView.areHeaderDividersEnabled());
         assertEquals(1, mListView.getHeaderViewsCount());
 
-        mInstrumentation.runOnMainSync(() -> mListView.addHeaderView(headerView1));
+        mListView.setHeaderDividersEnabled(false);
+        mListView.addHeaderView(headerView1);
+        assertFalse(mListView.areHeaderDividersEnabled());
         assertEquals(2, mListView.getHeaderViewsCount());
+
+        mListView.removeHeaderView(headerView2);
+        assertFalse(mListView.areHeaderDividersEnabled());
+        assertEquals(1, mListView.getHeaderViewsCount());
     }
 
+    @Test
     public void testHeaderFooterType() throws Throwable {
-        final TextView headerView = new TextView(getActivity());
-        final List<Pair<View, View>> mismatch = new ArrayList<Pair<View, View>>();
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        final List<Pair<View, View>> mismatch = new ArrayList<>();
         final ArrayAdapter adapter = new ArrayAdapter<String>(mActivity,
                 android.R.layout.simple_list_item_1, mNameList) {
             @Override
@@ -330,10 +383,10 @@
             @Override
             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));
+                    if (convertView != null && convertView != mTextView) {
+                        mismatch.add(new Pair<>(mTextView, convertView));
                     }
-                    return headerView;
+                    return mTextView;
                 } else {
                     return super.getView(position - 1, convertView, parent);
                 }
@@ -344,80 +397,77 @@
                 return super.getCount() + 1;
             }
         };
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(adapter));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> adapter.notifyDataSetChanged());
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                adapter::notifyDataSetChanged);
 
         assertEquals(0, mismatch.size());
     }
 
-    public void testAccessDivider() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testAccessDivider() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mListView,
                 () -> mListView.setDivider(d));
         assertSame(d, mListView.getDivider());
         assertEquals(d.getBounds().height(), mListView.getDividerHeight());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setDividerHeight(10));
         assertEquals(10, mListView.getDividerHeight());
         assertEquals(10, d.getBounds().height());
     }
 
-    public void testSetSelection() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testSetSelection() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setSelection(1));
         String item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[1], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setSelectionFromTop(5, 0));
         item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[5], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
-                () -> mListView.setSelectionAfterHeaderView());
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                mListView::setSelectionAfterHeaderView);
         item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[0], item);
     }
 
-    public void testOnKeyUpDown() {
-        // implementation details, do NOT test
-    }
-
-    public void testPerformItemClick() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testPerformItemClick() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
         mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setSelection(2));
 
-        final TextView child = (TextView) mAdapter_countries.getView(2, null, mListView);
-        assertNotNull(child);
-        assertEquals(mCountryList[2], child.getText().toString());
+        mActivityRule.runOnUiThread(() ->
+                mTextView = (TextView) mAdapter_countries.getView(2, null, mListView));
+        mInstrumentation.waitForIdleSync();
+        assertNotNull(mTextView);
+        assertEquals(mCountryList[2], mTextView.getText().toString());
         final long itemID = mAdapter_countries.getItemId(2);
         assertEquals(2, itemID);
 
-        mInstrumentation.runOnMainSync(() -> mListView.performItemClick(child, 2, itemID));
+        mActivityRule.runOnUiThread(() -> mListView.performItemClick(mTextView, 2, itemID));
         mInstrumentation.waitForIdleSync();
 
         OnItemClickListener onClickListener = mock(OnItemClickListener.class);
@@ -425,37 +475,55 @@
         verify(onClickListener, never()).onItemClick(any(AdapterView.class), any(View.class),
                 anyInt(), anyLong());
 
-        mInstrumentation.runOnMainSync(() -> mListView.performItemClick(child, 2, itemID));
+        mActivityRule.runOnUiThread(() -> mListView.performItemClick(mTextView, 2, itemID));
         mInstrumentation.waitForIdleSync();
 
-        verify(onClickListener, times(1)).onItemClick(mListView, child, 2, 2L);
+        verify(onClickListener, times(1)).onItemClick(mListView, mTextView, 2, 2L);
         verifyNoMoreInteractions(onClickListener);
     }
 
-    public void testSaveAndRestoreInstanceState() {
-        // implementation details, do NOT test
+    @UiThreadTest
+    @Test
+    public void testSaveAndRestoreInstanceState_positionIsRestored() {
+        mListView.setAdapter(mAdapter_countries);
+        assertEquals(0, mListView.getSelectedItemPosition());
+
+        int positionToTest = mAdapter_countries.getCount() - 1;
+        mListView.setSelection(positionToTest);
+        assertEquals(positionToTest, mListView.getSelectedItemPosition());
+        Parcelable savedState = mListView.onSaveInstanceState();
+
+        mListView.setSelection(positionToTest - 1);
+        assertEquals(positionToTest - 1, mListView.getSelectedItemPosition());
+
+        mListView.onRestoreInstanceState(savedState);
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+        mListView.measure(measureSpec,measureSpec);
+        mListView.layout(0, 0, 100, 100);
+        assertEquals(positionToTest, mListView.getSelectedItemPosition());
     }
 
-    public void testDispatchKeyEvent() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testDispatchKeyEvent() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> {
                     mListView.setAdapter(mAdapter_countries);
                     mListView.requestFocus();
                 });
         assertTrue(mListView.hasFocus());
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setSelection(1));
         String item = (String) mListView.getSelectedItem();
         assertEquals(mCountryList[1], item);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () ->  {
                     KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
                     mListView.dispatchKeyEvent(keyEvent);
                 });
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> {
                     KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN,
                             KeyEvent.KEYCODE_DPAD_DOWN);
@@ -467,25 +535,25 @@
         assertEquals(mCountryList[4], item);
     }
 
-    public void testRequestChildRectangleOnScreen() {
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mListView,
+    @Test
+    public void testRequestChildRectangleOnScreen() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
                 () -> mListView.setAdapter(mAdapter_countries));
 
-        TextView child = (TextView) mAdapter_countries.getView(0, null, mListView);
-        assertNotNull(child);
-        assertEquals(mCountryList[0], child.getText().toString());
+        mActivityRule.runOnUiThread(() ->
+                mTextView = (TextView) mAdapter_countries.getView(0, null, mListView));
+        mInstrumentation.waitForIdleSync();
+        assertNotNull(mTextView);
+        assertEquals(mCountryList[0], mTextView.getText().toString());
 
         Rect rect = new Rect(0, 0, 10, 10);
-        assertFalse(mListView.requestChildRectangleOnScreen(child, rect, false));
+        assertFalse(mListView.requestChildRectangleOnScreen(mTextView, rect, false));
 
         // TODO: how to check?
     }
 
-    public void testOnTouchEvent() {
-        // implementation details, do NOT test
-    }
-
     @UiThreadTest
+    @Test
     public void testCanAnimate() {
         MyListView listView = new MyListView(mActivity, mAttributeSet);
 
@@ -500,12 +568,9 @@
         assertTrue(listView.canAnimate());
     }
 
-    @UiThreadTest
-    public void testDispatchDraw() {
-        // implementation details, do NOT test
-    }
 
     @UiThreadTest
+    @Test
     public void testFindViewTraversal() {
         MyListView listView = new MyListView(mActivity, mAttributeSet);
         TextView headerView = (TextView) mActivity.findViewById(R.id.headerview1);
@@ -518,6 +583,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testFindViewWithTagTraversal() {
         MyListView listView = new MyListView(mActivity, mAttributeSet);
         TextView headerView = (TextView) mActivity.findViewById(R.id.headerview1);
@@ -530,22 +596,6 @@
         assertSame(headerView, listView.findViewWithTagTraversal("header"));
     }
 
-    public void testLayoutChildren() {
-        // TODO: how to test?
-    }
-
-    public void testOnFinishInflate() {
-        // implementation details, do NOT test
-    }
-
-    public void testOnFocusChanged() {
-        // implementation details, do NOT test
-    }
-
-    public void testOnMeasure() {
-        // implementation details, do NOT test
-    }
-
     /**
      * MyListView for test
      */
@@ -580,67 +630,67 @@
         }
     }
 
-    /**
-     * The following functions are merged from frameworktest.
-     */
     @MediumTest
-    public void testRequestLayoutCallsMeasure() throws Exception {
-        ListView listView = new ListView(mActivity);
+    @UiThreadTest
+    @Test
+    public void testRequestLayoutCallsMeasure() {
         List<String> items = new ArrayList<>();
         items.add("hello");
-        Adapter<String> adapter = new Adapter<String>(mActivity, 0, items);
-        listView.setAdapter(adapter);
+        MockAdapter<String> adapter = new MockAdapter<>(mActivity, 0, items);
+        mListView.setAdapter(adapter);
 
         int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
 
         adapter.notifyDataSetChanged();
-        listView.measure(measureSpec, measureSpec);
-        listView.layout(0, 0, 100, 100);
+        mListView.measure(measureSpec, measureSpec);
+        mListView.layout(0, 0, 100, 100);
 
-        MockView childView = (MockView) listView.getChildAt(0);
+        MockView childView = (MockView) mListView.getChildAt(0);
 
         childView.requestLayout();
         childView.onMeasureCalled = false;
-        listView.measure(measureSpec, measureSpec);
-        listView.layout(0, 0, 100, 100);
+        mListView.measure(measureSpec, measureSpec);
+        mListView.layout(0, 0, 100, 100);
         Assert.assertTrue(childView.onMeasureCalled);
     }
 
     @MediumTest
+    @UiThreadTest
+    @Test
     public void testNoSelectableItems() throws Exception {
-        ListView listView = new ListView(mActivity);
         // We use a header as the unselectable item to remain after the selectable one is removed.
-        listView.addHeaderView(new View(mActivity), null, false);
+        mListView.addHeaderView(new View(mActivity), null, false);
         List<String> items = new ArrayList<>();
         items.add("hello");
-        Adapter<String> adapter = new Adapter<String>(mActivity, 0, items);
-        listView.setAdapter(adapter);
+        MockAdapter<String> adapter = new MockAdapter<>(mActivity, 0, items);
+        mListView.setAdapter(adapter);
 
-        listView.setSelection(1);
+        mListView.setSelection(1);
 
         int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
 
         adapter.notifyDataSetChanged();
-        listView.measure(measureSpec, measureSpec);
-        listView.layout(0, 0, 100, 100);
+        mListView.measure(measureSpec, measureSpec);
+        mListView.layout(0, 0, 100, 100);
 
         items.remove(0);
 
         adapter.notifyDataSetChanged();
-        listView.measure(measureSpec, measureSpec);
-        listView.layout(0, 0, 100, 100);
+        mListView.measure(measureSpec, measureSpec);
+        mListView.layout(0, 0, 100, 100);
     }
 
     @MediumTest
-    public void testFullDetachHeaderViewOnScroll() {
+    @Test
+    public void testFullDetachHeaderViewOnScroll() throws Throwable {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mListView, () -> {
             mListView.scrollListBy(mListView.getHeight() * 3);
         });
         assertNull("test sanity, header should be removed", header.getParent());
@@ -649,15 +699,16 @@
     }
 
     @MediumTest
-    public void testFullDetachHeaderViewOnRelayout() {
+    @Test
+    public void testFullDetachHeaderViewOnRelayout() throws Throwable {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mListView, () -> {
             mListView.setSelection(800);
         });
         assertNull("test sanity, header should be removed", header.getParent());
@@ -666,9 +717,10 @@
     }
 
     @MediumTest
-    public void testFullDetachHeaderViewOnScrollForFocus() {
+    @Test
+    public void testFullDetachHeaderViewOnScrollForFocus() throws Throwable {
         final AttachDetachAwareView header = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000));
             mListView.addHeaderView(header);
         });
@@ -676,28 +728,29 @@
         assertEquals("test sanity", 0, header.mOnDetachCount);
         while(header.getParent() != null) {
             assertEquals("header view should NOT be detached", 0, header.mOnDetachCount);
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, null);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mListView, KeyEvent.KEYCODE_DPAD_DOWN);
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, null);
         }
         assertEquals("header view should be detached", 1, header.mOnDetachCount);
         assertFalse(header.isTemporarilyDetached());
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnScroll() {
+    @Test
+    public void testFullyDetachUnusedViewOnScroll() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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);
@@ -709,20 +762,21 @@
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnReLayout() {
+    @Test
+    public void testFullyDetachUnusedViewOnReLayout() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, mListView, () -> {
             mListView.setSelection(0);
         });
         assertNotNull("test sanity, view should be re-added", theView.getParent());
@@ -732,23 +786,24 @@
     }
 
     @MediumTest
-    public void testFullyDetachUnusedViewOnScrollForFocus() {
+    @Test
+    public void testFullyDetachUnusedViewOnScrollForFocus() throws Throwable {
         final AttachDetachAwareView theView = new AttachDetachAwareView(mActivity);
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, () -> {
             mListView.setAdapter(new DummyAdapter(1000, theView));
         });
         assertEquals("test sanity", 1, theView.mOnAttachCount);
         assertEquals("test sanity", 0, theView.mOnDetachCount);
         while(theView.getParent() != null) {
             assertEquals("the view should NOT be detached", 0, theView.mOnDetachCount);
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-            ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, null);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mListView, KeyEvent.KEYCODE_DPAD_DOWN);
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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);
+            CtsKeyEventUtil.sendKeys(mInstrumentation, mListView, KeyEvent.KEYCODE_DPAD_UP);
+            WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, null);
         }
         assertEquals("the view should be re-attached", 2, theView.mOnAttachCount);
         assertEquals("the view should not recieve another detach", 1, theView.mOnDetachCount);
@@ -756,43 +811,45 @@
     }
 
     @MediumTest
-    public void testSetPadding() {
+    @Test
+    public void testSetPadding() throws Throwable {
         View view = new View(mActivity);
         view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 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(mActivityRule, 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(mActivityRule, mListView, () -> {
             mListView.setPadding(10, 0, 5, 0);
             assertTrue(view.isLayoutRequested());
         });
         assertEquals(185, view.getWidth());
         assertFalse(view.isLayoutRequested());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, () -> {
             mListView.setPadding(10, 0, 5, 0);
             assertFalse(view.isLayoutRequested());
         });
     }
 
     @MediumTest
-    public void testResolveRtlOnReAttach() {
-        View spacer = new View(getActivity());
+    @Test
+    public void testResolveRtlOnReAttach() throws Throwable {
+        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(mActivityRule, 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(mActivityRule, mListView, () -> {
             // we scroll in pieces because list view caps scroll by its height
             mListView.scrollListBy(100);
             mListView.scrollListBy(100);
@@ -800,14 +857,14 @@
         });
         assertEquals("test sanity", 1, mListView.getChildCount());
         assertEquals("test sanity", 1, mListView.getFirstVisiblePosition());
-        ViewTestUtils.runOnMainAndDrawSync(getInstrumentation(), mListView, () -> {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mListView, () -> {
             mListView.scrollListBy(100);
             mListView.scrollListBy(100);
             mListView.scrollListBy(60);
@@ -834,9 +891,9 @@
         }
     }
 
-    private class Adapter<T> extends ArrayAdapter<T> {
+    private class MockAdapter<T> extends ArrayAdapter<T> {
 
-        public Adapter(Context context, int resource, List<T> objects) {
+        public MockAdapter(Context context, int resource, List<T> objects) {
             super(context, resource, objects);
         }
 
@@ -847,8 +904,8 @@
     }
 
     @MediumTest
-    public void testRequestLayoutWithTemporaryDetach() throws Exception {
-        ListView listView = new ListView(mActivity);
+    @Test
+    public void testRequestLayoutWithTemporaryDetach() throws Throwable {
         List<String> items = new ArrayList<>();
         items.add("0");
         items.add("1");
@@ -856,38 +913,34 @@
         final TemporarilyDetachableMockViewAdapter<String> adapter =
                 new TemporarilyDetachableMockViewAdapter<>(
                         mActivity, android.R.layout.simple_list_item_1, items);
-        mInstrumentation.runOnMainSync(() -> {
-            listView.setAdapter(adapter);
-            mActivity.setContentView(listView);
-        });
-        mInstrumentation.waitForIdleSync();
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.setAdapter(adapter));
 
-        assertEquals(items.size(), listView.getCount());
+        assertEquals(items.size(), mListView.getCount());
         final TemporarilyDetachableMockView childView0 =
-                (TemporarilyDetachableMockView) listView.getChildAt(0);
+                (TemporarilyDetachableMockView) mListView.getChildAt(0);
         final TemporarilyDetachableMockView childView1 =
-                (TemporarilyDetachableMockView) listView.getChildAt(1);
+                (TemporarilyDetachableMockView) mListView.getChildAt(1);
         final TemporarilyDetachableMockView childView2 =
-                (TemporarilyDetachableMockView) listView.getChildAt(2);
+                (TemporarilyDetachableMockView) mListView.getChildAt(2);
         assertNotNull(childView0);
         assertNotNull(childView1);
         assertNotNull(childView2);
 
         // Make sure that the childView1 has focus.
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, childView1, childView1::requestFocus);
-        assertTrue(childView1.isFocused());
+        mActivityRule.runOnUiThread(childView1::requestFocus);
+        PollingCheck.waitFor(1000, childView1::isFocused);
 
         // Make sure that ListView#requestLayout() is optimized when nothing is changed.
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, listView::requestLayout);
-        assertEquals(childView0, listView.getChildAt(0));
-        assertEquals(childView1, listView.getChildAt(1));
-        assertEquals(childView2, listView.getChildAt(2));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, mListView::requestLayout);
+        assertEquals(childView0, mListView.getChildAt(0));
+        assertEquals(childView1, mListView.getChildAt(1));
+        assertEquals(childView2, mListView.getChildAt(2));
     }
 
-    private static final int EXACTLY_500_PX = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY);
-
     @MediumTest
-    public void testJumpDrawables() {
+    @Test
+    public void testJumpDrawables() throws Throwable {
         FrameLayout layout = new FrameLayout(mActivity);
         ListView listView = new ListView(mActivity);
         ArrayAdapterWithMockDrawable adapter = new ArrayAdapterWithMockDrawable(mActivity);
@@ -896,7 +949,7 @@
         }
 
         // Initial state should jump exactly once during attach.
-        mInstrumentation.runOnMainSync(() -> {
+        mActivityRule.runOnUiThread(() -> {
             listView.setAdapter(adapter);
             layout.addView(listView, new LayoutParams(LayoutParams.MATCH_PARENT, 200));
             mActivity.setContentView(layout);
@@ -907,7 +960,7 @@
         verify(firstBackground, times(1)).jumpToCurrentState();
 
         // Lay out views without recycling. This should not jump again.
-        mInstrumentation.runOnMainSync(() -> listView.requestLayout());
+        mActivityRule.runOnUiThread(() -> listView.requestLayout());
         mInstrumentation.waitForIdleSync();
         assertSame(firstBackground, listView.getChildAt(0).getBackground());
         verify(firstBackground, times(1)).jumpToCurrentState();
@@ -929,7 +982,7 @@
         // Scroll so that we have new views on screen. This should jump at
         // least once when the view is recycled in a new position (but may be
         // more if it was recycled from a view that was previously on-screen).
-        mInstrumentation.runOnMainSync(() -> listView.setSelection(targetPosition));
+        mActivityRule.runOnUiThread(() -> listView.setSelection(targetPosition));
         mInstrumentation.waitForIdleSync();
 
         View lastChild = listView.getChildAt(listView.getChildCount() - 1);
@@ -941,7 +994,7 @@
         // Scroll back to the top. This should jump at least once when the view
         // is recycled in a new position (but may be more if it was recycled
         // from a view that was previously on-screen).
-        mInstrumentation.runOnMainSync(() -> listView.setSelection(0));
+        mActivityRule.runOnUiThread(() -> listView.setSelection(0));
         mInstrumentation.waitForIdleSync();
 
         View firstChild = listView.getChildAt(0);
@@ -1038,17 +1091,22 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            return views.get(position);
+            View result = views.get(position);
+            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, 40);
+            result.setLayoutParams(lp);
+            return result;
         }
     }
 
-    public void testTransientStateUnstableIds() throws Exception {
+    @Test
+    public void testTransientStateUnstableIds() throws Throwable {
         final ListView listView = mListView;
         final ArrayList<String> items = new ArrayList<String>(Arrays.asList(mCountryList));
         final ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity,
                 android.R.layout.simple_list_item_1, items);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView,
                 () -> listView.setAdapter(adapter));
 
         final View oldItem = listView.getChildAt(2);
@@ -1056,7 +1114,7 @@
                 .getText();
         oldItem.setHasTransientState(true);
 
-        ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, listView,
                 () -> {
                     adapter.remove(adapter.getItem(0));
                     adapter.notifyDataSetChanged();
@@ -1069,29 +1127,29 @@
         Assert.assertFalse(oldText.equals(newText));
     }
 
-    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,
+    @Test
+    public void testTransientStateStableIds() throws Throwable {
+        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(mActivityRule, 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(mActivityRule, 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 +1173,136 @@
             return true;
         }
     }
+
+    @LargeTest
+    @Test
+    public void testSmoothScrollByOffset() throws Throwable {
+        final int itemCount = mLongCountryList.length;
+
+        mActivityRule.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;
+        mActivityRule.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;
+        }
+    }
+
+    @Test
+    public void testGetCheckItemIds() throws Throwable {
+        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(mActivityRule, mListView,
+                () -> mListView.setAdapter(adapter));
+
+        mActivityRule.runOnUiThread(
+                () -> mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE));
+        assertTrue(mListView.getCheckItemIds().length == 0);
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, true));
+        TestUtils.assertIdentical(new long[] { 2 }, mListView.getCheckItemIds());
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, true));
+        TestUtils.assertIdentical(new long[] { 2, 4 }, mListView.getCheckItemIds());
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(2, false));
+        TestUtils.assertIdentical(new long[] { 4 }, mListView.getCheckItemIds());
+
+        mActivityRule.runOnUiThread(() -> mListView.setItemChecked(4, false));
+        assertTrue(mListView.getCheckItemIds().length == 0);
+    }
+
+    @Test
+    public void testAccessOverscrollHeader() throws Throwable {
+        final Drawable overscrollHeaderDrawable = spy(new ColorDrawable(Color.YELLOW));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView, () -> {
+            mListView.setAdapter(mAdapter_longCountries);
+            mListView.setOverscrollHeader(overscrollHeaderDrawable);
+        });
+
+        assertEquals(overscrollHeaderDrawable, mListView.getOverscrollHeader());
+        verify(overscrollHeaderDrawable, never()).draw(any(Canvas.class));
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mListView,
+                () -> mListView.setScrollY(-mListView.getHeight() / 2));
+
+        verify(overscrollHeaderDrawable, atLeastOnce()).draw(any(Canvas.class));
+    }
+
+    @Test
+    public void testAccessOverscrollFooter() throws Throwable {
+        final Drawable overscrollFooterDrawable = spy(new ColorDrawable(Color.MAGENTA));
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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..386c3d9 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
@@ -16,25 +16,34 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+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 android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 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 com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -42,25 +51,25 @@
 /**
  * Test {@link MediaController}.
  */
-public class MediaControllerTest extends
-        ActivityInstrumentationTestCase2<MediaControllerCtsActivity> {
-    private MediaController mMediaController;
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class MediaControllerTest {
     private Instrumentation mInstrumentation;
-    private static final long DEFAULT_TIMEOUT = 3000;
+    private Activity mActivity;
+    private MediaController mMediaController;
 
-    public MediaControllerTest() {
-        super("android.widget.cts", MediaControllerCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<MediaControllerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(MediaControllerCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new MediaController(mActivity, null);
 
@@ -80,6 +89,7 @@
      *
      */
     @UiThreadTest
+    @Test
     public void testMediaController() {
         mMediaController = new MediaController(mActivity);
         final MockMediaPlayerControl mediaPlayerControl = new MockMediaPlayerControl();
@@ -109,12 +119,10 @@
         assertTrue(mMediaController.isShowing());
     }
 
-    public void testShow() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMediaController = new MediaController(mActivity, true);
-            }
-        });
+    @Test
+    public void testShow() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> mMediaController = new MediaController(mActivity, true));
         mInstrumentation.waitForIdleSync();
         assertFalse(mMediaController.isShowing());
 
@@ -125,48 +133,29 @@
                 (VideoView) mActivity.findViewById(R.id.mediacontroller_videoview);
         mMediaController.setAnchorView(videoView);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMediaController.show();
-            }
-        });
+        mActivityRule.runOnUiThread(mMediaController::show);
         mInstrumentation.waitForIdleSync();
         assertTrue(mMediaController.isShowing());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMediaController.hide();
-            }
-        });
+        mActivityRule.runOnUiThread(mMediaController::hide);
         mInstrumentation.waitForIdleSync();
         assertFalse(mMediaController.isShowing());
 
         final int timeout = 2000;
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMediaController.show(timeout);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mMediaController.show(timeout));
+
         mInstrumentation.waitForIdleSync();
         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() {
-        InputStream source = null;
-        OutputStream target = null;
         final String VIDEO_NAME   = "testvideo.3gp";
 
-        try {
-            source = mActivity.getResources().openRawResource(R.raw.testvideo);
-            target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE);
+        try (InputStream source = mActivity.getResources().openRawResource(R.raw.testvideo);
+             OutputStream target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE)) {
 
             final byte[] buffer = new byte[1024];
             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
@@ -174,28 +163,14 @@
             }
         } catch (final IOException e) {
             fail(e.getMessage());
-        } finally {
-            try {
-                if (source != null) {
-                    source.close();
-                }
-                if (target != null) {
-                    target.close();
-                }
-            } catch (final IOException ignored) {
-                // Ignore the IOException.
-            }
         }
 
         return mActivity.getFileStreamPath(VIDEO_NAME).getAbsolutePath();
     }
 
-    public void testOnTrackballEvent() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mMediaController = new MediaController(mActivity);
-            }
-        });
+    @Test
+    public void testOnTrackballEvent() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mMediaController = new MediaController(mActivity));
         mInstrumentation.waitForIdleSync();
         final MockMediaPlayerControl mediaPlayerControl = new MockMediaPlayerControl();
         mMediaController.setMediaPlayer(mediaPlayerControl);
@@ -203,11 +178,9 @@
         final VideoView videoView =
                 (VideoView) mActivity.findViewById(R.id.mediacontroller_videoview);
         videoView.setMediaController(mMediaController);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                videoView.setVideoPath(prepareSampleVideo());
-                videoView.requestFocus();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            videoView.setVideoPath(prepareSampleVideo());
+            videoView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
@@ -228,6 +201,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetEnabled() {
         final View videoView = mActivity.findViewById(R.id.mediacontroller_videoview);
         final MockMediaPlayerControl mediaPlayerControl = new MockMediaPlayerControl();
@@ -236,9 +210,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();
 
@@ -250,6 +224,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetPrevNextListeners() {
         final View videoView = mActivity.findViewById(R.id.mediacontroller_videoview);
         final MockMediaPlayerControl mediaPlayerControl = new MockMediaPlayerControl();
@@ -258,20 +233,15 @@
         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 {
-        private boolean mIsPlayingCalled = false;
         private boolean mIsPlaying = false;
         private int mPosition = 0;
 
-        public boolean hasIsPlayingCalled() {
-            return mIsPlayingCalled;
-        }
-
         public void start() {
             mIsPlaying = true;
         }
@@ -293,7 +263,6 @@
         }
 
         public boolean isPlaying() {
-            mIsPlayingCalled = true;
             return mIsPlaying;
         }
 
@@ -318,16 +287,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/MockLinearLayout.java b/tests/tests/widget/src/android/widget/cts/MockLinearLayout.java
deleted file mode 100644
index da1937e..0000000
--- a/tests/tests/widget/src/android/widget/cts/MockLinearLayout.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-package android.widget.cts;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.ViewParent;
-import android.widget.LinearLayout;
-
-public class MockLinearLayout extends LinearLayout {
-
-    public boolean mIsInvalidateChildInParentCalled;
-
-    public MockLinearLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MockLinearLayout(Context context) {
-        super(context);
-    }
-
-    @Override
-    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
-        mIsInvalidateChildInParentCalled = true;
-        return super.invalidateChildInParent(location, dirty);
-    }
-
-}
-
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..4075a83 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextViewTest.java
@@ -16,88 +16,95 @@
 
 package android.widget.cts;
 
-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.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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.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;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class MultiAutoCompleteTextViewTest {
+    private Activity mActivity;
     private MultiAutoCompleteTextView mMultiAutoCompleteTextView_country;
     private MultiAutoCompleteTextView mMultiAutoCompleteTextView_name;
-    private Activity mActivity;
 
-    public MultiAutoCompleteTextViewTest() {
-        super("android.widget.cts", MultiAutoCompleteTextViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<MultiAutoCompleteTextViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(MultiAutoCompleteTextViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mMultiAutoCompleteTextView_country = (MultiAutoCompleteTextView)mActivity
                 .findViewById(R.id.country_edit);
         mMultiAutoCompleteTextView_name = (MultiAutoCompleteTextView)mActivity
                 .findViewById(R.id.name_edit);
     }
 
-    @UiThreadTest
+    @Test
     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);
-
-        try {
-            new MultiAutoCompleteTextView(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
-
-        try {
-            new MultiAutoCompleteTextView(null, null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
-
-        try {
-            new MultiAutoCompleteTextView(null, null, -1);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
+        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);
     }
 
-    @UiThreadTest
-    private void setText(MultiAutoCompleteTextView m, CharSequence c) {
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new MultiAutoCompleteTextView(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new MultiAutoCompleteTextView(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new MultiAutoCompleteTextView(null, null, -1);
+    }
+
+    private void setText(final MultiAutoCompleteTextView m, final CharSequence c) {
         m.setText(c);
         m.setSelection(0, c.length());
     }
 
     @UiThreadTest
+    @Test
     public void testMultiAutoCompleteTextView() {
         mMultiAutoCompleteTextView_country.setTokenizer(new CommaTokenizer());
         mMultiAutoCompleteTextView_name.setTokenizer(new CommaTokenizer());
@@ -125,21 +132,23 @@
 
         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
+    @Test
     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];
+                    }
+                });
+
+        mMultiAutoCompleteTextView_country.setValidator(validator);
         MockTokenizer t = new MockTokenizer();
         mMultiAutoCompleteTextView_country.setTokenizer(t);
         String str = new String("Foo, Android Test, OH");
@@ -147,19 +156,20 @@
         mMultiAutoCompleteTextView_country.performValidation();
         assertEquals(str, mMultiAutoCompleteTextView_country.getText().toString());
 
-        v.setValid(false);
+        when(validator.isValid(any(CharSequence.class))).thenReturn(false);
         mMultiAutoCompleteTextView_country.performValidation();
         assertEquals(str + ", ", mMultiAutoCompleteTextView_country.getText().toString());
     }
 
     @UiThreadTest
+    @Test
     public void testPerformFiltering() {
         MyMultiAutoCompleteTextView multiAutoCompleteTextView =
             new MyMultiAutoCompleteTextView(mActivity);
         CommaTokenizer t = new CommaTokenizer();
         multiAutoCompleteTextView.setTokenizer(t);
 
-        ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity,
+        ArrayAdapter<String> adapter = new ArrayAdapter<>(mActivity,
                 R.layout.simple_dropdown_item_1line);
         assertNotNull(adapter);
 
@@ -169,8 +179,8 @@
         String text = "Android test.";
         multiAutoCompleteTextView.setText(text);
         multiAutoCompleteTextView.setSelection(0, 12);
-
         multiAutoCompleteTextView.performFiltering(text, KeyEvent.KEYCODE_0);
+
         assertNotNull(multiAutoCompleteTextView.getFilter());
 
         multiAutoCompleteTextView.performFiltering(text, 0, text.length(), KeyEvent.KEYCODE_E);
@@ -178,6 +188,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testReplaceText() {
         MyMultiAutoCompleteTextView multiAutoCompleteTextView =
             new MyMultiAutoCompleteTextView(mActivity);
@@ -253,22 +264,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/MultiAutoCompleteTextView_CommaTokenizerTest.java b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextView_CommaTokenizerTest.java
index 254050f..ba467e4 100644
--- a/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextView_CommaTokenizerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MultiAutoCompleteTextView_CommaTokenizerTest.java
@@ -16,35 +16,41 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
 
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.style.UnderlineSpan;
-import android.widget.MultiAutoCompleteTextView.CommaTokenizer;
+import android.widget.MultiAutoCompleteTextView;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class MultiAutoCompleteTextView_CommaTokenizerTest extends TestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MultiAutoCompleteTextView_CommaTokenizerTest {
     private static final String TEST_TEXT = "first token, second token";
-    CommaTokenizer mCommaTokenizer;
+    MultiAutoCompleteTextView.CommaTokenizer mCommaTokenizer;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mCommaTokenizer = new CommaTokenizer();
+    @Before
+    public void setup() {
+        mCommaTokenizer = new MultiAutoCompleteTextView.CommaTokenizer();
     }
 
+    @Test
     public void testConstructor() {
-        new CommaTokenizer();
+        new MultiAutoCompleteTextView.CommaTokenizer();
     }
 
+    @Test
     public void testFindTokenStart() {
         int indexOfSecondToken = TEST_TEXT.indexOf("second");
         assertEquals(indexOfSecondToken,
                 mCommaTokenizer.findTokenStart(TEST_TEXT, indexOfSecondToken));
         // cursor point to the space before "second".
-        // FIXME: does it worked as intended? findTokenStart does not exclude this leading
-        // space in this case.
         assertEquals(indexOfSecondToken - 1,
                 mCommaTokenizer.findTokenStart(TEST_TEXT, indexOfSecondToken - 1));
         assertEquals(indexOfSecondToken,
@@ -56,22 +62,19 @@
 
         assertEquals(-1, mCommaTokenizer.findTokenStart(TEST_TEXT, -1));
         assertEquals(-2, mCommaTokenizer.findTokenStart(TEST_TEXT, -2));
-
-        try {
-            mCommaTokenizer.findTokenStart(TEST_TEXT, TEST_TEXT.length() + 1);
-            fail("did not throw IndexOutOfBoundsException when cursor is large than length");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            mCommaTokenizer.findTokenStart(null, TEST_TEXT.length());
-            fail("did not throw NullPointerException when text is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testFindTokenStartInvalidCursor() {
+        mCommaTokenizer.findTokenStart(TEST_TEXT, TEST_TEXT.length() + 1);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testFindTokenStartNullText() {
+        mCommaTokenizer.findTokenStart(null, TEST_TEXT.length());
+    }
+
+    @Test
     public void testFindTokenEnd() {
         int indexOfComma = TEST_TEXT.indexOf(",");
 
@@ -85,22 +88,19 @@
                 mCommaTokenizer.findTokenEnd(TEST_TEXT, TEST_TEXT.length()));
         assertEquals(TEST_TEXT.length(),
                 mCommaTokenizer.findTokenEnd(TEST_TEXT, TEST_TEXT.length() + 1));
-
-        try {
-            mCommaTokenizer.findTokenEnd(TEST_TEXT, -1);
-            fail("did not throw IndexOutOfBoundsException when cursor is -1");
-        } catch (IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            mCommaTokenizer.findTokenEnd(null, 1);
-            fail("did not throw NullPointerException when text is null");
-        } catch (NullPointerException e) {
-            // expected
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testFindTokenEndInvalidCursor() {
+        mCommaTokenizer.findTokenEnd(TEST_TEXT, -1);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testFindTokenEndNullText() {
+        mCommaTokenizer.findTokenEnd(null, 1);
+    }
+
+    @Test
     public void testTerminateToken() {
         String text = "end with comma,";
         assertEquals(text, mCommaTokenizer.terminateToken(text));
@@ -130,12 +130,10 @@
         assertEquals(expected.toString(), actual.toString());
         assertEquals(0, actual.getSpanStart(what));
         assertEquals(spannableString.length(), actual.getSpanEnd(what));
+    }
 
-        try {
-            mCommaTokenizer.terminateToken(null);
-            fail("did not throw NullPointerException when text is null");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
+    @Test(expected=NullPointerException.class)
+    public void testTerminateTokenNullText() {
+        mCommaTokenizer.terminateToken(null);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/MyGallery.java b/tests/tests/widget/src/android/widget/cts/MyGallery.java
deleted file mode 100644
index 27b5d45..0000000
--- a/tests/tests/widget/src/android/widget/cts/MyGallery.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.
- */
-
-package android.widget.cts;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-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;
-
-/**
- * A minimal mock gallery for {@link Gallery} test.
- */
-public class MyGallery extends Gallery {
-    private ContextMenuInfo mContextMenuInfo;
-
-    public MyGallery(Context context) {
-        super(context);
-    }
-
-    public MyGallery(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MyGallery(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected boolean getChildStaticTransformation(View child, Transformation t) {
-        return super.getChildStaticTransformation(child, t);
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return super.checkLayoutParams(p);
-    }
-
-    @Override
-    protected int computeHorizontalScrollExtent() {
-        return super.computeHorizontalScrollExtent();
-    }
-
-    @Override
-    protected int computeHorizontalScrollOffset() {
-        return super.computeHorizontalScrollOffset();
-    }
-
-    @Override
-    protected int computeHorizontalScrollRange() {
-        return super.computeHorizontalScrollRange();
-    }
-
-    @Override
-    protected void dispatchSetPressed(boolean pressed) {
-        super.dispatchSetPressed(pressed);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return super.generateDefaultLayoutParams();
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return super.generateLayoutParams(p);
-    }
-
-    @Override
-    protected int getChildDrawingOrder(int childCount, int i) {
-        return super.getChildDrawingOrder(childCount, i);
-    }
-
-    @Override
-    protected ContextMenuInfo getContextMenuInfo() {
-        if (mContextMenuInfo == null) {
-            mContextMenuInfo = new MyContextMenuInfo();
-        }
-        return mContextMenuInfo;
-    }
-
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction,
-            Rect previouslyFocusedRect) {
-        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-    }
-
-    private static class MyContextMenuInfo implements ContextMenuInfo {
-    }
-}
diff --git a/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java b/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java
deleted file mode 100644
index a5a0150..0000000
--- a/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java
+++ /dev/null
@@ -1,85 +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.widget.cts;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.HorizontalScrollView;
-
-public class MyHorizontalScrollView extends HorizontalScrollView {
-    public MyHorizontalScrollView(Context context) {
-        super(context);
-    }
-
-    public MyHorizontalScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected int computeHorizontalScrollRange() {
-        return super.computeHorizontalScrollRange();
-    }
-
-    @Override
-    protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
-        return super.computeScrollDeltaToGetChildRectOnScreen(rect);
-    }
-
-    @Override
-    protected float getLeftFadingEdgeStrength() {
-        return super.getLeftFadingEdgeStrength();
-    }
-
-    @Override
-    protected float getRightFadingEdgeStrength() {
-        return super.getRightFadingEdgeStrength();
-    }
-
-    @Override
-    protected void measureChild(View child, int parentWidthMeasureSpec,
-            int parentHeightMeasureSpec) {
-        super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec);
-    }
-
-    @Override
-    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
-            int parentHeightMeasureSpec, int heightUsed) {
-        super.measureChildWithMargins(child, parentWidthMeasureSpec,
-                widthUsed, parentHeightMeasureSpec, heightUsed);
-    }
-
-    @Override
-    public int computeVerticalScrollRange() {
-        return super.computeVerticalScrollRange();
-    }
-
-    @Override
-    public int computeVerticalScrollOffset() {
-        return super.computeVerticalScrollOffset();
-    }
-
-    @Override
-    public int computeVerticalScrollExtent() {
-        return super.computeVerticalScrollExtent();
-    }
-}
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/tests/tests/widget/src/android/widget/cts/MyScrollView.java b/tests/tests/widget/src/android/widget/cts/MyScrollView.java
deleted file mode 100644
index 006b423..0000000
--- a/tests/tests/widget/src/android/widget/cts/MyScrollView.java
+++ /dev/null
@@ -1,69 +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.widget.cts;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ScrollView;
-
-public class MyScrollView extends ScrollView {
-    public MyScrollView(Context context) {
-        super(context);
-    }
-
-    public MyScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
-        return super.computeScrollDeltaToGetChildRectOnScreen(rect);
-    }
-
-    @Override
-    protected int computeVerticalScrollRange() {
-        return super.computeVerticalScrollRange();
-    }
-
-    @Override
-    protected float getBottomFadingEdgeStrength() {
-        return super.getBottomFadingEdgeStrength();
-    }
-
-    @Override
-    protected float getTopFadingEdgeStrength() {
-        return super.getTopFadingEdgeStrength();
-    }
-
-    @Override
-    protected void measureChild(View c, int pWidthMeasureSpec, int pHeightMeasureSpec) {
-        super.measureChild(c, pWidthMeasureSpec, pHeightMeasureSpec);
-    }
-
-    @Override
-    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
-            int parentHeightMeasureSpec, int heightUsed) {
-        super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
-                parentHeightMeasureSpec, heightUsed);
-    }
-}
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
new file mode 100644
index 0000000..f93a1da
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.NumberPicker;
+
+/**
+ * A minimal application for {@link NumberPicker} test.
+ */
+public class NumberPickerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..4d25740
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -0,0 +1,404 @@
+/*
+ * 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.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.inOrder;
+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.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+import android.widget.NumberPicker;
+
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NumberPickerTest {
+    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;
+
+    @Rule
+    public ActivityTestRule<NumberPickerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(NumberPickerCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mNumberPicker = (NumberPicker) mActivity.findViewById(R.id.number_picker);
+    }
+
+    @UiThreadTest
+    @Test
+    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]);
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetDisplayedValuesRangeMatch() {
+        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
+        mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+
+        assertEquals(10, mNumberPicker.getMinValue());
+        assertEquals(12, mNumberPicker.getMaxValue());
+        verifyDisplayedValues(NUMBER_NAMES_ALT3);
+
+        mNumberPicker.setMinValue(24);
+        mNumberPicker.setMaxValue(26);
+
+        assertEquals(24, mNumberPicker.getMinValue());
+        assertEquals(26, mNumberPicker.getMaxValue());
+        verifyDisplayedValues(NUMBER_NAMES_ALT3);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetDisplayedValuesRangeMismatch() {
+        mNumberPicker.setMinValue(10);
+        mNumberPicker.setMaxValue(14);
+        assertEquals(10, mNumberPicker.getMinValue());
+        assertEquals(14, mNumberPicker.getMaxValue());
+
+        // Try setting too few displayed entries
+        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);
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSelectionDisplayedValueFromDisplayedValues() {
+        mNumberPicker.setMinValue(1);
+        mNumberPicker.setMaxValue(3);
+        mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(2);
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(3);
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Switch to a different displayed values array
+        mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(2);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSelectionDisplayedValueFromFormatter() {
+        mNumberPicker.setMinValue(0);
+        mNumberPicker.setMaxValue(4);
+        mNumberPicker.setFormatter((int value) -> "entry " + value);
+
+        mNumberPicker.setValue(0);
+        assertTrue(TextUtils.equals("entry 0",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals("entry 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(2);
+        assertTrue(TextUtils.equals("entry 2",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(3);
+        assertTrue(TextUtils.equals("entry 3",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(4);
+        assertTrue(TextUtils.equals("entry 4",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Switch to a different formatter
+        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
+        mNumberPicker.setValue(0);
+        assertTrue(TextUtils.equals("row 0",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals("row 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+
+    @UiThreadTest
+    @Test
+    public void testSelectionDisplayedValuePrecedence() {
+        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
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(2);
+        assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        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
+        mNumberPicker.setDisplayedValues(null);
+        assertTrue(TextUtils.equals("entry 3",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals("entry 1",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(2);
+        assertTrue(TextUtils.equals("entry 2",
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        // Set a different displayed values array and test that it's taking precedence
+        mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(1);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+        mNumberPicker.setValue(3);
+        assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+                mNumberPicker.getDisplayedValueForCurrentSelection()));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessValue() {
+        mNumberPicker.setMinValue(20);
+        mNumberPicker.setMaxValue(22);
+        mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+
+        final NumberPicker.OnValueChangeListener mockValueChangeListener =
+                mock(NumberPicker.OnValueChangeListener.class);
+        mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+        mNumberPicker.setValue(21);
+        assertEquals(21, mNumberPicker.getValue());
+
+        mNumberPicker.setValue(20);
+        assertEquals(20, mNumberPicker.getValue());
+
+        mNumberPicker.setValue(22);
+        assertEquals(22, mNumberPicker.getValue());
+
+        // Check trying to set value out of min/max range
+        mNumberPicker.setValue(10);
+        assertEquals(20, mNumberPicker.getValue());
+
+        mNumberPicker.setValue(100);
+        assertEquals(22, mNumberPicker.getValue());
+
+        // Since all changes to value are via API calls, we should have no interactions /
+        // callbacks on our listener.
+        verifyZeroInteractions(mockValueChangeListener);
+    }
+
+    @Test
+    public void testInteractionWithSwipeDown() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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);
+
+        mActivityRule.runOnUiThread(() -> 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_FLING);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+        verifyNoMoreInteractions(mockScrollListener);
+    }
+
+    @Test
+    public void testInteractionWithSwipeUp() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            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);
+
+        mActivityRule.runOnUiThread(() -> 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_FLING);
+        inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+                NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+        verifyNoMoreInteractions(mockScrollListener);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessWrapSelectorValue() {
+        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());
+
+        mNumberPicker.setWrapSelectorWheel(false);
+        assertFalse(mNumberPicker.getWrapSelectorWheel());
+
+        mNumberPicker.setWrapSelectorWheel(true);
+        assertTrue(mNumberPicker.getWrapSelectorWheel());
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
new file mode 100644
index 0000000..c0c6b78
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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.os.Bundle;
+
+public class PointerIconCtsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.pointer_icon_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconTest.java b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
new file mode 100644
index 0000000..fe985b2
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.View;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+import android.widget.TextView;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointerIconTest {
+
+    @Rule
+    public final ActivityTestRule<PointerIconCtsActivity> mActivityRule =
+            new ActivityTestRule<>(PointerIconCtsActivity.class);
+
+    private Activity mActivity;
+    private View mTopView;
+    private PointerIcon mHandIcon;
+    private PointerIcon mHelpIcon;
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mTopView = mActivity.findViewById(R.id.top);
+        mHandIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND);
+        mHelpIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP);
+    }
+
+    private void assertPointerIcon(String message, PointerIcon expectedIcon, View target) {
+        final int[] topPos = mTopView.getLocationOnScreen();
+        final int[] targetPos = target.getLocationOnScreen();
+        final int x = targetPos[0] + target.getWidth() / 2 - topPos[0];
+        final int y = targetPos[1] + target.getHeight() / 2 - topPos[1];
+        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
+        assertEquals(message, expectedIcon, mTopView.onResolvePointerIcon(event, 0));
+    }
+
+    private void assertDefaultWidgetPointerIconBehavior(View view) {
+        assertPointerIcon("Default pointer icon", mHandIcon, view);
+
+        view.setEnabled(false);
+        assertPointerIcon("Disabled view has no pointer icon", null, view);
+
+        view.setEnabled(true);
+        assertPointerIcon("Enabled view has default pointer icon", mHandIcon, view);
+
+        view.setPointerIcon(mHelpIcon);
+        assertPointerIcon("Override pointer icon", mHelpIcon, view);
+
+        view.setPointerIcon(null);
+        assertPointerIcon("Revert to default pointer icon", mHandIcon, view);
+    }
+
+    private TabHost.TabSpec createTabSpec(TabHost tabHost, String label, PointerIcon pointerIcon) {
+        final TextView tabIndicator = new TextView(mActivity);
+        tabIndicator.setText(label);
+        tabIndicator.setPointerIcon(pointerIcon);
+        return tabHost.newTabSpec(label)
+                .setIndicator(tabIndicator)
+                .setContent(tag -> new View(mActivity));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.button));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testImageButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.image_button));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSpinnerButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.spinner));
+    }
+
+    @Test
+    public void testTabWidget() throws Throwable {
+        final TabHost tabHost = (TabHost) mActivity.findViewById(android.R.id.tabhost);
+
+        WidgetTestUtils.runOnMainAndLayoutSync(
+                mActivityRule,
+                () -> {
+                    tabHost.setup();
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 0", null));
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 1", mHandIcon));
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 2", mHelpIcon));
+                },
+                false /* force layout */);
+
+        mActivityRule.runOnUiThread(() -> {
+            final TabWidget tabWidget = tabHost.getTabWidget();
+
+            tabWidget.setEnabled(false);
+            assertPointerIcon("Disabled Tab 0", null, tabWidget.getChildTabViewAt(0));
+            assertPointerIcon("Disabled Tab 1", null, tabWidget.getChildTabViewAt(1));
+            assertPointerIcon("Disabled Tab 2", null, tabWidget.getChildTabViewAt(2));
+
+            tabWidget.setEnabled(true);
+            assertPointerIcon("Tab 0", mHandIcon, tabWidget.getChildTabViewAt(0));
+            assertPointerIcon("Tab 1", mHandIcon, tabWidget.getChildTabViewAt(1));
+            assertPointerIcon("Tab 2", mHelpIcon, tabWidget.getChildTabViewAt(2));
+        });
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index ee38448..daae02d 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -16,66 +16,72 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+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.verifyNoMoreInteractions;
+
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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.*;
+import com.android.compatibility.common.util.CtsTouchUtils;
 
-@SmallTest
-public class PopupMenuTest extends
-        ActivityInstrumentationTestCase2<PopupMenuCtsActivity> {
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PopupMenuTest {
     private Instrumentation mInstrumentation;
     private Activity mActivity;
 
     private Builder mBuilder;
     private PopupMenu mPopupMenu;
 
-    public PopupMenuTest() {
-        super("android.widget.cts", PopupMenuCtsActivity.class);
+    @Rule
+    public ActivityTestRule<PopupMenuCtsActivity> mActivityRule =
+            new ActivityTestRule<>(PopupMenuCtsActivity.class);
+
+
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+
+        // Disable and remove focusability on the first child of our activity so that
+        // it doesn't bring in the soft keyboard that can mess up with some of the tests
+        // (such as menu dismissal when we emulate a tap outside the menu bounds).
+        final EditText editText = (EditText) mActivity.findViewById(R.id.anchor_upper_left);
+        editText.setEnabled(false);
+        editText.setFocusable(false);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-
-        try {
-            runTestOnUiThread(() -> {
-                // Disable and remove focusability on the first child of our activity so that
-                // it doesn't bring in the soft keyboard that can mess up with some of the tests
-                // (such as menu dismissal when we emulate a tap outside the menu bounds).
-                final EditText editText = (EditText) mActivity.findViewById(R.id.anchor_upper_left);
-                editText.setEnabled(false);
-                editText.setFocusable(false);
-            });
-        } catch (Throwable t) {
-            throw new RuntimeException(t);
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void teardown() throws Throwable {
         if (mPopupMenu != null) {
-            try {
-                runTestOnUiThread(() -> mPopupMenu.dismiss());
-            } catch (Throwable t) {
-                throw new RuntimeException(t);
-            }
+            mActivityRule.runOnUiThread(mPopupMenu::dismiss);
         }
-        super.tearDown();
     }
 
     private void verifyMenuContent() {
@@ -95,84 +101,93 @@
         assertEquals(R.id.action_share_circles, shareSubMenu.getItem(1).getItemId());
     }
 
+    @Test
     public void testPopulateViaInflater() throws Throwable {
         mBuilder = new Builder().inflateWithInflater(true);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         verifyMenuContent();
     }
 
+    @Test
     public void testDirectPopulate() throws Throwable {
         mBuilder = new Builder().inflateWithInflater(false);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         verifyMenuContent();
     }
 
+    @Test
     public void testAccessGravity() throws Throwable {
         mBuilder = new Builder();
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
 
         assertEquals(Gravity.NO_GRAVITY, mPopupMenu.getGravity());
         mPopupMenu.setGravity(Gravity.TOP);
         assertEquals(Gravity.TOP, mPopupMenu.getGravity());
     }
 
+    @Test
     public void testConstructorWithGravity() throws Throwable {
         mBuilder = new Builder().withGravity(Gravity.TOP);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
 
         assertEquals(Gravity.TOP, mPopupMenu.getGravity());
     }
 
+    @Test
     public void testDismissalViaAPI() throws Throwable {
         mBuilder = new Builder().withDismissListener();
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
 
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        mActivityRule.runOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        mActivityRule.runOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         // Shouldn't have any more interactions with our dismiss listener since the menu was
         // already dismissed when we called dismiss()
         verifyNoMoreInteractions(mBuilder.mOnDismissListener);
     }
 
+    @Test
     public void testNestedDismissalViaAPI() throws Throwable {
         // Use empty popup style to remove all transitions from the popup. That way we don't
         // need to synchronize with the popup window enter transition before proceeding to
         // "click" a submenu item.
         mBuilder = new Builder().withDismissListener()
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0));
+        mActivityRule.runOnUiThread(
+                () -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0));
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(() -> mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
+        mActivityRule.runOnUiThread(
+                () -> mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
                         performIdentifierAction(R.id.action_share_email, 0));
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        mActivityRule.runOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.dismiss());
+        mActivityRule.runOnUiThread(mPopupMenu::dismiss);
         mInstrumentation.waitForIdleSync();
         // Shouldn't have any more interactions with our dismiss listener since the menu was
         // already dismissed when we called dismiss()
         verifyNoMoreInteractions(mBuilder.mOnDismissListener);
     }
 
+    @Test
     public void testDismissalViaTouch() throws Throwable {
         // Use empty popup style to remove all transitions from the popup. That way we don't
         // need to synchronize with the popup window enter transition before proceeding to
@@ -180,60 +195,32 @@
         mBuilder = new Builder().withDismissListener()
                 .withPopupMenuContent(R.menu.popup_menu_single)
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(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.emulateTapOnView(mInstrumentation, mBuilder.mAnchor, 10, -20);
 
         // At this point our popup should have notified its dismiss listener
         verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
     }
 
+    @Test
     public void testSimpleMenuItemClickViaAPI() throws Throwable {
         mBuilder = new Builder().withMenuItemClickListener().withDismissListener();
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
 
         // Verify that our menu item click listener hasn't been called yet
         verify(mBuilder.mOnMenuItemClickListener, never()).onMenuItemClick(any(MenuItem.class));
 
-        runTestOnUiThread(
+        mActivityRule.runOnUiThread(
                 () -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_highlight, 0));
 
         // Verify that our menu item click listener has been called with the expected menu item
@@ -245,26 +232,29 @@
         verifyNoMoreInteractions(mBuilder.mOnDismissListener);
     }
 
+    @Test
     public void testSubMenuClickViaAPI() throws Throwable {
         // Use empty popup style to remove all transitions from the popup. That way we don't
         // need to synchronize with the popup window enter transition before proceeding to
         // "click" a submenu item.
         mBuilder = new Builder().withDismissListener().withMenuItemClickListener()
                 .withPopupStyleResource(R.style.PopupWindow_NullTransitions);
-        runTestOnUiThread(() -> mBuilder.show());
+        mActivityRule.runOnUiThread(mBuilder::show);
         mInstrumentation.waitForIdleSync();
 
         // Verify that our menu item click listener hasn't been called yet
         verify(mBuilder.mOnMenuItemClickListener, never()).onMenuItemClick(any(MenuItem.class));
 
-        runTestOnUiThread(() -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0));
+        mActivityRule.runOnUiThread(
+                () -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0));
         // Verify that our menu item click listener has been called on "share" action
         // and that the dismiss listener hasn't been called just as a result of opening the submenu.
         verify(mBuilder.mOnMenuItemClickListener, times(1)).onMenuItemClick(
                 mPopupMenu.getMenu().findItem(R.id.action_share));
         verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
 
-        runTestOnUiThread(() -> mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
+        mActivityRule.runOnUiThread(
+                () -> mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
                         performIdentifierAction(R.id.action_share_email, 0));
 
         // Verify that out menu item click listener has been called with the expected menu item
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowCtsActivity.java b/tests/tests/widget/src/android/widget/cts/PopupWindowCtsActivity.java
index 418f04a..a2e7c60 100755
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowCtsActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.PopupWindow;
+import android.content.res.Configuration;
 import android.widget.cts.R;
 
 /**
@@ -30,5 +31,19 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.popup_window);
     }
+
+    @Override
+    public void onConfigurationChanged(Configuration c) {
+        super.onConfigurationChanged(c);
+        synchronized (this) {
+            this.notifyAll();
+        }
+    }
+
+    void waitForConfigurationChanged() throws InterruptedException {
+        synchronized (this) {
+            this.wait(10000);
+        }
+    }
 }
 
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 47efffc..6ed8e4d 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,16 +16,33 @@
 
 package android.widget.cts;
 
-import android.app.Activity;
+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.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;
+
 import android.app.Instrumentation;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.transition.Transition;
 import android.transition.Transition.TransitionListener;
 import android.transition.TransitionValues;
@@ -42,41 +59,31 @@
 import android.widget.PopupWindow;
 import android.widget.PopupWindow.OnDismissListener;
 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;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class PopupWindowTest extends
-        ActivityInstrumentationTestCase2<PopupWindowCtsActivity> {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PopupWindowTest {
     private Instrumentation mInstrumentation;
-    private Activity mActivity;
-    /** The popup window. */
+    private PopupWindowCtsActivity mActivity;
     private PopupWindow mPopupWindow;
+    private TextView mTextView;
 
-    /**
-     * Instantiates a new popup window test.
-     */
-    public PopupWindowTest() {
-        super("android.widget.cts", PopupWindowCtsActivity.class);
+    @Rule
+    public ActivityTestRule<PopupWindowCtsActivity> mActivityRule =
+            new ActivityTestRule<>(PopupWindowCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = (PopupWindowCtsActivity) mActivityRule.getActivity();
     }
 
-    /*
-     * (non-Javadoc)
-     *
-     * @see android.test.ActivityInstrumentationTestCase#setUp()
-     */
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new PopupWindow(mActivity);
 
@@ -84,6 +91,18 @@
 
         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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSize() {
         mPopupWindow = new PopupWindow();
         assertEquals(0, mPopupWindow.getWidth());
         assertEquals(0, mPopupWindow.getHeight());
@@ -134,10 +153,9 @@
         assertTrue(mPopupWindow.isFocusable());
     }
 
+    @Test
     public void testAccessEnterExitTransitions() {
-        PopupWindow w;
-
-        w = new PopupWindow(mActivity, null, 0, 0);
+        PopupWindow w = new PopupWindow(mActivity, null, 0, 0);
         assertNull(w.getEnterTransition());
         assertNull(w.getExitTransition());
 
@@ -181,6 +199,7 @@
         public void captureEndValues(TransitionValues transitionValues) {}
     }
 
+    @Test
     public void testAccessBackground() {
         mPopupWindow = new PopupWindow(mActivity);
 
@@ -192,6 +211,7 @@
         assertNull(mPopupWindow.getBackground());
     }
 
+    @Test
     public void testAccessAnimationStyle() {
         mPopupWindow = new PopupWindow(mActivity);
         // default is -1
@@ -206,28 +226,31 @@
         assertEquals(-100, mPopupWindow.getAnimationStyle());
     }
 
-    public void testAccessContentView() {
+    @Test
+    public void testAccessContentView() throws Throwable {
         mPopupWindow = new PopupWindow(mActivity);
         assertNull(mPopupWindow.getContentView());
 
-        View view = new TextView(mActivity);
-        mPopupWindow.setContentView(view);
-        assertSame(view, mPopupWindow.getContentView());
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        mPopupWindow.setContentView(mTextView);
+        assertSame(mTextView, mPopupWindow.getContentView());
 
         mPopupWindow.setContentView(null);
         assertNull(mPopupWindow.getContentView());
 
         // can not set the content if the old content is shown
-        mPopupWindow.setContentView(view);
+        mPopupWindow.setContentView(mTextView);
         assertFalse(mPopupWindow.isShowing());
         showPopup();
         ImageView img = new ImageView(mActivity);
         assertTrue(mPopupWindow.isShowing());
         mPopupWindow.setContentView(img);
-        assertSame(view, mPopupWindow.getContentView());
+        assertSame(mTextView, mPopupWindow.getContentView());
         dismissPopup();
     }
 
+    @Test
     public void testAccessFocusable() {
         mPopupWindow = new PopupWindow(mActivity);
         assertFalse(mPopupWindow.isFocusable());
@@ -239,6 +262,7 @@
         assertFalse(mPopupWindow.isFocusable());
     }
 
+    @Test
     public void testAccessHeight() {
         mPopupWindow = new PopupWindow(mActivity);
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getHeight());
@@ -273,6 +297,7 @@
         return wm.getDefaultDisplay();
     }
 
+    @Test
     public void testAccessWidth() {
         mPopupWindow = new PopupWindow(mActivity);
         assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getWidth());
@@ -307,7 +332,8 @@
     private static final int LESS_THAN = -1;
     private static final int EQUAL_TO = 0;
 
-    public void testShowAsDropDown() {
+    @Test
+    public void testShowAsDropDown() throws Throwable {
         final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
         popup.setClipToScreenEnabled(false);
         popup.setOverlapAnchor(false);
@@ -315,29 +341,30 @@
         popup.setExitTransition(null);
         popup.setEnterTransition(null);
 
-        assertPosition(popup, R.id.anchor_upper_left,
+        verifyPosition(popup, R.id.anchor_upper_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_upper,
+        verifyPosition(popup, R.id.anchor_upper,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_upper_right,
+        verifyPosition(popup, R.id.anchor_upper_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        assertPosition(popup, R.id.anchor_middle_left,
+        verifyPosition(popup, R.id.anchor_middle_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_middle,
+        verifyPosition(popup, R.id.anchor_middle,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_middle_right,
+        verifyPosition(popup, R.id.anchor_middle_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        assertPosition(popup, R.id.anchor_lower_left,
+        verifyPosition(popup, R.id.anchor_lower_left,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower,
+        verifyPosition(popup, R.id.anchor_lower,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower_right,
+        verifyPosition(popup, R.id.anchor_lower_right,
                 RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
     }
 
-    public void testShowAsDropDown_ClipToScreen() {
+    @Test
+    public void testShowAsDropDown_ClipToScreen() throws Throwable {
         final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
         popup.setClipToScreenEnabled(true);
         popup.setOverlapAnchor(false);
@@ -345,29 +372,30 @@
         popup.setExitTransition(null);
         popup.setEnterTransition(null);
 
-        assertPosition(popup, R.id.anchor_upper_left,
+        verifyPosition(popup, R.id.anchor_upper_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_upper,
+        verifyPosition(popup, R.id.anchor_upper,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_upper_right,
+        verifyPosition(popup, R.id.anchor_upper_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        assertPosition(popup, R.id.anchor_middle_left,
+        verifyPosition(popup, R.id.anchor_middle_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_middle,
+        verifyPosition(popup, R.id.anchor_middle,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_middle_right,
+        verifyPosition(popup, R.id.anchor_middle_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        assertPosition(popup, R.id.anchor_lower_left,
+        verifyPosition(popup, R.id.anchor_lower_left,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower,
+        verifyPosition(popup, R.id.anchor_lower,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower_right,
+        verifyPosition(popup, R.id.anchor_lower_right,
                 RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
     }
 
-    public void testShowAsDropDown_ClipToScreen_Overlap() {
+    @Test
+    public void testShowAsDropDown_ClipToScreen_Overlap() throws Throwable {
         final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
         popup.setClipToScreenEnabled(true);
         popup.setOverlapAnchor(true);
@@ -375,29 +403,30 @@
         popup.setExitTransition(null);
         popup.setEnterTransition(null);
 
-        assertPosition(popup, R.id.anchor_upper_left,
+        verifyPosition(popup, R.id.anchor_upper_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_upper,
+        verifyPosition(popup, R.id.anchor_upper,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_upper_right,
+        verifyPosition(popup, R.id.anchor_upper_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
 
-        assertPosition(popup, R.id.anchor_middle_left,
+        verifyPosition(popup, R.id.anchor_middle_left,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_middle,
+        verifyPosition(popup, R.id.anchor_middle,
                 LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_middle_right,
+        verifyPosition(popup, R.id.anchor_middle_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
 
-        assertPosition(popup, R.id.anchor_lower_left,
+        verifyPosition(popup, R.id.anchor_lower_left,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower,
+        verifyPosition(popup, R.id.anchor_lower,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
-        assertPosition(popup, R.id.anchor_lower_right,
+        verifyPosition(popup, R.id.anchor_lower_right,
                 RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
     }
 
-    public void testShowAsDropDown_ClipToScreen_Overlap_Offset() {
+    @Test
+    public void testShowAsDropDown_ClipToScreen_Overlap_Offset() throws Throwable {
         final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
         popup.setClipToScreenEnabled(true);
         popup.setOverlapAnchor(true);
@@ -409,38 +438,39 @@
         final int offsetY = mActivity.findViewById(R.id.anchor_upper).getHeight() / 2;
         final int gravity = Gravity.TOP | Gravity.START;
 
-        assertPosition(popup, R.id.anchor_upper_left,
+        verifyPosition(popup, R.id.anchor_upper_left,
                 LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_upper,
+        verifyPosition(popup, R.id.anchor_upper,
                 LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_upper_right,
+        verifyPosition(popup, R.id.anchor_upper_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
 
-        assertPosition(popup, R.id.anchor_middle_left,
+        verifyPosition(popup, R.id.anchor_middle_left,
                 LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_middle,
+        verifyPosition(popup, R.id.anchor_middle,
                 LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_middle_right,
+        verifyPosition(popup, R.id.anchor_middle_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
                 offsetX, offsetY, gravity);
 
-        assertPosition(popup, R.id.anchor_lower_left,
+        verifyPosition(popup, R.id.anchor_lower_left,
                 LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_lower,
+        verifyPosition(popup, R.id.anchor_lower,
                 LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
                 offsetX, offsetY, gravity);
-        assertPosition(popup, R.id.anchor_lower_right,
+        verifyPosition(popup, R.id.anchor_lower_right,
                 RIGHT, EQUAL_TO, RIGHT, BOTTOM, LESS_THAN, BOTTOM,
                 offsetX, offsetY, gravity);
     }
 
-    public void testShowAsDropDown_ClipToScreen_TooBig() {
+    @Test
+    public void testShowAsDropDown_ClipToScreen_TooBig() throws Throwable {
         final View rootView = mActivity.findViewById(R.id.anchor_upper_left).getRootView();
         final int width = rootView.getWidth() * 2;
         final int height = rootView.getHeight() * 2;
@@ -455,51 +485,51 @@
         popup.setExitTransition(null);
         popup.setEnterTransition(null);
 
-        assertPosition(popup, R.id.anchor_upper_left,
+        verifyPosition(popup, R.id.anchor_upper_left,
                 LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
-        assertPosition(popup, R.id.anchor_upper,
+        verifyPosition(popup, R.id.anchor_upper,
                 LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
-        assertPosition(popup, R.id.anchor_upper_right,
+        verifyPosition(popup, R.id.anchor_upper_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
 
-        assertPosition(popup, R.id.anchor_middle_left,
+        verifyPosition(popup, R.id.anchor_middle_left,
                 LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
-        assertPosition(popup, R.id.anchor_middle,
+        verifyPosition(popup, R.id.anchor_middle,
                 LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
-        assertPosition(popup, R.id.anchor_middle_right,
+        verifyPosition(popup, R.id.anchor_middle_right,
                 RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
 
-        assertPosition(popup, R.id.anchor_lower_left,
+        verifyPosition(popup, R.id.anchor_lower_left,
                 LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_lower,
+        verifyPosition(popup, R.id.anchor_lower,
                 LEFT, LESS_THAN, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
-        assertPosition(popup, R.id.anchor_lower_right,
+        verifyPosition(popup, R.id.anchor_lower_right,
                 RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, BOTTOM);
     }
 
-    private void assertPosition(PopupWindow popup, int anchorId,
+    private void verifyPosition(PopupWindow popup, int anchorId,
             int contentEdgeX, int operatorX, int anchorEdgeX,
-            int contentEdgeY, int operatorY, int anchorEdgeY) {
-        assertPosition(popup, anchorId,
+            int contentEdgeY, int operatorY, int anchorEdgeY) throws Throwable {
+        verifyPosition(popup, anchorId,
                 contentEdgeX, operatorX, anchorEdgeX,
                 contentEdgeY, operatorY, anchorEdgeY,
                 0, 0, Gravity.TOP | Gravity.START);
     }
 
-    private void assertPosition(PopupWindow popup, int anchorId,
+    private void verifyPosition(PopupWindow popup, int anchorId,
             int contentEdgeX, int operatorX, int anchorEdgeX,
             int contentEdgeY, int operatorY, int anchorEdgeY,
-            int offsetX, int offsetY, int gravity) {
+            int offsetX, int offsetY, int gravity) throws Throwable {
         final View content = popup.getContentView();
         final View anchor = mActivity.findViewById(anchorId);
 
-        getInstrumentation().runOnMainSync(() -> popup.showAsDropDown(
+        mActivityRule.runOnUiThread(() -> popup.showAsDropDown(
                 anchor, offsetX, offsetY, gravity));
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         assertTrue(popup.isShowing());
-        assertPositionX(content, contentEdgeX, operatorX, anchor, anchorEdgeX);
-        assertPositionY(content, contentEdgeY, operatorY, anchor, anchorEdgeY);
+        verifyPositionX(content, contentEdgeX, operatorX, anchor, anchorEdgeX);
+        verifyPositionY(content, contentEdgeY, operatorY, anchor, anchorEdgeY);
 
         // Make sure it fits in the display frame.
         final Rect displayFrame = new Rect();
@@ -509,13 +539,13 @@
         assertTrue("Content (" + contentFrame + ") extends outside display (" + displayFrame + ")",
                 displayFrame.contains(contentFrame));
 
-        getInstrumentation().runOnMainSync(() -> popup.dismiss());
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(popup::dismiss);
+        mInstrumentation.waitForIdleSync();
 
         assertFalse(popup.isShowing());
     }
 
-    public static void assertPositionY(View content, int contentEdge, int flags,
+    private void verifyPositionY(View content, int contentEdge, int flags,
             View anchor, int anchorEdge) {
         final int[] anchorOnScreenXY = new int[2];
         anchor.getLocationOnScreen(anchorOnScreenXY);
@@ -534,7 +564,7 @@
         assertComparison(contentY, flags, anchorY);
     }
 
-    private static void assertPositionX(View content, int contentEdge, int flags,
+    private void verifyPositionX(View content, int contentEdge, int flags,
             View anchor, int anchorEdge) {
         final int[] anchorOnScreenXY = new int[2];
         anchor.getLocationOnScreen(anchorOnScreenXY);
@@ -553,7 +583,7 @@
         assertComparison(contentX, flags, anchorX);
     }
 
-    private static void assertComparison(int left, int operator, int right) {
+    private void assertComparison(int left, int operator, int right) {
         switch (operator) {
             case GREATER_THAN:
                 assertTrue(left + " <= " + right, left > right);
@@ -567,7 +597,8 @@
         }
     }
 
-    public void testShowAtLocation() {
+    @Test
+    public void testShowAtLocation() throws Throwable {
         int[] popupContentViewInWindowXY = new int[2];
         int[] popupContentViewOnScreenXY = new int[2];
         Rect containingRect = new Rect();
@@ -576,6 +607,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;
@@ -585,7 +618,7 @@
         assertEquals(0, popupContentViewInWindowXY[0]);
         assertEquals(0, popupContentViewInWindowXY[1]);
 
-        mInstrumentation.runOnMainSync(
+        mActivityRule.runOnUiThread(
                 () -> mPopupWindow.showAtLocation(upperAnchor, Gravity.NO_GRAVITY, xOff, yOff));
         mInstrumentation.waitForIdleSync();
 
@@ -604,7 +637,8 @@
         dismissPopup();
     }
 
-    public void testShowAsDropDownWithOffsets() {
+    @Test
+    public void testShowAsDropDownWithOffsets() throws Throwable {
         int[] anchorXY = new int[2];
         int[] viewOnScreenXY = new int[2];
         int[] viewInWindowXY = new int[2];
@@ -617,7 +651,7 @@
         final int xOff = 11;
         final int yOff = 12;
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(upperAnchor, xOff, yOff));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.showAsDropDown(upperAnchor, xOff, yOff));
         mInstrumentation.waitForIdleSync();
 
         mPopupWindow.getContentView().getLocationOnScreen(viewOnScreenXY);
@@ -628,7 +662,8 @@
         dismissPopup();
     }
 
-    public void testOverlapAnchor() {
+    @Test
+    public void testOverlapAnchor() throws Throwable {
         int[] anchorXY = new int[2];
         int[] viewOnScreenXY = new int[2];
         int[] viewInWindowXY = new int[2];
@@ -641,7 +676,7 @@
         mPopupWindow.setOverlapAnchor(true);
         assertTrue(mPopupWindow.getOverlapAnchor());
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(upperAnchor, 0, 0));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.showAsDropDown(upperAnchor, 0, 0));
         mInstrumentation.waitForIdleSync();
 
         mPopupWindow.getContentView().getLocationOnScreen(viewOnScreenXY);
@@ -650,6 +685,7 @@
         assertEquals(anchorXY[1] + viewInWindowXY[1], viewOnScreenXY[1]);
     }
 
+    @Test
     public void testAccessWindowLayoutType() {
         mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
@@ -659,47 +695,80 @@
                 mPopupWindow.getWindowLayoutType());
     }
 
+    @Test
     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
+    @Test
     public void testDismiss() {
         mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         assertFalse(mPopupWindow.isShowing());
@@ -713,8 +782,11 @@
         assertFalse(mPopupWindow.isShowing());
     }
 
-    public void testSetOnDismissListener() {
-        mPopupWindow = new PopupWindow(new TextView(mActivity));
+    @Test
+    public void testSetOnDismissListener() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        mPopupWindow = new PopupWindow(mTextView);
         mPopupWindow.setOnDismissListener(null);
 
         OnDismissListener onDismissListener = mock(OnDismissListener.class);
@@ -733,7 +805,8 @@
         verify(onDismissListener, times(2)).onDismiss();
     }
 
-    public void testUpdate() {
+    @Test
+    public void testUpdate() throws Throwable {
         mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         mPopupWindow.setBackgroundDrawable(null);
         showPopup();
@@ -756,7 +829,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());
+        mActivityRule.runOnUiThread(mPopupWindow::update);
         mInstrumentation.waitForIdleSync();
 
         assertEquals(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES,
@@ -772,7 +845,21 @@
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM & p.flags);
     }
 
-    public void testEnterExitTransition() {
+    @Test
+    public void testEnterExitTransitionAsDropDown() throws Throwable {
+        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+        verifyEnterExitTransition(
+                () -> mPopupWindow.showAsDropDown(anchorView, 0, 0));
+    }
+
+    @Test
+    public void testEnterExitTransitionAtLocation() throws Throwable {
+        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+        verifyEnterExitTransition(
+                () -> mPopupWindow.showAtLocation(anchorView, Gravity.BOTTOM, 0, 0));
+    }
+
+    private void verifyEnterExitTransition(Runnable showRunnable) throws Throwable {
         TransitionListener enterListener = mock(TransitionListener.class);
         Transition enterTransition = new BaseTransition();
         enterTransition.addListener(enterListener);
@@ -787,31 +874,28 @@
         mPopupWindow.setEnterTransition(enterTransition);
         mPopupWindow.setExitTransition(exitTransition);
         mPopupWindow.setOnDismissListener(dismissListener);
-        verify(enterListener, never()).onTransitionStart(any(Transition.class));
-        verify(exitListener, never()).onTransitionStart(any(Transition.class));
-        verify(dismissListener, never()).onDismiss();
 
-        final View anchorView = mActivity.findViewById(R.id.anchor_upper);
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(anchorView, 0, 0));
+        mActivityRule.runOnUiThread(showRunnable);
         mInstrumentation.waitForIdleSync();
         verify(enterListener, times(1)).onTransitionStart(any(Transition.class));
         verify(exitListener, never()).onTransitionStart(any(Transition.class));
         verify(dismissListener, never()).onDismiss();
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.dismiss());
+        mActivityRule.runOnUiThread(mPopupWindow::dismiss);
         mInstrumentation.waitForIdleSync();
         verify(enterListener, times(1)).onTransitionStart(any(Transition.class));
         verify(exitListener, times(1)).onTransitionStart(any(Transition.class));
         verify(dismissListener, times(1)).onDismiss();
     }
 
-    public void testUpdatePositionAndDimension() {
+    @Test
+    public void testUpdatePositionAndDimension() throws Throwable {
         int[] fstXY = new int[2];
         int[] sndXY = new int[2];
         int[] viewInWindowXY = new int[2];
         Rect containingRect = new Rect();
 
-        mInstrumentation.runOnMainSync(() -> {
+        mActivityRule.runOnUiThread(() -> {
             mPopupWindow = createPopupWindow(createPopupContent(50, 50));
             // Do not attach within the decor; we will be measuring location
             // with regard to screen coordinates.
@@ -821,6 +905,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,7 +915,15 @@
         containerView.getWindowDisplayFrame(containingRect);
 
         // update if it is not shown
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(20, 50, 50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(80, 80));
+
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mPopupWindow.isShowing());
+        assertEquals(80, mPopupWindow.getWidth());
+        assertEquals(80, mPopupWindow.getHeight());
+
+        // update if it is not shown
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(20, 50, 50, 50));
 
         mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isShowing());
@@ -842,7 +935,7 @@
         assertEquals(containingRect.top + viewInWindowXY[1] + 50, fstXY[1]);
 
         // ignore if width or height is -1
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(4, 0, -1, -1, true));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(4, 0, -1, -1, true));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mPopupWindow.isShowing());
@@ -856,8 +949,9 @@
         dismissPopup();
     }
 
-    public void testUpdateDimensionAndAlignAnchorView() {
-        mInstrumentation.runOnMainSync(
+    @Test
+    public void testUpdateDimensionAndAlignAnchorView() throws Throwable {
+        mActivityRule.runOnUiThread(
                 () -> mPopupWindow = createPopupWindow(createPopupContent(50, 50)));
         mInstrumentation.waitForIdleSync();
 
@@ -868,27 +962,28 @@
         assertEquals(100, mPopupWindow.getWidth());
         assertEquals(100, mPopupWindow.getHeight());
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(anchorView));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.showAsDropDown(anchorView));
         mInstrumentation.waitForIdleSync();
         // update if it is shown
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(anchorView, 50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(anchorView, 50, 50));
         mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isShowing());
         assertEquals(50, mPopupWindow.getWidth());
         assertEquals(50, mPopupWindow.getHeight());
 
         // ignore if width or height is -1
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(anchorView, -1, -1));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(anchorView, -1, -1));
         mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isShowing());
         assertEquals(50, mPopupWindow.getWidth());
         assertEquals(50, mPopupWindow.getHeight());
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.dismiss());
+        mActivityRule.runOnUiThread(mPopupWindow::dismiss);
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testUpdateDimensionAndAlignAnchorViewWithOffsets() {
+    @Test
+    public void testUpdateDimensionAndAlignAnchorViewWithOffsets() throws Throwable {
         int[] anchorXY = new int[2];
         int[] viewInWindowOff = new int[2];
         int[] viewXY = new int[2];
@@ -905,7 +1000,7 @@
         mPopupWindow.getContentView().getLocationInWindow(viewInWindowOff);
 
         // update if it is not shown
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(anchorView, 20, 50, 50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(anchorView, 20, 50, 50, 50));
 
         mInstrumentation.waitForIdleSync();
 
@@ -920,7 +1015,7 @@
         assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
 
         // ignore width and height but change location
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(anchorView, 10, 50, -1, -1));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(anchorView, 10, 50, -1, -1));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mPopupWindow.isShowing());
@@ -934,7 +1029,7 @@
         assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
 
         final View anotherView = mActivity.findViewById(R.id.anchor_middle_left);
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(anotherView, 0, 0, 60, 60));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(anotherView, 0, 0, 60, 60));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mPopupWindow.isShowing());
@@ -952,6 +1047,7 @@
         dismissPopup();
     }
 
+    @Test
     public void testAccessInputMethodMode() {
         mPopupWindow = new PopupWindow(mActivity);
         assertEquals(0, mPopupWindow.getInputMethodMode());
@@ -969,6 +1065,7 @@
         assertEquals(-1, mPopupWindow.getInputMethodMode());
     }
 
+    @Test
     public void testAccessClippingEnabled() {
         mPopupWindow = new PopupWindow(mActivity);
         assertTrue(mPopupWindow.isClippingEnabled());
@@ -977,6 +1074,7 @@
         assertFalse(mPopupWindow.isClippingEnabled());
     }
 
+    @Test
     public void testAccessOutsideTouchable() {
         mPopupWindow = new PopupWindow(mActivity);
         assertFalse(mPopupWindow.isOutsideTouchable());
@@ -985,6 +1083,7 @@
         assertTrue(mPopupWindow.isOutsideTouchable());
     }
 
+    @Test
     public void testAccessTouchable() {
         mPopupWindow = new PopupWindow(mActivity);
         assertTrue(mPopupWindow.isTouchable());
@@ -993,13 +1092,14 @@
         assertFalse(mPopupWindow.isTouchable());
     }
 
-    public void testIsAboveAnchor() {
-        mInstrumentation.runOnMainSync(() -> mPopupWindow = createPopupWindow(createPopupContent(50,
+    @Test
+    public void testIsAboveAnchor() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mPopupWindow = createPopupWindow(createPopupContent(50,
                 50)));
         mInstrumentation.waitForIdleSync();
         final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(upperAnchor));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.showAsDropDown(upperAnchor));
         mInstrumentation.waitForIdleSync();
         assertFalse(mPopupWindow.isAboveAnchor());
         dismissPopup();
@@ -1007,14 +1107,17 @@
         mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         final View lowerAnchor = mActivity.findViewById(R.id.anchor_lower);
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(lowerAnchor, 0, 0));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.showAsDropDown(lowerAnchor, 0, 0));
         mInstrumentation.waitForIdleSync();
         assertTrue(mPopupWindow.isAboveAnchor());
         dismissPopup();
     }
 
-    public void testSetTouchInterceptor() {
-        mPopupWindow = new PopupWindow(new TextView(mActivity));
+    @Test
+    public void testSetTouchInterceptor() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        mPopupWindow = new PopupWindow(mTextView);
 
         OnTouchListener onTouchListener = mock(OnTouchListener.class);
         when(onTouchListener.onTouch(any(View.class), any(MotionEvent.class))).thenReturn(true);
@@ -1037,25 +1140,28 @@
         long eventTime = SystemClock.uptimeMillis();
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         verify(onTouchListener, times(1)).onTouch(any(View.class), any(MotionEvent.class));
 
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
 
         mPopupWindow.setTouchInterceptor(null);
         downTime = SystemClock.uptimeMillis();
         eventTime = SystemClock.uptimeMillis();
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
-        getInstrumentation().sendPointerSync(event);
+        mInstrumentation.sendPointerSync(event);
         verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
     }
 
-    public void testSetWindowLayoutMode() {
-        mPopupWindow = new PopupWindow(new TextView(mActivity));
+    @Test
+    public void testSetWindowLayoutMode() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        mPopupWindow = new PopupWindow(mTextView);
         showPopup();
 
         ViewGroup.LayoutParams p = mPopupWindow.getContentView().getRootView().getLayoutParams();
@@ -1063,12 +1169,136 @@
         assertEquals(0, p.height);
 
         mPopupWindow.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.update(20, 50, 50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.update(20, 50, 50, 50));
 
         assertEquals(LayoutParams.WRAP_CONTENT, p.width);
         assertEquals(LayoutParams.MATCH_PARENT, p.height);
     }
 
+    @Test
+    public void testAccessElevation() throws Throwable {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setElevation(2.0f));
+
+        showPopup();
+        assertEquals(2.0f, mPopupWindow.getElevation(), 0.0f);
+
+        dismissPopup();
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setElevation(4.0f));
+        showPopup();
+        assertEquals(4.0f, mPopupWindow.getElevation(), 0.0f);
+
+        dismissPopup();
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setElevation(10.0f));
+        showPopup();
+        assertEquals(10.0f, mPopupWindow.getElevation(), 0.0f);
+    }
+
+    @Test
+    public void testAccessSoftInputMode() throws Throwable {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mActivityRule.runOnUiThread(
+                () -> mPopupWindow.setSoftInputMode(
+                        WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE));
+
+        showPopup();
+        assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE,
+                mPopupWindow.getSoftInputMode());
+
+        dismissPopup();
+        mActivityRule.runOnUiThread(
+                () -> mPopupWindow.setSoftInputMode(
+                        WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN));
+        showPopup();
+        assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN,
+                mPopupWindow.getSoftInputMode());
+    }
+
+    @Test
+    public void testAccessSplitTouchEnabled() throws Throwable {
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setSplitTouchEnabled(true));
+
+        showPopup();
+        assertTrue(mPopupWindow.isSplitTouchEnabled());
+
+        dismissPopup();
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setSplitTouchEnabled(false));
+        showPopup();
+        assertFalse(mPopupWindow.isSplitTouchEnabled());
+
+        dismissPopup();
+        mActivityRule.runOnUiThread(() -> mPopupWindow.setSplitTouchEnabled(true));
+        showPopup();
+        assertTrue(mPopupWindow.isSplitTouchEnabled());
+    }
+
+    @Test
+    public void testVerticallyClippedBeforeAdjusted() throws Throwable {
+        View parentWindowView = mActivity.getWindow().getDecorView();
+        int parentWidth = parentWindowView.getMeasuredWidth();
+        int parentHeight = parentWindowView.getMeasuredHeight();
+
+        // We make a popup which is too large to fit within the parent window.
+        // After showing it, we verify that it is shrunk to fit the window,
+        // rather than adjusted up.
+        mPopupWindow = createPopupWindow(createPopupContent(parentWidth*2, parentHeight*2));
+        mPopupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
+        mPopupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
+
+        showPopup(R.id.anchor_middle);
+
+        View popupRoot = mPopupWindow.getContentView();
+        int measuredWidth = popupRoot.getMeasuredWidth();
+        int measuredHeight = popupRoot.getMeasuredHeight();
+        View anchor = mActivity.findViewById(R.id.anchor_middle);
+        int[] anchorLocationInWindowXY = new int[2];
+        anchor.getLocationInWindow(anchorLocationInWindowXY);
+
+        assertEquals(measuredHeight, parentHeight - anchorLocationInWindowXY[1]);
+    }
+
+    @Test
+    public void testClipToScreenClipsToInsets() throws Throwable {
+        int[] orientationValues = {ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT};
+        int currentOrientation = mActivity.getResources().getConfiguration().orientation;
+        if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+            orientationValues[0] = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+            orientationValues[1] = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+        }
+
+        for (int i = 0; i < 2; i++) {
+            final int orientation = orientationValues[i];
+            mActivity.runOnUiThread(() ->
+                    mActivity.setRequestedOrientation(orientation));
+            mActivity.waitForConfigurationChanged();
+
+            View parentWindowView = mActivity.getWindow().getDecorView();
+            int parentWidth = parentWindowView.getMeasuredWidth();
+            int parentHeight = parentWindowView.getMeasuredHeight();
+
+            mPopupWindow = createPopupWindow(createPopupContent(parentWidth*2, parentHeight*2));
+            mPopupWindow.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
+            mPopupWindow.setHeight(WindowManager.LayoutParams.MATCH_PARENT);
+            mPopupWindow.setClipToScreenEnabled(true);
+
+            showPopup(R.id.anchor_upper_left);
+
+            View popupRoot = mPopupWindow.getContentView().getRootView();
+            int measuredWidth  = popupRoot.getMeasuredWidth();
+            int measuredHeight = popupRoot.getMeasuredHeight();
+
+            // The visible frame will not include the insets.
+            Rect visibleFrame = new Rect();
+            parentWindowView.getWindowVisibleDisplayFrame(visibleFrame);
+
+            assertEquals(measuredWidth, visibleFrame.width());
+            assertEquals(measuredHeight, visibleFrame.height());
+        }
+    }
+
+
     private static class BaseTransition extends Transition {
         @Override
         public void captureStartValues(TransitionValues transitionValues) {}
@@ -1099,20 +1329,24 @@
         return window;
     }
 
-    private void showPopup() {
-        mInstrumentation.runOnMainSync(() -> {
+    private void showPopup(int resourceId) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
             if (mPopupWindow == null || mPopupWindow.isShowing()) {
                 return;
             }
-            View anchor = mActivity.findViewById(R.id.anchor_upper);
+            View anchor = mActivity.findViewById(resourceId);
             mPopupWindow.showAsDropDown(anchor);
             assertTrue(mPopupWindow.isShowing());
         });
         mInstrumentation.waitForIdleSync();
     }
 
-    private void dismissPopup() {
-        mInstrumentation.runOnMainSync(() -> {
+    private void showPopup() throws Throwable {
+        showPopup(R.id.anchor_upper_left);
+    }
+
+    private void dismissPopup() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
             if (mPopupWindow == null || !mPopupWindow.isShowing()) {
                 return;
             }
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..93e49b6 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -16,429 +16,489 @@
 
 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.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.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+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 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.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AttributeSet;
 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;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ProgressBarTest {
+    private ProgressBarCtsActivity mActivity;
+    private ProgressBar mProgressBar;
+    private ProgressBar mProgressBarHorizontal;
+
+    @Rule
+    public ActivityTestRule<ProgressBarCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ProgressBarCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mProgressBar = (ProgressBar) mActivity.findViewById(R.id.progress);
+        mProgressBarHorizontal = (ProgressBar) mActivity.findViewById(R.id.progress_horizontal);
     }
 
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     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
+    @Test
     public void testPostInvalidate() {
-        MockProgressBar mockProgressBar = new MockProgressBar(mContext);
-        mockProgressBar.postInvalidate();
+        mProgressBarHorizontal.postInvalidate();
     }
 
+    @UiThreadTest
+    @Test
     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
+    @Test
     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
+    @Test
     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());
+
+        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));
     }
 
-    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;
-        }
-
-    }
-
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testOnSizeChange() {
-        // onSizeChanged() is implementation details, do NOT test
-    }
-
+    @UiThreadTest
+    @Test
     public void testVerifyDrawable() {
-        MockProgressBar mockProgressBar = new MockProgressBar(mContext);
+        MockProgressBar mockProgressBar =
+                (MockProgressBar) mActivity.findViewById(R.id.progress_custom);
         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.getDrawable(R.drawable.blue);
+        Drawable d2 = mActivity.getDrawable(R.drawable.red);
+        Drawable d3 = mActivity.getDrawable(R.drawable.yellow);
 
         mockProgressBar.setBackgroundDrawable(d1);
         assertTrue(mockProgressBar.verifyDrawable(null));
@@ -459,89 +519,45 @@
         assertTrue(mockProgressBar.verifyDrawable(d3));
     }
 
-    public void testDrawableStateChanged() {
-        // drawableStateChanged() is implementation details, do NOT test
-    }
-
+    @UiThreadTest
+    @Test
     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 static class MockProgressBar extends ProgressBar {
         public MockProgressBar(Context context) {
             super(context);
         }
 
+        public MockProgressBar(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         @Override
         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/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
index a65bbe9..0bec808 100644
--- a/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
+++ b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
@@ -16,6 +16,9 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -25,21 +28,28 @@
 import android.os.UserHandle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.QuickContactBadge;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public class QuickContactBadgeTest extends InstrumentationTestCase {
-
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class QuickContactBadgeTest {
     @UiThreadTest
+    @Test
     public void testPrioritizedMimetype() throws InterruptedException {
         final String plainMimeType = "text/plain";
         final Uri nonExistentContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 0);
         final CountDownLatch latch = new CountDownLatch(1);
-        final Context context = new ContextWrapper(getInstrumentation().getContext()) {
+        final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
             @Override
             public void startActivity(Intent intent) {
                 testCallback(intent);
diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
new file mode 100644
index 0000000..442d5f7
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.RadioButton;
+
+/**
+ * A minimal application for {@link RadioButton} test.
+ */
+public class RadioButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..2daa6ea 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
@@ -16,67 +16,188 @@
 
 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 android.content.Context;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 import android.widget.RadioButton;
 
-/**
- * Test {@link RadioButton}.
- */
-public class RadioButtonTest extends InstrumentationTestCase {
-    private Context mContext;
+import com.android.compatibility.common.util.CtsTouchUtils;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RadioButtonTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private RadioButton mRadioButton;
+
+    @Rule
+    public ActivityTestRule<RadioButtonCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RadioButtonCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mRadioButton = (RadioButton) mActivity.findViewById(R.id.radio_button);
     }
 
+    @Test
     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) {
-        }
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new RadioButton(null);
+    }
 
-        new RadioButton(mContext, attrs);
-        try {
-            new RadioButton(null, attrs);
-            fail("The constructor should throw NullPointerException when param Context is null.");
-        } catch (NullPointerException e) {
-        }
-        new RadioButton(mContext, null);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new RadioButton(null, null);
+    }
 
-        new RadioButton(mContext, attrs, 0);
-        try {
-            new RadioButton(null, attrs, 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);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new RadioButton(null, null, 0);
     }
 
     @UiThreadTest
-    public void testToggle() {
-        RadioButton button = new RadioButton(mContext);
-        assertFalse(button.isChecked());
+    @Test
+    public void testText() {
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.hello_world), mRadioButton.getText()));
 
-        button.toggle();
-        assertTrue(button.isChecked());
+        mRadioButton.setText("new text");
+        assertTrue(TextUtils.equals("new text", mRadioButton.getText()));
 
-        // Can't be toggled if it is checked
-        button.toggle();
-        assertTrue(button.isChecked());
+        mRadioButton.setText(R.string.text_name);
+        assertTrue(TextUtils.equals(
+                mActivity.getString(R.string.text_name), mRadioButton.getText()));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessChecked() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // not checked -> not checked
+        mRadioButton.setChecked(false);
+        verifyZeroInteractions(mockCheckedChangeListener);
+        assertFalse(mRadioButton.isChecked());
+
+        // not checked -> checked
+        mRadioButton.setChecked(true);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // checked -> checked
+        mRadioButton.setChecked(true);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+        assertTrue(mRadioButton.isChecked());
+
+        // checked -> not checked
+        mRadioButton.setChecked(false);
+        verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, false);
+        assertFalse(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testToggleViaApi() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // toggle to checked
+        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
+        mRadioButton.toggle();
+        assertTrue(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
+    }
+
+    @Test
+    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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testToggleViaPerformClick() {
+        final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+                mock(RadioButton.OnCheckedChangeListener.class);
+        mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+        verifyZeroInteractions(mockCheckedChangeListener);
+
+        assertFalse(mRadioButton.isChecked());
+
+        // click to checked
+        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
+        mRadioButton.performClick();
+        assertTrue(mRadioButton.isChecked());
+
+        verifyNoMoreInteractions(mockCheckedChangeListener);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroupCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RadioGroupCtsActivity.java
new file mode 100755
index 0000000..26f8703
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroupCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.RadioGroup;
+
+/**
+ * A minimal application for {@link RadioGroup} test.
+ */
+public class RadioGroupCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.radiogroup_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
index b2154e2..869102b 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroupTest.java
@@ -16,15 +16,19 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
+import android.app.Activity;
 import android.content.Context;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
@@ -34,9 +38,16 @@
 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 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;
 import java.util.Vector;
@@ -44,64 +55,62 @@
 /**
  * Test {@link RadioGroup}.
  */
-public class RadioGroupTest extends InstrumentationTestCase {
-    private static final int BUTTON_ID_0 = 0;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RadioGroupTest {
+    private Activity mActivity;
+    private RadioGroup mRadioGroup;
 
-    private static final int BUTTON_ID_1 = 1;
+    @Rule
+    public ActivityTestRule<RadioGroupCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RadioGroupCtsActivity.class);
 
-    private static final int BUTTON_ID_2 = 2;
-
-    private static final int BUTTON_ID_3 = 3;
-
-    /** the IDs of the buttons inside the group are 0, 1, 2, 3. */
-    private RadioGroup mDefaultRadioGroup;
-
-    private Context mContext;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
-        // the IDs of the buttons inside the group are 0, 1, 2, 3
-        mDefaultRadioGroup = createDefaultRadioGroup();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mRadioGroup = (RadioGroup) mActivity.findViewById(R.id.radio_group);
     }
 
+    @Test
     public void testConstructors() {
-        new RadioGroup(mContext);
+        new RadioGroup(mActivity);
 
         AttributeSet attrs = getAttributeSet(R.layout.radiogroup_1);
-        new RadioGroup(mContext, attrs);
-        new RadioGroup(mContext, null);
+        new RadioGroup(mActivity, attrs);
+        new RadioGroup(mActivity, null);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetOnHierarchyChangeListener() {
         MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        mDefaultRadioGroup.setOnHierarchyChangeListener(listener);
+        mRadioGroup.setOnHierarchyChangeListener(listener);
 
-        View button3 = mDefaultRadioGroup.findViewById(BUTTON_ID_3);
+        View button3 = mRadioGroup.findViewById(R.id.radio_button_3);
         listener.reset();
-        mDefaultRadioGroup.removeView(button3);
-        assertSame(mDefaultRadioGroup, listener.getOnChildViewRemovedParentParam());
+        mRadioGroup.removeView(button3);
+        assertSame(mRadioGroup, listener.getOnChildViewRemovedParentParam());
         assertSame(button3, listener.getOnChildViewRemovedChildParam());
 
         listener.reset();
-        mDefaultRadioGroup.addView(button3);
-        assertSame(mDefaultRadioGroup, listener.getOnChildViewAddedParentParam());
+        mRadioGroup.addView(button3);
+        assertSame(mRadioGroup, listener.getOnChildViewAddedParentParam());
         assertSame(button3, listener.getOnChildViewAddedChildParam());
 
         // Set listener to null
-        mDefaultRadioGroup.setOnHierarchyChangeListener(null);
+        mRadioGroup.setOnHierarchyChangeListener(null);
         // and no exceptions thrown in the following method calls
-        mDefaultRadioGroup.removeView(button3);
-        mDefaultRadioGroup.addView(button3);
+        mRadioGroup.removeView(button3);
+        mRadioGroup.addView(button3);
     }
 
+    @UiThreadTest
+    @Test
     public void testInternalPassThroughHierarchyChangeListener() {
-        mDefaultRadioGroup = new RadioGroup(mContext);
-        RadioButton newButton = new RadioButton(mContext);
+        RadioButton newButton = new RadioButton(mActivity);
 
         assertEquals(View.NO_ID, newButton.getId());
-        mDefaultRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
+        mRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
                 RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT));
         // aapt-generated IDs have a nonzero high byte; check that the ID generated by
         // RadioGroup falls within a range that will not collide with aapt IDs.
@@ -109,15 +118,15 @@
     }
 
     @UiThreadTest
+    @Test
     public void testInternalCheckedStateTracker() {
-        mDefaultRadioGroup = new RadioGroup(mContext);
-        RadioButton newButton = new RadioButton(mContext);
+        RadioButton newButton = new RadioButton(mActivity);
         // inject the tracker to the button when the button is added by
         // CompoundButton#setOnCheckedChangeWidgetListener(OnCheckedChangeListener)
-        mDefaultRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
+        mRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
                 RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT));
         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        mDefaultRadioGroup.setOnCheckedChangeListener(listener);
+        mRadioGroup.setOnCheckedChangeListener(listener);
 
         listener.reset();
         newButton.setChecked(true);
@@ -130,7 +139,7 @@
         assertHasCalledOnCheckedChanged(listener);
 
         // remove the tracker from the button when the button is removed
-        mDefaultRadioGroup.removeView(newButton);
+        mRadioGroup.removeView(newButton);
         listener.reset();
         newButton.setChecked(true);
         assertHaveNotCalledOnCheckedChanged(listener);
@@ -141,152 +150,156 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCheckedRadioButtonId() {
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
 
-        mDefaultRadioGroup.check(BUTTON_ID_0);
-        assertEquals(BUTTON_ID_0, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(R.id.radio_button_0);
+        assertEquals(R.id.radio_button_0, mRadioGroup.getCheckedRadioButtonId());
 
-        mDefaultRadioGroup.check(BUTTON_ID_3);
-        assertEquals(BUTTON_ID_3, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(R.id.radio_button_3);
+        assertEquals(R.id.radio_button_3, mRadioGroup.getCheckedRadioButtonId());
 
         // None of the buttons inside the group has of of the following IDs
-        mDefaultRadioGroup.check(4);
-        assertEquals(4, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(4);
+        assertEquals(4, mRadioGroup.getCheckedRadioButtonId());
 
-        mDefaultRadioGroup.check(-1);
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(-1);
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
 
-        mDefaultRadioGroup.check(-3);
-        assertEquals(-3, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(-3);
+        assertEquals(-3, mRadioGroup.getCheckedRadioButtonId());
     }
 
     @UiThreadTest
+    @Test
     public void testClearCheck() {
         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        mDefaultRadioGroup.setOnCheckedChangeListener(listener);
+        mRadioGroup.setOnCheckedChangeListener(listener);
 
-        mDefaultRadioGroup.check(BUTTON_ID_3);
-        assertEquals(BUTTON_ID_3, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(R.id.radio_button_3);
+        assertEquals(R.id.radio_button_3, mRadioGroup.getCheckedRadioButtonId());
 
         listener.reset();
-        mDefaultRadioGroup.clearCheck();
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.clearCheck();
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
         assertHasCalledOnCheckedChanged(listener);
         // uncheck the original button
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, BUTTON_ID_3);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_3);
 
         // None of the buttons inside the group has of of the following IDs
-        mDefaultRadioGroup.check(4);
-        assertEquals(4, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(4);
+        assertEquals(4, mRadioGroup.getCheckedRadioButtonId());
 
         listener.reset();
-        mDefaultRadioGroup.clearCheck();
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.clearCheck();
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
         // why the method is called while none of the button is checked or unchecked?
         assertHasCalledOnCheckedChanged(listener);
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, -1);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
 
-        mDefaultRadioGroup.check(-1);
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.check(-1);
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
 
         listener.reset();
-        mDefaultRadioGroup.clearCheck();
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.clearCheck();
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
         // why the method is called while none of the button is checked or unchecked?
         assertHasCalledOnCheckedChanged(listener);
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, -1);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
     }
 
     @UiThreadTest
+    @Test
     public void testCheck() {
         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        mDefaultRadioGroup.setOnCheckedChangeListener(listener);
-        assertEquals(-1, mDefaultRadioGroup.getCheckedRadioButtonId());
+        mRadioGroup.setOnCheckedChangeListener(listener);
+        assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
 
         listener.reset();
-        mDefaultRadioGroup.check(BUTTON_ID_0);
+        mRadioGroup.check(R.id.radio_button_0);
         assertHasCalledOnCheckedChanged(listener);
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, BUTTON_ID_0);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_0);
 
         listener.reset();
-        mDefaultRadioGroup.check(BUTTON_ID_1);
+        mRadioGroup.check(R.id.radio_button_1);
         assertHasCalledOnCheckedChanged(listener);
         // uncheck the original button
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, BUTTON_ID_0);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_0);
         // check the new button
-        assertOnCheckedChangedParams(listener, 1, mDefaultRadioGroup, BUTTON_ID_1);
+        assertOnCheckedChangedParams(listener, 1, mRadioGroup, R.id.radio_button_1);
 
         listener.reset();
-        mDefaultRadioGroup.check(-1);
+        mRadioGroup.check(-1);
         assertHasCalledOnCheckedChanged(listener);
         // uncheck the original button
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, BUTTON_ID_1);
-        assertOnCheckedChangedParams(listener, 1, mDefaultRadioGroup, -1);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_1);
+        assertOnCheckedChangedParams(listener, 1, mRadioGroup, -1);
 
         // None of the buttons inside the group has of of the following IDs
         listener.reset();
-        mDefaultRadioGroup.check(-1);
+        mRadioGroup.check(-1);
         // why the method is called while none of the inside buttons has been changed
         assertHasCalledOnCheckedChanged(listener);
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, -1);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
 
         listener.reset();
-        mDefaultRadioGroup.check(4);
+        mRadioGroup.check(4);
         // why the method is called while none of the inside buttons has been changed
         assertHasCalledOnCheckedChanged(listener);
-        assertOnCheckedChangedParams(listener, 0, mDefaultRadioGroup, 4);
+        assertOnCheckedChangedParams(listener, 0, mRadioGroup, 4);
 
         // Set listener to null
-        mDefaultRadioGroup.setOnCheckedChangeListener(null);
+        mRadioGroup.setOnCheckedChangeListener(null);
         // no exceptions thrown during the following method
-        mDefaultRadioGroup.check(0);
+        mRadioGroup.check(0);
     }
 
     @UiThreadTest
+    @Test
     public void testSetOnCheckedChangeListener() {
         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
-        mDefaultRadioGroup.setOnCheckedChangeListener(listener);
+        mRadioGroup.setOnCheckedChangeListener(listener);
 
         listener.reset();
-        mDefaultRadioGroup.check(BUTTON_ID_0);
+        mRadioGroup.check(R.id.radio_button_0);
         assertHasCalledOnCheckedChanged(listener);
 
         // does not call the method if the button the id is already checked
         listener.reset();
-        mDefaultRadioGroup.check(BUTTON_ID_0);
+        mRadioGroup.check(R.id.radio_button_0);
         assertHaveNotCalledOnCheckedChanged(listener);
 
         // call the method if none of the buttons inside the group has the id
         listener.reset();
-        mDefaultRadioGroup.check(-3);
+        mRadioGroup.check(-3);
         assertHasCalledOnCheckedChanged(listener);
 
         // does not call the method if the button the id is already checked
         // and none of the buttons inside the group has the id
         listener.reset();
-        mDefaultRadioGroup.check(-3);
+        mRadioGroup.check(-3);
         assertHaveNotCalledOnCheckedChanged(listener);
 
         // always call the method if the checked id is -1
         listener.reset();
-        mDefaultRadioGroup.clearCheck();
+        mRadioGroup.clearCheck();
         assertHasCalledOnCheckedChanged(listener);
 
         listener.reset();
-        mDefaultRadioGroup.check(-1);
+        mRadioGroup.check(-1);
         assertHasCalledOnCheckedChanged(listener);
 
         // Set listener to null
-        mDefaultRadioGroup.setOnCheckedChangeListener(null);
+        mRadioGroup.setOnCheckedChangeListener(null);
         // no exceptions thrown during the following method
-        mDefaultRadioGroup.check(0);
+        mRadioGroup.check(0);
     }
 
+    @Test
     public void testGenerateLayoutParams() {
-        mDefaultRadioGroup = new RadioGroup(mContext);
         RadioGroup.LayoutParams layoutParams =
-            mDefaultRadioGroup.generateLayoutParams((AttributeSet) null);
+            mRadioGroup.generateLayoutParams((AttributeSet) null);
         assertNotNull(layoutParams);
         // default values
         assertEquals(0.0, layoutParams.weight, 0);
@@ -299,7 +312,7 @@
         assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.height);
 
         AttributeSet attrs = getAttributeSet(R.layout.radiogroup_1);
-        layoutParams = mDefaultRadioGroup.generateLayoutParams(attrs);
+        layoutParams = mRadioGroup.generateLayoutParams(attrs);
         // values from layout
         assertNotNull(layoutParams);
         assertEquals(0.5, layoutParams.weight, 0);
@@ -312,8 +325,9 @@
         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.height);
     }
 
+    @Test
     public void testCheckLayoutParams() {
-        MockRadioGroup mRadioGroupWrapper = new MockRadioGroup(mContext);
+        MockRadioGroup mRadioGroupWrapper = new MockRadioGroup(mActivity);
 
         assertFalse(mRadioGroupWrapper.checkLayoutParams(null));
 
@@ -330,8 +344,9 @@
         assertTrue(mRadioGroupWrapper.checkLayoutParams(radioParams));
     }
 
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        MockRadioGroup radioGroupWrapper = new MockRadioGroup(mContext);
+        MockRadioGroup radioGroupWrapper = new MockRadioGroup(mActivity);
         LinearLayout.LayoutParams p = radioGroupWrapper.generateDefaultLayoutParams();
 
         assertTrue(p instanceof RadioGroup.LayoutParams);
@@ -340,13 +355,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnFinishInflate() {
-        MockRadioGroup radioGroup = new MockRadioGroup(mContext);
+        MockRadioGroup radioGroup = new MockRadioGroup(mActivity);
         int checkId = 100;
         radioGroup.check(checkId);
         // the button is added after the check(int)method
         // and it not checked though it has exactly the checkId
-        RadioButton button = new RadioButton(mContext);
+        RadioButton button = new RadioButton(mActivity);
         button.setId(checkId);
         radioGroup.addView(button, new LinearLayout.LayoutParams(
                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
@@ -361,8 +377,8 @@
         assertHasCalledOnCheckedChanged(listener);
         assertEquals(checkId, radioGroup.getCheckedRadioButtonId());
 
-        radioGroup = new MockRadioGroup(mContext);
-        button = new RadioButton(mContext);
+        radioGroup = new MockRadioGroup(mActivity);
+        button = new RadioButton(mActivity);
         radioGroup.addView(button, new LinearLayout.LayoutParams(
                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
         listener = new MockOnCheckedChangeListener();
@@ -379,55 +395,24 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAddView() {
-        mDefaultRadioGroup.check(BUTTON_ID_0);
-        assertEquals(BUTTON_ID_0, mDefaultRadioGroup.getCheckedRadioButtonId());
-        assertEquals(4, mDefaultRadioGroup.getChildCount());
+        mRadioGroup.check(R.id.radio_button_0);
+        assertEquals(R.id.radio_button_0, mRadioGroup.getCheckedRadioButtonId());
+        assertEquals(4, mRadioGroup.getChildCount());
 
-        int id = BUTTON_ID_3 + 10;
-        RadioButton choice4 = new RadioButton(mContext);
+        int id = R.id.radio_button_3 + 10;
+        RadioButton choice4 = new RadioButton(mActivity);
         choice4.setText("choice4");
         choice4.setId(id);
         choice4.setChecked(true);
-        mDefaultRadioGroup.addView(choice4, 4, new ViewGroup.LayoutParams(100, 200));
-        assertEquals(id, mDefaultRadioGroup.getCheckedRadioButtonId());
-        assertEquals(5, mDefaultRadioGroup.getChildCount());
-    }
-
-    /**
-     * Initialises the group with 4 RadioButtons which IDs are
-     * BUTTON_ID_0, BUTTON_ID_1, BUTTON_ID_2, BUTTON_ID_3.
-     */
-    private RadioGroup createDefaultRadioGroup() {
-        RadioGroup radioGroup = new RadioGroup(mContext);
-        RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(
-                RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT);
-
-        RadioButton choice0 = new RadioButton(mContext);
-        choice0.setText("choice0");
-        choice0.setId(BUTTON_ID_0);
-        radioGroup.addView(choice0, params);
-
-        RadioButton choice1 = new RadioButton(mContext);
-        choice1.setText("choice1");
-        choice1.setId(BUTTON_ID_1);
-        radioGroup.addView(choice1, params);
-
-        RadioButton choice2 = new RadioButton(mContext);
-        choice2.setText("choice2");
-        choice2.setId(BUTTON_ID_2);
-        radioGroup.addView(choice2, params);
-
-        RadioButton choice3 = new RadioButton(mContext);
-        choice3.setText("choice3");
-        choice3.setId(BUTTON_ID_3);
-        radioGroup.addView(choice3, params);
-
-        return radioGroup;
+        mRadioGroup.addView(choice4, 4, new ViewGroup.LayoutParams(100, 200));
+        assertEquals(id, mRadioGroup.getCheckedRadioButtonId());
+        assertEquals(5, mRadioGroup.getChildCount());
     }
 
     private AttributeSet getAttributeSet(int resId) {
-        XmlPullParser parser = mContext.getResources().getLayout(resId);
+        XmlPullParser parser = mActivity.getResources().getLayout(resId);
         assertNotNull(parser);
         int type = 0;
         try {
@@ -531,7 +516,7 @@
         }
     }
 
-    private class MockRadioGroup extends RadioGroup {
+    public static class MockRadioGroup extends RadioGroup {
         public MockRadioGroup(Context context) {
             super(context);
         }
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..d7aecfd 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioGroup_LayoutParamsTest.java
@@ -16,82 +16,82 @@
 
 package android.widget.cts;
 
-import android.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.Gravity;
 import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.RadioGroup;
-import android.widget.RadioGroup.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;
 
 /**
- * Test {@link LayoutParams}.
+ * Test {@link RadioGroup.LayoutParams}.
  */
-public class RadioGroup_LayoutParamsTest extends AndroidTestCase {
-    private LayoutParams mLayoutParams;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RadioGroup_LayoutParamsTest {
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mLayoutParams = null;
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
     public void testConstructor() {
-        mLayoutParams = new RadioGroup.LayoutParams(Integer.MIN_VALUE, Integer.MAX_VALUE);
+        RadioGroup.LayoutParams mLayoutParams =
+                new RadioGroup.LayoutParams(Integer.MIN_VALUE, Integer.MAX_VALUE);
         assertEquals(Integer.MIN_VALUE, mLayoutParams.width);
         assertEquals(Integer.MAX_VALUE, mLayoutParams.height);
-        assertEquals(0.0f, mLayoutParams.weight);
+        assertEquals(0.0f, mLayoutParams.weight, 0.0f);
 
         mLayoutParams = new RadioGroup.LayoutParams(Integer.MAX_VALUE, Integer.MIN_VALUE);
         assertEquals(Integer.MAX_VALUE, mLayoutParams.width);
         assertEquals(Integer.MIN_VALUE, mLayoutParams.height);
-        assertEquals(0.0f, mLayoutParams.weight);
+        assertEquals(0.0f, mLayoutParams.weight, 0.0f);
 
         mLayoutParams = new RadioGroup.LayoutParams(Integer.MIN_VALUE, Integer.MAX_VALUE,
                 Float.MAX_VALUE);
         assertEquals(Integer.MIN_VALUE, mLayoutParams.width);
         assertEquals(Integer.MAX_VALUE, mLayoutParams.height);
-        assertEquals(Float.MAX_VALUE, mLayoutParams.weight);
+        assertEquals(Float.MAX_VALUE, mLayoutParams.weight, 0.0f);
 
         mLayoutParams = new RadioGroup.LayoutParams(Integer.MIN_VALUE, Integer.MAX_VALUE,
                 Float.MIN_VALUE);
         assertEquals(Integer.MIN_VALUE, mLayoutParams.width);
         assertEquals(Integer.MAX_VALUE, mLayoutParams.height);
-        assertEquals(Float.MIN_VALUE, mLayoutParams.weight);
+        assertEquals(Float.MIN_VALUE, mLayoutParams.weight, 0.0f);
 
         mLayoutParams = new RadioGroup.LayoutParams(new ViewGroup.LayoutParams(40, 60));
         assertEquals(40, mLayoutParams.width);
         assertEquals(60, mLayoutParams.height);
-        assertEquals(0.0f, mLayoutParams.weight);
+        assertEquals(0.0f, mLayoutParams.weight, 0.0f);
 
-        try {
-            new RadioGroup.LayoutParams((ViewGroup.LayoutParams) null);
-            fail("The constructor should throw NullPointerException when param "
-                    + "ViewGroup.LayoutParams is null.");
-        } catch (NullPointerException e) {
-        }
-
-        mLayoutParams = new RadioGroup.LayoutParams(new MarginLayoutParams(100, 200));
+        mLayoutParams = new RadioGroup.LayoutParams(new ViewGroup.MarginLayoutParams(100, 200));
         assertEquals(100, mLayoutParams.width);
         assertEquals(200, mLayoutParams.height);
-        assertEquals(0.0f, mLayoutParams.weight);
+        assertEquals(0.0f, mLayoutParams.weight, 0.0f);
         assertEquals(0, mLayoutParams.leftMargin);
         assertEquals(0, mLayoutParams.topMargin);
         assertEquals(0, mLayoutParams.rightMargin);
         assertEquals(0, mLayoutParams.bottomMargin);
 
-        MarginLayoutParams source = new MarginLayoutParams(10, 20);
+        ViewGroup.MarginLayoutParams source = new ViewGroup.MarginLayoutParams(10, 20);
         source.leftMargin = 1;
         source.topMargin = 2;
         source.rightMargin = 3;
@@ -100,57 +100,60 @@
         mLayoutParams = new RadioGroup.LayoutParams(source);
         assertEquals(10, mLayoutParams.width);
         assertEquals(20, mLayoutParams.height);
-        assertEquals(0.0f, mLayoutParams.weight);
+        assertEquals(0.0f, mLayoutParams.weight, 0.0f);
         assertEquals(1, mLayoutParams.leftMargin);
         assertEquals(2, mLayoutParams.topMargin);
         assertEquals(3, mLayoutParams.rightMargin);
         assertEquals(4, mLayoutParams.bottomMargin);
 
-        try {
-            new RadioGroup.LayoutParams((MarginLayoutParams) null);
-            fail("The constructor should throw NullPointerException when param "
-                    + "MarginLayoutParams is null.");
-        } catch (NullPointerException e) {
-        }
-
-        mLayoutParams = new LayoutParams(getContext(),
-                getAttributeSet(android.widget.cts.R.layout.radiogroup_1));
+        mLayoutParams = new RadioGroup.LayoutParams(mContext,
+                getAttributeSet(R.layout.radiogroup_1));
         assertNotNull(mLayoutParams);
-        assertEquals(0.5, mLayoutParams.weight, 0);
+        assertEquals(0.5, mLayoutParams.weight, 0.0f);
         assertEquals(Gravity.BOTTOM, mLayoutParams.gravity);
         assertEquals(5, mLayoutParams.leftMargin);
         assertEquals(5, mLayoutParams.topMargin);
         assertEquals(5, mLayoutParams.rightMargin);
         assertEquals(5, mLayoutParams.bottomMargin);
-        assertEquals(LayoutParams.MATCH_PARENT, mLayoutParams.width);
-        assertEquals(LayoutParams.MATCH_PARENT, mLayoutParams.height);
+        assertEquals(RadioGroup.LayoutParams.MATCH_PARENT, mLayoutParams.width);
+        assertEquals(RadioGroup.LayoutParams.MATCH_PARENT, mLayoutParams.height);
 
-        mLayoutParams = new RadioGroup.LayoutParams(getContext(), null);
+        mLayoutParams = new RadioGroup.LayoutParams(mContext, null);
         assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, mLayoutParams.width);
         assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, mLayoutParams.height);
-
-        try {
-            new RadioGroup.LayoutParams(null,
-                    getAttributeSet(android.widget.cts.R.layout.radiogroup_1));
-            fail("The constructor should throw NullPointerException when param Context is null.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullViewGroupLayoutParams() {
+        new RadioGroup.LayoutParams((ViewGroup.LayoutParams) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullMarginLayoutParams() {
+        new RadioGroup.LayoutParams((ViewGroup.MarginLayoutParams) null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new RadioGroup.LayoutParams(null, getAttributeSet(R.layout.radiogroup_1));
+    }
+
+    @Test
     public void testSetBaseAttributes() {
-        MockLayoutParams layoutParams = new MockLayoutParams(getContext(), null);
+        MockLayoutParams layoutParams = new MockLayoutParams(mContext, null);
         // default values
-        assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.width);
-        assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.height);
+        assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, layoutParams.width);
+        assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, layoutParams.height);
 
         AttributeSet attrs = getAttributeSet(android.widget.cts.R.layout.radiogroup_1);
-        TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
+        TypedArray a = mContext.obtainStyledAttributes(attrs,
+                android.R.styleable.ViewGroup_MarginLayout);
         layoutParams.setBaseAttributes(a,
-                R.styleable.ViewGroup_MarginLayout_layout_width,
-                R.styleable.ViewGroup_MarginLayout_layout_height);
+                android.R.styleable.ViewGroup_MarginLayout_layout_width,
+                android.R.styleable.ViewGroup_MarginLayout_layout_height);
         // check the attributes from the layout file
-        assertEquals(LayoutParams.MATCH_PARENT, layoutParams.width);
-        assertEquals(LayoutParams.MATCH_PARENT, layoutParams.height);
+        assertEquals(RadioGroup.LayoutParams.MATCH_PARENT, layoutParams.width);
+        assertEquals(RadioGroup.LayoutParams.MATCH_PARENT, layoutParams.height);
     }
 
     private AttributeSet getAttributeSet(int resId) {
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..0725c10 100644
--- a/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RatingBarTest.java
@@ -16,235 +16,183 @@
 
 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 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.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.RatingBar;
-import android.widget.RatingBar.OnRatingBarChangeListener;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link RatingBar}.
  */
-public class RatingBarTest extends ActivityInstrumentationTestCase2<RatingBarCtsActivity> {
-    private Context mContext;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RatingBarTest {
     private RatingBarCtsActivity mActivity;
+    private RatingBar mRatingBar;
 
-    public RatingBarTest() {
-        super("android.widget.cts", RatingBarCtsActivity.class);
+    @Rule
+    public ActivityTestRule<RatingBarCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RatingBarCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mRatingBar = (RatingBar) mActivity.findViewById(R.id.ratingbar_constructor);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        assertNotNull(mActivity);
-        mContext = getInstrumentation().getContext();
-    }
-
+    @Test
     public void testConstructor() {
-        new RatingBar(mContext, null, android.R.attr.ratingBarStyle);
+        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);
+    }
 
-        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());
+    @Test
+    public void testAttributesFromLayout() {
+        assertFalse(mRatingBar.isIndicator());
+        assertEquals(50, mRatingBar.getNumStars());
+        assertEquals(1.2f, mRatingBar.getRating(), 0.0f);
+        assertEquals(0.2f, mRatingBar.getStepSize(), 0.0f);
     }
 
     @UiThreadTest
+    @Test
     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());
+        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);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessIndicator() {
-        RatingBar ratingBar = new RatingBar(mContext);
+        mRatingBar.setIsIndicator(true);
+        assertTrue(mRatingBar.isIndicator());
 
-        ratingBar.setIsIndicator(true);
-        assertTrue(ratingBar.isIndicator());
-
-        ratingBar.setIsIndicator(false);
-        assertFalse(ratingBar.isIndicator());
+        mRatingBar.setIsIndicator(false);
+        assertFalse(mRatingBar.isIndicator());
     }
 
+    @UiThreadTest
+    @Test
     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());
+        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
+        mRatingBar.setNumStars(-10);
+        assertEquals(20, mRatingBar.getNumStars());
 
-        mockRatingBar.reset();
-        mockRatingBar.setNumStars(Integer.MAX_VALUE);
-        assertTrue(mockRatingBar.hasCalledRequestLayout());
-        assertEquals(Integer.MAX_VALUE, mockRatingBar.getNumStars());
+        mRatingBar.setNumStars(Integer.MAX_VALUE);
+        assertEquals(Integer.MAX_VALUE, mRatingBar.getNumStars());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessRating() {
-        RatingBar ratingBar = new RatingBar(mContext);
-
-        // set Rating
         // normal value
-        ratingBar.setRating(2.0f);
-        assertEquals(2.0f, ratingBar.getRating());
+        mRatingBar.setRating(2.0f);
+        assertEquals(2.0f, mRatingBar.getRating(), 0.0f);
 
         // exceptional value
-        ratingBar.setRating(-2.0f);
-        assertEquals(0f, ratingBar.getRating());
+        mRatingBar.setRating(-2.0f);
+        assertEquals(0f, mRatingBar.getRating(), 0.0f);
 
-        ratingBar.setRating(Float.MAX_VALUE);
-        assertEquals((float) ratingBar.getNumStars(), ratingBar.getRating());
+        mRatingBar.setRating(Float.MAX_VALUE);
+        assertEquals((float) mRatingBar.getNumStars(), mRatingBar.getRating(), 0.0f);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetMax() {
-        RatingBar ratingBar = new RatingBar(mContext);
-
         // normal value
-        ratingBar.setMax(10);
-        assertEquals(10, ratingBar.getMax());
+        mRatingBar.setMax(10);
+        assertEquals(10, mRatingBar.getMax());
 
-        ratingBar.setProgress(10);
+        mRatingBar.setProgress(10);
 
         // exceptional values
-        ratingBar.setMax(-10);
-        assertEquals(10, ratingBar.getMax());
-        assertEquals(10, ratingBar.getProgress());
+        mRatingBar.setMax(-10);
+        assertEquals(10, mRatingBar.getMax());
+        assertEquals(10, mRatingBar.getProgress());
 
-        ratingBar.setMax(Integer.MAX_VALUE);
-        assertEquals(Integer.MAX_VALUE, ratingBar.getMax());
+        mRatingBar.setMax(Integer.MAX_VALUE);
+        assertEquals(Integer.MAX_VALUE, mRatingBar.getMax());
     }
 
+    @UiThreadTest
+    @Test
     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());
+        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(), 0.0f);
 
-        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());
+        mRatingBar.setStepSize(-1.5f);
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize(), 0.0f);
 
-        ratingBar.setStepSize(0f);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
+        mRatingBar.setStepSize(0f);
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize(), 0.0f);
 
-        ratingBar.setStepSize(ratingBar.getNumStars() + 0.1f);
-        assertEquals(currentMax, ratingBar.getMax());
-        assertEquals(currentProgress, ratingBar.getProgress());
-        assertEquals(currentStepSize, ratingBar.getStepSize());
+        mRatingBar.setStepSize(mRatingBar.getNumStars() + 0.1f);
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize(), 0.0f);
 
-        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;
-        }
+        mRatingBar.setStepSize(Float.MAX_VALUE);
+        assertEquals(currentMax, mRatingBar.getMax());
+        assertEquals(currentProgress, mRatingBar.getProgress());
+        assertEquals(currentStepSize, mRatingBar.getStepSize(), 0.0f);
     }
 }
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..bebebf2 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -16,15 +16,19 @@
 
 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.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
+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.test.ViewAsserts;
 import android.util.AttributeSet;
 import android.util.Xml;
@@ -36,25 +40,35 @@
 import android.widget.RelativeLayout;
 import android.widget.cts.util.XmlUtils;
 
+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;
 
 /**
  * Test {@link RelativeLayout}.
  */
-public class RelativeLayoutTest extends
-        ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RelativeLayoutTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
-    public RelativeLayoutTest() {
-        super("android.widget.cts", RelativeLayoutCtsActivity.class);
+    @Rule
+    public ActivityTestRule<RelativeLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RelativeLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new RelativeLayout(mActivity);
 
@@ -65,15 +79,15 @@
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.relative_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
         new RelativeLayout(mActivity, attrs);
-
-        try {
-            new RelativeLayout(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
-    public void testSetIgnoreGravity() {
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new RelativeLayout(null, null);
+    }
+
+    @Test
+    public void testSetIgnoreGravity() throws Throwable {
         // Initial gravity for this RelativeLayout is Gravity.Right.
         final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_ignore_gravity);
@@ -86,27 +100,20 @@
         ViewAsserts.assertRightAligned(relativeLayout, view13);
 
         relativeLayout.setIgnoreGravity(R.id.relative_view13);
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.requestLayout();
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(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();
+        mActivityRule.runOnUiThread(relativeLayout::requestLayout);
+        mInstrumentation.waitForIdleSync();
         ViewAsserts.assertRightAligned(relativeLayout, view12);
         ViewAsserts.assertRightAligned(relativeLayout, view13);
     }
 
-    public void testSetGravity() {
+    @Test
+    public void testAccessGravity() throws Throwable {
         final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_gravity);
 
@@ -120,48 +127,38 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // -- BOTTOM && RIGHT
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(
+                () -> 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();
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(() -> 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();
@@ -170,7 +167,8 @@
         assertEquals(view11.getTop(), view10.getBottom());
     }
 
-    public void testSetHorizontalGravity() {
+    @Test
+    public void testSetHorizontalGravity() throws Throwable {
         final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_gravity);
 
@@ -184,31 +182,28 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // RIGHT
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setHorizontalGravity(Gravity.RIGHT);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(
+                () -> 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);
         assertEquals(view11.getTop(), view10.getBottom());
     }
 
-    public void testSetVerticalGravity() {
+    @Test
+    public void testSetVerticalGravity() throws Throwable {
         final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
                 R.id.relative_sublayout_gravity);
 
@@ -222,24 +217,20 @@
         assertEquals(view11.getTop(), view10.getBottom());
 
         // BOTTOM
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                relativeLayout.setVerticalGravity(Gravity.BOTTOM);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(
+                () -> 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();
@@ -248,6 +239,7 @@
         assertEquals(view11.getTop(), view10.getBottom());
     }
 
+    @Test
     public void testGetBaseline() {
         RelativeLayout relativeLayout = new RelativeLayout(mActivity);
         assertEquals(-1, relativeLayout.getBaseline());
@@ -257,6 +249,7 @@
         assertEquals(view.getBaseline(), relativeLayout.getBaseline());
     }
 
+    @Test
     public void testGenerateLayoutParams1() throws XmlPullParserException, IOException {
         RelativeLayout relativeLayout = new RelativeLayout(mActivity);
 
@@ -268,6 +261,7 @@
         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.height);
     }
 
+    @Test
     public void testGenerateLayoutParams2() {
         RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(200, 300);
 
@@ -278,15 +272,15 @@
                  (RelativeLayout.LayoutParams) myRelativeLayout.generateLayoutParams(p);
          assertEquals(200, layoutParams.width);
          assertEquals(300, layoutParams.height);
-
-        // exceptional value
-         try {
-             myRelativeLayout.generateLayoutParams((ViewGroup.LayoutParams) null);
-             fail("Should throw RuntimeException");
-         } catch (RuntimeException e) {
-         }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGenerateLayoutParamsFromNull() {
+        MyRelativeLayout myRelativeLayout = new MyRelativeLayout(mActivity);
+        myRelativeLayout.generateLayoutParams((ViewGroup.LayoutParams) null);
+    }
+
+    @Test
     public void testGenerateDefaultLayoutParams() {
         MyRelativeLayout myRelativeLayout = new MyRelativeLayout(mActivity);
 
@@ -296,6 +290,7 @@
         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, layoutParams.height);
     }
 
+    @Test
     public void testGenerateLayoutParamsFromMarginParams() {
         MyRelativeLayout layout = new MyRelativeLayout(mActivity);
         ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5);
@@ -315,14 +310,7 @@
         assertEquals(4, generated.bottomMargin);
     }
 
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
-
+    @Test
     public void testCheckLayoutParams() {
         MyRelativeLayout myRelativeLayout = new MyRelativeLayout(mActivity);
 
@@ -336,6 +324,7 @@
         assertFalse(myRelativeLayout.checkLayoutParams(p3));
     }
 
+    @Test
     public void testGetRule() {
         RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(0, 0);
         p.addRule(RelativeLayout.LEFT_OF, R.id.abslistview_root);
@@ -351,13 +340,11 @@
     /**
      * 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();
+    @Test
+    public void testBaselineAlignment() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> 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..9de034b 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayout_LayoutParamsTest.java
@@ -16,27 +16,49 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
-import android.test.ActivityInstrumentationTestCase2;
+import android.app.Activity;
+import android.content.res.XmlResourceParser;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 
 /**
  * Test {@link RelativeLayout.LayoutParams}.
  */
-public class RelativeLayout_LayoutParamsTest extends
-        ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RelativeLayout_LayoutParamsTest {
+    private Activity mActivity;
 
-    public RelativeLayout_LayoutParamsTest() {
-        super("android.widget.cts", RelativeLayoutCtsActivity.class);
+    @Rule
+    public ActivityTestRule<RelativeLayoutCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RelativeLayoutCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    public void testConstructor() {
-
+    @Test
+    public void testConstructor() throws XmlPullParserException, IOException {
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
         assertEquals(200, layoutParams.width);
         assertEquals(300, layoutParams.height);
@@ -46,22 +68,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 +102,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 +113,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 +125,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 +135,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 +145,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 +155,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 +165,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 +176,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);
@@ -155,20 +187,20 @@
         assertEquals(R.id.relative_view3, rules[RelativeLayout.ALIGN_BOTTOM]);
     }
 
+    @Test
     public void testStartEnd() {
         RelativeLayout.LayoutParams layoutParams;
 
         // 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 +209,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 +229,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 +251,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 +270,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 +289,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 +308,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 +323,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 +343,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);
@@ -332,9 +364,10 @@
         layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_LTR);
     }
 
-    public void testAccessRule1() {
+    @Test
+    public void testAccessRuleVerb() {
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
-        int rules[]= layoutParams.getRules();
+        int rules[] = layoutParams.getRules();
 
         // normal value
         assertEquals(0, rules[RelativeLayout.CENTER_IN_PARENT]);
@@ -346,24 +379,24 @@
         assertEquals(0, rules[RelativeLayout.ALIGN_LEFT]);
         layoutParams.addRule(RelativeLayout.ALIGN_LEFT);
         assertEquals(RelativeLayout.TRUE, rules[RelativeLayout.ALIGN_LEFT]);
-
-        // exceptional value
-        try {
-            layoutParams.addRule(-1);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // issue 1695243, not clear what is supposed to happen when verb is exceptional.
-        }
-
-        try {
-            layoutParams.addRule(Integer.MAX_VALUE);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // issue 1695243, not clear what is supposed to happen when verb is exceptional.
-        }
     }
 
-    public void testAccessRule2() {
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testAddRuleVerbTooLow() {
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
+
+        layoutParams.addRule(-1);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testAddRuleVerbTooHigh() {
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
+
+        layoutParams.addRule(Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void testAccessRuleVerbSubject() {
         int rules[];
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
 
@@ -393,20 +426,6 @@
         rules = layoutParams.getRules();
         assertEquals(R.id.relative_view1, rules[RelativeLayout.ALIGN_PARENT_LEFT]);
 
-        try {
-            layoutParams.addRule(-1, 0);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // issue 1695243, not clear what is supposed to happen when verb is exceptional.
-        }
-
-        try {
-            layoutParams.addRule(Integer.MAX_VALUE, 0);
-            fail("Should throw ArrayIndexOutOfBoundsException");
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // issue 1695243, not clear what is supposed to happen when verb is exceptional.
-        }
-
         layoutParams.addRule(RelativeLayout.ALIGN_LEFT, Integer.MAX_VALUE);
         rules = layoutParams.getRules();
         assertEquals(Integer.MAX_VALUE, rules[RelativeLayout.ALIGN_LEFT]);
@@ -416,6 +435,21 @@
         assertEquals(Integer.MIN_VALUE, rules[RelativeLayout.ALIGN_LEFT]);
     }
 
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testAddRuleVerbSubjectTooLow() {
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
+
+        layoutParams.addRule(-1, 0);
+    }
+
+    @Test(expected=ArrayIndexOutOfBoundsException.class)
+    public void testAddRuleVerbSubjectTooHigh() {
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
+
+        layoutParams.addRule(Integer.MAX_VALUE, 0);
+    }
+
+    @Test
     public void testRemoveRule() {
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
 
@@ -439,6 +473,7 @@
         assertEquals(0, layoutParams.getRule(RelativeLayout.CENTER_HORIZONTAL));
     }
 
+    @Test
     public void testDebug() {
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(200, 300);
         assertNotNull(layoutParams.debug("test: "));
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
index 369d7aa..5c92e66 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsActivityTest.java
@@ -16,35 +16,43 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
-import android.cts.util.NullWebViewUtils;
 import android.os.Parcel;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.InflateException;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
-import android.widget.cts.R;
+import com.android.compatibility.common.util.NullWebViewUtils;
 
-public class RemoteViewsActivityTest
-        extends ActivityInstrumentationTestCase2<RemoteViewsCtsActivity> {
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteViewsActivityTest {
     private static final String PACKAGE_NAME = "android.widget.cts";
     private Activity mActivity;
 
-    public RemoteViewsActivityTest() {
-        super(PACKAGE_NAME, RemoteViewsCtsActivity.class);
+    @Rule
+    public ActivityTestRule<RemoteViewsCtsActivity> mActivityRule =
+            new ActivityTestRule<>(RemoteViewsCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @MediumTest
-    public void testGood() throws Exception {
+    @Test
+    public void testGood() {
         RemoteViews orig = new RemoteViews(PACKAGE_NAME, R.layout.remote_view_test_good);
         Parcel p = Parcel.obtain();
         orig.writeToParcel(p, 0);
@@ -69,8 +77,8 @@
         assertTrue("Button not inflated", result.findViewById(R.id.button) != null);
     }
 
-    @MediumTest
-    public void testDerivedClass() throws Exception {
+    @Test
+    public void testDerivedClass() {
         RemoteViews orig = new RemoteViews(PACKAGE_NAME, R.layout.remote_view_test_bad_1);
         Parcel p = Parcel.obtain();
         orig.writeToParcel(p, 0);
@@ -95,8 +103,8 @@
         assertNull("Derived class (EditText) allowed to be inflated", result);
     }
 
-    @MediumTest
-    public void testWebView() throws Exception {
+    @Test
+    public void testWebView() {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
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..f8b9994 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -16,38 +16,71 @@
 
 package android.widget.cts;
 
-import android.graphics.drawable.Icon;
-import android.test.UiThreadTest;
-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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 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.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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 com.android.compatibility.common.util.WidgetTestUtils;
+
+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 +91,58 @@
 /**
  * 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;
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
+        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);
+
+        root.addView(mResult);
     }
 
-    @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);
-            }
-        });
-    }
-
+    @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,106 +150,131 @@
         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());
     }
 
-    public void testSetViewVisibility() {
+    @Test
+    public void testSetContentDescription() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertTrue(TextUtils.equals(contentDescription, view.getContentDescription()));
+    }
+
+    @Test
+    public void testSetViewVisibility() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.INVISIBLE, view.getVisibility());
 
         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.GONE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.GONE, view.getVisibility());
 
         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.VISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.VISIBLE, view.getVisibility());
     }
 
-    public void testSetTextViewText() {
+    @Test
+    public void testSetTextViewText() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(expected, textView.getText().toString());
 
         mRemoteViews.setTextViewText(R.id.remoteView_text, null);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetIcon() {
+    @Test
+    public void testSetTextViewTextSize() throws Throwable {
+        TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setTextViewTextSize(R.id.remoteView_text, TypedValue.COMPLEX_UNIT_SP, 18);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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());
     }
 
-    public void testSetImageViewIcon() {
+    @Test
+    public void testSetImageViewIcon() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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());
 
     }
 
-    public void testSetImageViewResource() {
+    @Test
+    public void testSetImageViewResource() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetImageViewUri() throws IOException {
+    @Test
+    public void testSetImageViewUri() throws Throwable {
         String path = getTestImagePath();
         File imageFile = new File(path);
 
@@ -212,11 +286,11 @@
             assertNull(image.getDrawable());
 
             mRemoteViews.setImageViewUri(R.id.remoteView_image, uri);
-            mRemoteViews.reapply(mActivity, mResult);
+            mActivityRule.runOnUiThread(() -> 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,42 +301,57 @@
      * 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";
     }
 
-    public void testSetChronometer() {
+    @Test
+    public void testSetChronometer() throws Throwable {
         long base1 = 50;
         long base2 = -50;
         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
 
         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "HH:MM:SS",
                 false);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetProgressBar() {
+    @Test
+    public void testSetChronometerCountDown() throws Throwable {
+        Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
+
+        mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, true);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertTrue(chronometer.isCountDown());
+
+        mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, false);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
         ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress);
         assertEquals(100, progress.getMax());
         assertEquals(0, progress.getProgress());
@@ -270,27 +359,24 @@
         assertFalse(progress.isIndeterminate());
 
         mRemoteViews.setProgressBar(R.id.remoteView_progress, 80, 50, true);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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 +390,58 @@
         assertNotNull(mResult.findViewById(R.id.remoteView_text));
     }
 
-    public void testReapply() {
-        TextView text = new TextView(mActivity);
+    @Test
+    public void testReapply() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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 +451,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 +459,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,131 +468,121 @@
         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
-        }
     }
 
-    public void testSetImageViewBitmap() {
+    @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() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetBitmap() {
+    @Test
+    public void testSetBitmap() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetBoolean() {
+    @Test
+    public void testSetBoolean() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetCharSequence() {
+    @Test
+    public void testSetCharSequence() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(expected, textView.getText().toString());
 
         mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", null);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetInt() {
+    @Test
+    public void testSetInt() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.INVISIBLE, view.getVisibility());
 
         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.GONE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.GONE, view.getVisibility());
 
         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.VISIBLE);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(View.VISIBLE, view.getVisibility());
     }
 
-    public void testSetString() {
+    @Test
+    public void testSetString() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetUri() throws IOException {
+    @Test
+    public void testSetUri() throws Throwable {
         String path = getTestImagePath();
         File imagefile = new File(path);
 
@@ -510,50 +594,102 @@
             assertNull(image.getDrawable());
 
             mRemoteViews.setUri(R.id.remoteView_image, "setImageURI", uri);
-            mRemoteViews.reapply(mActivity, mResult);
+            mActivityRule.runOnUiThread(() -> 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();
         }
     }
 
-    public void testSetTextColor() {
+    @Test
+    public void testSetTextColor() throws Throwable {
         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
 
         mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor1);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetOnClickPendingIntent() {
+    @Test
+    public void testSetTextCompoundDrawables() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
         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 +697,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();
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        mActivityRule.runOnUiThread(() -> view.performClick());
         newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT);
         assertNotNull(newActivity);
+        assertTrue(newActivity instanceof MockURLSpanTestActivity);
         newActivity.finish();
     }
 
-    public void testSetLong() {
+    @Test
+    public void testSetLong() throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         assertEquals(base1, chronometer.getBase());
 
         mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base2);
-        mRemoteViews.reapply(mActivity, mResult);
+        mActivityRule.runOnUiThread(() -> 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);
     }
 
-    public void testSetFloat() {
+    @Test
+    public void testSetFloat() throws Throwable {
         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());
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals(0, customView.getByteField());
+
+        byte b = 100;
+        mRemoteViews.setByte(R.id.remoteView_custom, "setByteField", b);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals('\u0000', customView.getCharField());
+
+        mRemoteViews.setChar(R.id.remoteView_custom, "setCharField", 'q');
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
+        assertEquals(0, customView.getShortField());
+
+        short s = 25;
+        mRemoteViews.setShort(R.id.remoteView_custom, "setShortField", s);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good);
+        assertTrue(root.getChildCount() > 0);
+
+        mRemoteViews.removeAllViews(R.id.remoteViews_good);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(0, root.getChildCount());
+    }
+
+    @Test
+    public void testAddView() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> 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() throws Throwable {
+        View labelView = mResult.findViewById(R.id.remoteView_label);
+        assertEquals(View.NO_ID, labelView.getLabelFor());
+
+        mRemoteViews.setLabelFor(R.id.remoteView_label, R.id.remoteView_text);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_text, labelView.getLabelFor());
+    }
+
+    @Test
+    public void testSetAccessibilityTraversalAfter() throws Throwable {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_frame);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalAfter());
+
+        mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_linear);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalAfter());
+    }
+
+    @Test
+    public void testSetAccessibilityTraversalBefore() throws Throwable {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_frame);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalBefore());
+
+        mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_linear);
+        mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+        assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalBefore());
+    }
+
+    @Test
+    public void testSetViewPadding() throws Throwable {
+        View textView = mResult.findViewById(R.id.remoteView_text);
+
+        mRemoteViews.setViewPadding(R.id.remoteView_text, 10, 20, 30, 40);
+        mActivityRule.runOnUiThread(() -> 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);
+        mActivityRule.runOnUiThread(() -> 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..9c47e69
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsWidgetTest.java
@@ -0,0 +1,518 @@
+/*
+ * 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.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+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.os.Bundle;
+import android.os.Process;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+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 com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
+
+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() throws Throwable {
+        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);
+
+        mActivityRule.runOnUiThread(
+                () -> 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);
+
+        mActivityRule.runOnUiThread(() -> 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) throws Throwable {
+        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();
+        mActivityRule.runOnUiThread(
+                () -> 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() throws Throwable {
+        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/RemoteViews_ActionExceptionTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViews_ActionExceptionTest.java
index 9f9f1d7..3550108 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViews_ActionExceptionTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViews_ActionExceptionTest.java
@@ -16,15 +16,20 @@
 
 package android.widget.cts;
 
-
-import android.test.InstrumentationTestCase;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.widget.RemoteViews;
-import android.widget.RemoteViews.ActionException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
- * Test {@link ActionException}.
+ * Test {@link RemoteViews.ActionException}.
  */
-public class RemoteViews_ActionExceptionTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteViews_ActionExceptionTest {
+    @Test
     public void testConstructor() {
         String message = "This is exception message";
         new RemoteViews.ActionException(message);
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
index aefca0f..972f092 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
@@ -16,23 +16,36 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static junit.framework.Assert.assertTrue;
 
+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 android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ResourceCursorAdapter;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ResourceCursorAdapter}.
  */
-public class ResourceCursorAdapterTest extends InstrumentationTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ResourceCursorAdapterTest {
     private ResourceCursorAdapter mResourceCursorAdapter;
 
     private Context mContext;
@@ -41,11 +54,9 @@
 
     private Cursor mCursor;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mResourceCursorAdapter = null;
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mParent = (ViewGroup) layoutInflater.inflate(R.layout.cursoradapter_host, null);
@@ -53,6 +64,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         MockResourceCursorAdapter adapter = new MockResourceCursorAdapter(mContext, -1, null);
         // the default is true
@@ -71,6 +83,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetViewResource() {
         mResourceCursorAdapter = new MockResourceCursorAdapter(mContext,
                 R.layout.cursoradapter_item0, mCursor);
@@ -87,6 +100,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetDropDownViewResource() {
         mResourceCursorAdapter = new MockResourceCursorAdapter(mContext,
                 R.layout.cursoradapter_item0, mCursor);
@@ -110,8 +124,9 @@
         assertEquals(R.id.cursorAdapter_item0, result.getId());
     }
 
-    // parameters Context and Cursor are never readin the method
+    // parameters Context and Cursor are never read in the method
     @UiThreadTest
+    @Test
     public void testNewDropDownView() {
         mResourceCursorAdapter = new MockResourceCursorAdapter(mContext,
                 R.layout.cursoradapter_item0, mCursor);
@@ -128,6 +143,7 @@
 
     // The parameters Context and Cursor are never read in the method
     @UiThreadTest
+    @Test
     public void testNewView() {
         mResourceCursorAdapter = new MockResourceCursorAdapter(mContext,
                 R.layout.cursoradapter_item0, mCursor);
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
index e801e93..2076620 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorTreeAdapterTest.java
@@ -16,23 +16,31 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ResourceCursorTreeAdapter;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ResourceCursorTreeAdapter}.
  */
-public class ResourceCursorTreeAdapterTest extends InstrumentationTestCase {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ResourceCursorTreeAdapterTest {
     private ResourceCursorTreeAdapter mResourceCursorTreeAdapter;
 
     private Context mContext;
@@ -63,16 +71,16 @@
 
     private int mLastChildId = R.id.cursorAdapter_item1;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mParent = (ViewGroup) layoutInflater.inflate(R.layout.cursoradapter_host, null);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         mResourceCursorTreeAdapter = new MockResourceCursorTreeAdapter(mContext, null,
                 mGroupLayout, mChildLayout);
@@ -96,8 +104,9 @@
         new MockResourceCursorTreeAdapter(mContext, null, -1, -1, -1, -1);
     }
 
-    // The parameters Context and Cursor are never readin the method
+    // The parameters Context and Cursor are never read in the method
     @UiThreadTest
+    @Test
     public void testNewChildView() {
         mResourceCursorTreeAdapter = new MockResourceCursorTreeAdapter(mContext, null,
                 mGroupLayout, mChildLayout);
@@ -118,8 +127,9 @@
         assertEquals(mNormalChildId, result.getId());
     }
 
-    // The parameters Context and Cursor are never readin the method
+    // The parameters Context and Cursor are never read in the method
     @UiThreadTest
+    @Test
     public void testNewGroupView() {
         mResourceCursorTreeAdapter = new MockResourceCursorTreeAdapter(mContext, null,
                 mGroupLayout, mChildLayout);
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..3abb023 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -16,36 +16,48 @@
 
 package android.widget.cts;
 
+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.junit.Assert.fail;
 import static org.mockito.Matchers.eq;
 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.app.Instrumentation;
 import android.content.Context;
-import android.cts.util.PollingCheck;
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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.util.TestUtils;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link ScrollView}.
  */
-public class ScrollViewTest extends ActivityInstrumentationTestCase2<ScrollViewCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ScrollViewTest {
     // view dpi constants. Must match those defined in scroll_view layout
     private static final int ITEM_WIDTH_DPI  = 250;
     private static final int ITEM_HEIGHT_DPI = 100;
@@ -61,30 +73,36 @@
     private int mScrollBottom;
     private int mScrollRight;
 
-    private MyScrollView mScrollView;
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
+    private ScrollView mScrollViewRegular;
+    private ScrollView mScrollViewCustom;
+    private MyScrollView mScrollViewCustomEmpty;
 
-    public ScrollViewTest() {
-        super("android.widget.cts", ScrollViewCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ScrollViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ScrollViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mScrollView = (MyScrollView) mActivity.findViewById(R.id.scroll_view);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mScrollViewRegular = (ScrollView) mActivity.findViewById(R.id.scroll_view_regular);
+        mScrollViewCustom = (ScrollView) mActivity.findViewById(R.id.scroll_view_custom);
+        mScrollViewCustomEmpty = (MyScrollView) mActivity.findViewById(
+                R.id.scroll_view_custom_empty);
 
         // 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;
     }
 
+    @Test
     public void testConstructor() {
         XmlPullParser parser = mActivity.getResources().getLayout(R.layout.scrollview_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -95,226 +113,214 @@
         new ScrollView(mActivity, attrs, 0);
     }
 
+    @UiThreadTest
+    @Test
     public void testGetMaxScrollAmount() {
         // the value is half of total layout height
-        ScrollView scrollView = new ScrollView(mActivity);
-        scrollView.layout(0, 0, 100, 200);
-        assertEquals((200 - 0) / 2, scrollView.getMaxScrollAmount());
+        mScrollViewRegular.layout(0, 0, 100, 200);
+        assertEquals((200 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
 
-        scrollView.layout(0, 0, 150, 100);
-        assertEquals((100 - 0) / 2, scrollView.getMaxScrollAmount());
+        mScrollViewRegular.layout(0, 0, 150, 100);
+        assertEquals((100 - 0) / 2, mScrollViewRegular.getMaxScrollAmount());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddView() {
-        ScrollView scrollView = new ScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1);
+            mScrollViewRegular.addView(child1);
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithIndex() {
-        ScrollView scrollView = new ScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, 0);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, 0);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, 1);
+            mScrollViewRegular.addView(child1, 1);
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
-        scrollView.addView(child0, -1);
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.removeAllViews();
+        mScrollViewRegular = new ScrollView(mActivity);
+        mScrollViewRegular.addView(child0, -1);
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, -1);
+            mScrollViewRegular.addView(child1, -1);
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
+        mScrollViewRegular = new ScrollView(mActivity);
         try {
-            scrollView.addView(child0, 1);
+            mScrollViewRegular.addView(child0, 1);
             fail("ScrollView can host only one direct child");
         } catch (IndexOutOfBoundsException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithLayoutParams() {
-        ScrollView scrollView = new ScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, new ViewGroup.LayoutParams(200, 100));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(200, child0.getLayoutParams().width);
         assertEquals(100, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, new ViewGroup.LayoutParams(200, 100));
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
+        mScrollViewRegular = new ScrollView(mActivity);
         child0 = new TextView(mActivity);
         try {
-            scrollView.addView(child0, null);
+            mScrollViewRegular.addView(child0, null);
             fail("The LayoutParams should not be null!");
         } catch (NullPointerException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAddViewWithIndexAndLayoutParams() {
-        ScrollView scrollView = new ScrollView(mActivity);
         TextView child0 = new TextView(mActivity);
-        scrollView.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.addView(child0, 0, new ViewGroup.LayoutParams(200, 100));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(200, child0.getLayoutParams().width);
         assertEquals(100, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         TextView child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, 0, new ViewGroup.LayoutParams(200, 100));
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
         child0 = new TextView(mActivity);
         try {
-            scrollView.addView(child0, null);
+            mScrollViewRegular.addView(child0, null);
             fail("The LayoutParams should not be null!");
         } catch (NullPointerException e) {
             // expected
         }
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
-        scrollView.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
-        assertSame(child0, scrollView.getChildAt(0));
+        mScrollViewRegular.removeAllViews();
+        mScrollViewRegular.addView(child0, -1, new ViewGroup.LayoutParams(300, 150));
+        assertSame(child0, mScrollViewRegular.getChildAt(0));
         assertEquals(300, child0.getLayoutParams().width);
         assertEquals(150, child0.getLayoutParams().height);
 
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
         child1 = new TextView(mActivity);
         try {
-            scrollView.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child1, -1, new ViewGroup.LayoutParams(200, 100));
             fail("ScrollView can host only one direct child");
         } catch (IllegalStateException e) {
             // expected
         }
-        assertEquals(1, scrollView.getChildCount());
+        assertEquals(1, mScrollViewRegular.getChildCount());
 
-        scrollView.removeAllViews();
-        scrollView = new ScrollView(mActivity);
+        mScrollViewRegular.removeAllViews();
         try {
-            scrollView.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
+            mScrollViewRegular.addView(child0, 1, new ViewGroup.LayoutParams(200, 100));
             fail("ScrollView can host only one direct child");
         } catch (IndexOutOfBoundsException e) {
             // expected
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessFillViewport() {
-        ScrollView scrollView = new ScrollView(mActivity);
-        assertFalse(scrollView.isFillViewport());
-        scrollView.layout(0, 0, 100, 100);
-        assertFalse(scrollView.isLayoutRequested());
+        assertFalse(mScrollViewRegular.isFillViewport());
+        mScrollViewRegular.layout(0, 0, 100, 100);
+        assertFalse(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.setFillViewport(false);
-        assertFalse(scrollView.isFillViewport());
-        assertFalse(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(false);
+        assertFalse(mScrollViewRegular.isFillViewport());
+        assertFalse(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.setFillViewport(true);
-        assertTrue(scrollView.isFillViewport());
-        assertTrue(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(true);
+        assertTrue(mScrollViewRegular.isFillViewport());
+        assertTrue(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.layout(0, 0, 100, 100);
-        assertFalse(mScrollView.isLayoutRequested());
+        mScrollViewRegular.layout(0, 0, 100, 100);
+        assertFalse(mScrollViewRegular.isLayoutRequested());
 
-        scrollView.setFillViewport(false);
-        assertFalse(scrollView.isFillViewport());
-        assertTrue(scrollView.isLayoutRequested());
+        mScrollViewRegular.setFillViewport(false);
+        assertFalse(mScrollViewRegular.isFillViewport());
+        assertTrue(mScrollViewRegular.isLayoutRequested());
     }
 
+    @Test
     public void testAccessSmoothScrollingEnabled() throws Throwable {
-        assertTrue(mScrollView.isSmoothScrollingEnabled());
+        assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
 
         // scroll immediately
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertFalse(mScrollView.isSmoothScrollingEnabled());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertFalse(mScrollViewCustom.isSmoothScrollingEnabled());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_DOWN);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
 
-        assertEquals(mScrollBottom, mScrollView.getScrollY(), TOLERANCE);
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_UP);
-            }
-        });
-        assertEquals(0, mScrollView.getScrollY());
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_UP));
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
         // smooth scroll
-        mScrollView.setSmoothScrollingEnabled(true);
-        assertTrue(mScrollView.isSmoothScrollingEnabled());
+        mScrollViewCustom.setSmoothScrollingEnabled(true);
+        assertTrue(mScrollViewCustom.isSmoothScrollingEnabled());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_DOWN);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
         pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
-        assertEquals(mScrollBottom, mScrollView.getScrollY(), TOLERANCE);
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fullScroll(View.FOCUS_UP);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fullScroll(View.FOCUS_UP));
         pollingCheckSmoothScrolling(0, 0, mScrollBottom, 0);
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChild() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-
         MyView child = new MyView(mActivity);
         child.setBackgroundDrawable(null);
         child.setPadding(0, 0, 0, 0);
@@ -326,16 +332,17 @@
         assertEquals(100, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewCustomEmpty.measureChild(child,
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
 
         assertEquals(30, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureChildWithMargins() {
-        MyScrollView mockScrollView = new MyScrollView(mActivity);
-
         MyView child = new MyView(mActivity);
         child.setBackgroundDrawable(null);
         child.setPadding(0, 0, 0, 0);
@@ -347,7 +354,7 @@
         assertEquals(100, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
 
-        mockScrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 5);
 
@@ -355,37 +362,42 @@
         assertEquals(100, child.getMeasuredWidth());
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecs() {
         MyView child = spy(new MyView(mActivity));
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+        mScrollViewCustomEmpty.measureChild(child,
+                MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
         verify(child).onMeasure(
                 eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)),
                 eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithPadding() {
         MyView child = spy(new MyView(mActivity));
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setPadding(3, 5, 7, 11);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+        mScrollViewCustomEmpty.measureChild(child,
+                MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
         verify(child).onMeasure(
                 eq(MeasureSpec.makeMeasureSpec(140, MeasureSpec.EXACTLY)),
                 eq(MeasureSpec.makeMeasureSpec(84, MeasureSpec.UNSPECIFIED)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMargins() {
         MyView child = spy(new MyView(mActivity));
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
         verify(child).onMeasure(
@@ -393,13 +405,14 @@
                 eq(MeasureSpec.makeMeasureSpec(85, MeasureSpec.UNSPECIFIED)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMarginsAndPadding() {
         MyView child = spy(new MyView(mActivity));
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setPadding(3, 5, 7, 11);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.setPadding(3, 5, 7, 11);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
                 MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
         verify(child).onMeasure(
@@ -407,12 +420,13 @@
                 eq(MeasureSpec.makeMeasureSpec(69, MeasureSpec.UNSPECIFIED)));
     }
 
+    @UiThreadTest
+    @Test
     public void testMeasureSpecsWithMarginsAndNoHintWidth() {
         MyView child = spy(new MyView(mActivity));
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.addView(child);
+        mScrollViewCustomEmpty.addView(child);
 
-        scrollView.measureChildWithMargins(child,
+        mScrollViewCustomEmpty.measureChildWithMargins(child,
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15);
         verify(child).onMeasure(
@@ -420,47 +434,52 @@
                 eq(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)));
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewport() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
 
         MyView child = new MyView(mActivity);
         child.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(150, child.getMeasuredHeight());
         assertEquals(100, child.getMeasuredWidth());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(0, child.getTop());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithScrollViewPadding() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setFillViewport(true);
-        scrollView.setPadding(3, 10, 5, 7);
+        mScrollViewRegular.setFillViewport(true);
+        mScrollViewRegular.setPadding(3, 10, 5, 7);
 
         MyView child = new MyView(mActivity);
         child.setLayoutParams(new ViewGroup.LayoutParams(10,10));
         child.setDesiredHeight(30);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(
+                MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(133, child.getMeasuredHeight());
         assertEquals(10, child.getMeasuredWidth());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(10, child.getTop());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithChildMargins() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
 
         MyView child = new MyView(mActivity);
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10);
@@ -471,40 +490,42 @@
         child.setDesiredHeight(30);
         child.setLayoutParams(lp);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(133, child.getMeasuredHeight());
         assertEquals(10, child.getMeasuredWidth());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(10, child.getTop());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithScrollViewPaddingAlreadyFills() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setFillViewport(true);
-        scrollView.setPadding(3, 10, 5, 7);
+        mScrollViewRegular.setFillViewport(true);
+        mScrollViewRegular.setPadding(3, 10, 5, 7);
 
         MyView child = new MyView(mActivity);
         child.setDesiredHeight(175);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
 
         assertEquals(92, child.getMeasuredWidth());
         assertEquals(175, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(10, child.getTop());
     }
 
+    @UiThreadTest
+    @Test
     public void testFillViewportWithChildMarginsAlreadyFills() {
-        MyScrollView scrollView = new MyScrollView(mActivity);
-        scrollView.setFillViewport(true);
+        mScrollViewRegular.setFillViewport(true);
         MyView child = new MyView(mActivity);
         FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
@@ -517,155 +538,155 @@
         child.setLayoutParams(lp);
         child.setDesiredHeight(175);
 
-        scrollView.addView(child);
-        scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+        mScrollViewRegular.addView(child);
+        mScrollViewRegular.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
 
         assertEquals(92, child.getMeasuredWidth());
         assertEquals(175, child.getMeasuredHeight());
 
-        scrollView.layout(0, 0, 100, 150);
+        mScrollViewRegular.layout(0, 0, 100, 150);
         assertEquals(10, child.getTop());
     }
 
     @UiThreadTest
+    @Test
     public void testPageScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollY());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_DOWN));
-        assertEquals(mPageHeight, mScrollView.getScrollY(), TOLERANCE);
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
+        assertEquals(mPageHeight, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_DOWN));
-        assertEquals(mPageHeight * 2, mScrollView.getScrollY(), TOLERANCE);
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
+        assertEquals(mPageHeight * 2, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        mScrollView.scrollTo(mPageWidth, mScrollBottom);
-        assertFalse(mScrollView.pageScroll(View.FOCUS_DOWN));
-        assertEquals(mScrollBottom, mScrollView.getScrollY(), TOLERANCE);
+        mScrollViewCustom.scrollTo(mPageWidth, mScrollBottom);
+        assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_DOWN));
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_UP));
-        assertEquals(mScrollBottom - mPageHeight, mScrollView.getScrollY(), TOLERANCE);
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_UP));
+        assertEquals(mScrollBottom - mPageHeight, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        assertTrue(mScrollView.pageScroll(View.FOCUS_UP));
-        assertEquals(mScrollBottom -mPageHeight * 2, mScrollView.getScrollY(), TOLERANCE);
+        assertTrue(mScrollViewCustom.pageScroll(View.FOCUS_UP));
+        assertEquals(mScrollBottom -mPageHeight * 2, mScrollViewCustom.getScrollY(), TOLERANCE);
 
-        mScrollView.scrollTo(mPageWidth, 0);
-        assertFalse(mScrollView.pageScroll(View.FOCUS_UP));
-        assertEquals(0, mScrollView.getScrollY());
+        mScrollViewCustom.scrollTo(mPageWidth, 0);
+        assertFalse(mScrollViewCustom.pageScroll(View.FOCUS_UP));
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
     @UiThreadTest
+    @Test
     public void testFullScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollY());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        assertTrue(mScrollView.fullScroll(View.FOCUS_DOWN));
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
+        assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
 
-        assertFalse(mScrollView.fullScroll(View.FOCUS_DOWN));
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_DOWN));
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
 
-        assertTrue(mScrollView.fullScroll(View.FOCUS_UP));
-        assertEquals(0, mScrollView.getScrollY());
+        assertTrue(mScrollViewCustom.fullScroll(View.FOCUS_UP));
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        assertFalse(mScrollView.fullScroll(View.FOCUS_UP));
-        assertEquals(0, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.fullScroll(View.FOCUS_UP));
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
     @UiThreadTest
+    @Test
     public void testArrowScroll() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        assertEquals(0, mScrollView.getScrollY());
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        int y = mScrollView.getScrollY();
+        int y = mScrollViewCustom.getScrollY();
         while (mScrollBottom != y) {
-            assertTrue(mScrollView.arrowScroll(View.FOCUS_DOWN));
-            assertTrue(y <= mScrollView.getScrollY());
-            y = mScrollView.getScrollY();
+            assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_DOWN));
+            assertTrue(y <= mScrollViewCustom.getScrollY());
+            y = mScrollViewCustom.getScrollY();
         }
 
-        assertFalse(mScrollView.arrowScroll(View.FOCUS_DOWN));
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_DOWN));
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
 
-        y = mScrollView.getScrollY();
+        y = mScrollViewCustom.getScrollY();
         while (0 != y) {
-            assertTrue(mScrollView.arrowScroll(View.FOCUS_UP));
-            assertTrue(y >= mScrollView.getScrollY());
-            y = mScrollView.getScrollY();
+            assertTrue(mScrollViewCustom.arrowScroll(View.FOCUS_UP));
+            assertTrue(y >= mScrollViewCustom.getScrollY());
+            y = mScrollViewCustom.getScrollY();
         }
 
-        assertFalse(mScrollView.arrowScroll(View.FOCUS_UP));
-        assertEquals(0, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.arrowScroll(View.FOCUS_UP));
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
+    @Test
     public void testSmoothScrollBy() throws Throwable {
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollBy(mScrollRight, mScrollBottom);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> mScrollViewCustom.smoothScrollBy(mScrollRight, mScrollBottom));
         // smoothScrollBy doesn't scroll in X
         pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollBy(-mScrollRight, -mScrollBottom);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> mScrollViewCustom.smoothScrollBy(-mScrollRight, -mScrollBottom));
         pollingCheckSmoothScrolling(mScrollRight, 0, mScrollBottom, 0);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
     }
 
+    @Test
     public void testSmoothScrollTo() throws Throwable {
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollTo(mScrollRight, mScrollBottom);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> mScrollViewCustom.smoothScrollTo(mScrollRight, mScrollBottom));
         // smoothScrollTo doesn't scroll in X
         pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.smoothScrollTo(mPageWidth, mPageHeight);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> mScrollViewCustom.smoothScrollTo(mPageWidth, mPageHeight));
         pollingCheckSmoothScrolling(0, 0, mScrollBottom, mPageHeight);
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(mPageHeight, mScrollView.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(mPageHeight, mScrollViewCustom.getScrollY());
     }
 
+    @UiThreadTest
+    @Test
     public void testComputeScrollDeltaToGetChildRectOnScreen() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        int edge = mScrollView.getVerticalFadingEdgeLength();
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        int edge = mScrollViewCustom.getVerticalFadingEdgeLength();
 
         // Rect's height is smaller than scroll view
         Rect rect = new Rect(0, 0, 0, 0);
-        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(0,
+                ((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
 
         rect = new Rect(0, edge, 0, mPageHeight);
-        assertEquals(0, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(0,
+                ((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
 
-        mScrollView.scrollTo(0, 0);
+        mScrollViewCustom.scrollTo(0, 0);
         rect = new Rect(0, edge + 1, 0, mPageHeight);
-        assertEquals(edge, mScrollView.computeScrollDeltaToGetChildRectOnScreen(rect));
+        assertEquals(edge,
+                ((MyScrollView) mScrollViewCustom).computeScrollDeltaToGetChildRectOnScreen(rect));
     }
 
+    @UiThreadTest
+    @Test
     public void testComputeVerticalScrollRange() {
-        assertTrue(mScrollView.getChildCount() > 0);
+        assertTrue(mScrollViewCustom.getChildCount() > 0);
         assertEquals(mItemHeight * ITEM_COUNT,
-                mScrollView.computeVerticalScrollRange(), TOLERANCE);
+                ((MyScrollView) mScrollViewCustom).computeVerticalScrollRange(), TOLERANCE);
 
         MyScrollView myScrollView = new MyScrollView(mActivity);
         assertEquals(0, myScrollView.getChildCount());
@@ -673,145 +694,110 @@
     }
 
     @UiThreadTest
+    @Test
     public void testRequestChildFocus() {
-        mScrollView.setSmoothScrollingEnabled(false);
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
 
-        View firstChild = mScrollView.findViewById(R.id.first_child);
-        View lastChild = mScrollView.findViewById(R.id.last_child);
+        View firstChild = mScrollViewCustom.findViewById(R.id.first_child);
+        View lastChild = mScrollViewCustom.findViewById(R.id.last_child);
         firstChild.requestFocus();
 
-        int scrollY = mScrollView.getScrollY();
-        mScrollView.requestChildFocus(lastChild, lastChild);
+        int scrollY = mScrollViewCustom.getScrollY();
+        mScrollViewCustom.requestChildFocus(lastChild, lastChild);
         // check scrolling to the child which wants focus
-        assertTrue(mScrollView.getScrollY() > scrollY);
+        assertTrue(mScrollViewCustom.getScrollY() > scrollY);
 
-        scrollY = mScrollView.getScrollY();
-        mScrollView.requestChildFocus(firstChild, firstChild);
+        scrollY = mScrollViewCustom.getScrollY();
+        mScrollViewCustom.requestChildFocus(firstChild, firstChild);
         // check scrolling to the child which wants focus
-        assertTrue(mScrollView.getScrollY() < scrollY);
+        assertTrue(mScrollViewCustom.getScrollY() < scrollY);
     }
 
     @UiThreadTest
+    @Test
     public void testRequestChildRectangleOnScreen() {
-        mScrollView.setSmoothScrollingEnabled(false);
-        mScrollView.setVerticalFadingEdgeEnabled(true);
-        int edge = mScrollView.getVerticalFadingEdgeLength();
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
+        mScrollViewCustom.setVerticalFadingEdgeEnabled(true);
+        int edge = mScrollViewCustom.getVerticalFadingEdgeLength();
 
-        View child = mScrollView.findViewById(R.id.first_child);
-        int orgRectSize = (int)(10 * getActivity().getResources().getDisplayMetrics().density);
+        View child = mScrollViewCustom.findViewById(R.id.first_child);
+        int orgRectSize = (int)(10 * mActivity.getResources().getDisplayMetrics().density);
         final Rect originalRect = new Rect(0, 0, orgRectSize, orgRectSize);
         final Rect newRect = new Rect(mItemWidth - orgRectSize, mItemHeight - orgRectSize,
                 mItemWidth, mItemHeight);
 
-        assertFalse(mScrollView.requestChildRectangleOnScreen(child, originalRect, true));
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(0, mScrollView.getScrollY());
+        assertFalse(mScrollViewCustom.requestChildRectangleOnScreen(child, originalRect, true));
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
-        assertTrue(mScrollView.requestChildRectangleOnScreen(child, newRect, true));
-        assertEquals(0, mScrollView.getScrollX());
-        assertEquals(edge, mScrollView.getScrollY());
+        assertTrue(mScrollViewCustom.requestChildRectangleOnScreen(child, newRect, true));
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(edge, mScrollViewCustom.getScrollY());
     }
 
     @UiThreadTest
+    @Test
     public void testRequestLayout() {
-        mScrollView.requestLayout();
+        mScrollViewCustom.requestLayout();
 
-        assertTrue(mScrollView.isLayoutRequested());
+        assertTrue(mScrollViewCustom.isLayoutRequested());
     }
 
+    @Test
     public void testFling() throws Throwable {
-        mScrollView.setSmoothScrollingEnabled(true);
-        assertEquals(0, mScrollView.getScrollY());
+        mScrollViewCustom.setSmoothScrollingEnabled(true);
+        assertEquals(0, mScrollViewCustom.getScrollY());
 
         // fling towards bottom
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fling(2000);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(2000));
         pollingCheckFling(0, true);
 
-        final int currentY = mScrollView.getScrollY();
+        final int currentY = mScrollViewCustom.getScrollY();
         // fling towards top
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mScrollView.fling(-2000);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.fling(-2000));
         pollingCheckFling(currentY, false);
     }
 
     @UiThreadTest
+    @Test
     public void testScrollTo() {
-        mScrollView.setSmoothScrollingEnabled(false);
+        mScrollViewCustom.setSmoothScrollingEnabled(false);
 
-        mScrollView.scrollTo(10, 10);
-        assertEquals(10, mScrollView.getScrollY());
-        assertEquals(10, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(10, 10);
+        assertEquals(10, mScrollViewCustom.getScrollY());
+        assertEquals(10, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(mPageWidth, mPageHeight);
-        assertEquals(mPageHeight, mScrollView.getScrollY());
-        assertEquals(mPageWidth, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(mPageWidth, mPageHeight);
+        assertEquals(mPageHeight, mScrollViewCustom.getScrollY());
+        assertEquals(mPageWidth, mScrollViewCustom.getScrollX());
 
-        mScrollView.scrollTo(mScrollRight, mScrollBottom);
-        assertEquals(mScrollBottom, mScrollView.getScrollY());
-        assertEquals(mScrollRight, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(mScrollRight, mScrollBottom);
+        assertEquals(mScrollBottom, mScrollViewCustom.getScrollY());
+        assertEquals(mScrollRight, mScrollViewCustom.getScrollX());
 
         // reach the top and left
-        mScrollView.scrollTo(-10, -10);
-        assertEquals(0, mScrollView.getScrollY());
-        assertEquals(0, mScrollView.getScrollX());
+        mScrollViewCustom.scrollTo(-10, -10);
+        assertEquals(0, mScrollViewCustom.getScrollY());
+        assertEquals(0, mScrollViewCustom.getScrollX());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetVerticalFadingEdgeStrengths() {
-        assertTrue(mScrollView.getChildCount() > 0);
-        assertTrue(mScrollView.getTopFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getTopFadingEdgeStrength() >= 0.0f);
-        assertTrue(mScrollView.getBottomFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getBottomFadingEdgeStrength() >= 0.0f);
+        MyScrollView myScrollViewCustom = (MyScrollView) mScrollViewCustom;
+
+        assertTrue(myScrollViewCustom.getChildCount() > 0);
+        assertTrue(myScrollViewCustom.getTopFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getTopFadingEdgeStrength() >= 0.0f);
+        assertTrue(myScrollViewCustom.getBottomFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollViewCustom.getBottomFadingEdgeStrength() >= 0.0f);
 
         MyScrollView myScrollView = new MyScrollView(mActivity);
         assertEquals(0, myScrollView.getChildCount());
-        assertTrue(mScrollView.getTopFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getTopFadingEdgeStrength() >= 0.0f);
-        assertTrue(mScrollView.getBottomFadingEdgeStrength() <= 1.0f);
-        assertTrue(mScrollView.getBottomFadingEdgeStrength() >= 0.0f);
-    }
-
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
-
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testExecuteKeyEvent() {
-        // executeKeyEvent() is implementation details, do NOT test
-    }
-
-    public void testOnRequestFocusInDescendants() {
-        // onRequestFocusInDescendants() is implementation details, do NOT test
-    }
-
-    public void testOnSizeChanged() {
-        // onSizeChanged() is implementation details, do NOT test
-    }
-
-    public void testDispatchKeyEvent() {
-        // dispatchKeyEvent() is implementation details, do NOT test
-    }
-
-    public void testOnInterceptTouchEvent() {
-        // onInterceptTouchEvent() is implementation details, do NOT test
-    }
-
-    public void testOnTouchEvent() {
-        // onTouchEvent() is implementation details, do NOT test
-    }
-
-    public void testComputeScroll() {
-        // computeScroll() is implementation details, do NOT test
+        assertTrue(myScrollView.getTopFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollView.getTopFadingEdgeStrength() >= 0.0f);
+        assertTrue(myScrollView.getBottomFadingEdgeStrength() <= 1.0f);
+        assertTrue(myScrollView.getBottomFadingEdgeStrength() >= 0.0f);
     }
 
     private boolean isInRange(int current, int from, int to) {
@@ -829,55 +815,35 @@
         }
 
         if (fromY != toY) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollY(), fromY, toY);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollY(), fromY, toY));
         }
 
         if (fromX != toX) {
-            new PollingCheck() {
-                @Override
-                protected boolean check() {
-                    return isInRange(mScrollView.getScrollX(), fromX, toX);
-                }
-            }.run();
+            PollingCheck.waitFor(() -> isInRange(mScrollViewCustom.getScrollX(), fromX, toX));
         }
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
-            }
-        }.run();
+        PollingCheck.waitFor(
+                () -> toX == mScrollViewCustom.getScrollX()
+                        && toY == mScrollViewCustom.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 mScrollViewCustom.getScrollY() > startPosition;
             }
-        };
+            return mScrollViewCustom.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[] { mScrollViewCustom.getScrollY() };
+        PollingCheck.waitFor(() -> {
+            if (mScrollViewCustom.getScrollY() == previousScrollY[0]) {
+                return true;
+            } else {
+                previousScrollY[0] = mScrollViewCustom.getScrollY();
+                return false;
             }
-        }.run();
+        });
     }
 
     public static class MyView extends View {
@@ -907,4 +873,50 @@
             }
         }
     }
+
+    public static class MyScrollView extends ScrollView {
+        public MyScrollView(Context context) {
+            super(context);
+        }
+
+        public MyScrollView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
+            return super.computeScrollDeltaToGetChildRectOnScreen(rect);
+        }
+
+        @Override
+        protected int computeVerticalScrollRange() {
+            return super.computeVerticalScrollRange();
+        }
+
+        @Override
+        protected float getBottomFadingEdgeStrength() {
+            return super.getBottomFadingEdgeStrength();
+        }
+
+        @Override
+        protected float getTopFadingEdgeStrength() {
+            return super.getTopFadingEdgeStrength();
+        }
+
+        @Override
+        protected void measureChild(View c, int pWidthMeasureSpec, int pHeightMeasureSpec) {
+            super.measureChild(c, pWidthMeasureSpec, pHeightMeasureSpec);
+        }
+
+        @Override
+        protected void measureChildWithMargins(View child, int parentWidthMeasureSpec,
+                int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+            super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+                    parentHeightMeasureSpec, heightUsed);
+        }
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollerTest.java b/tests/tests/widget/src/android/widget/cts/ScrollerTest.java
index e92e721..e9d98ae 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollerTest.java
@@ -16,33 +16,47 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.test.InstrumentationTestCase;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.animation.LinearInterpolator;
 import android.widget.Scroller;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link Scroller}.
  */
-public class ScrollerTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ScrollerTest {
     private Scroller mScroller;
 
     private Context mTargetContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTargetContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mTargetContext = InstrumentationRegistry.getTargetContext();
         mScroller = new Scroller(mTargetContext);
     }
 
+    @Test
     public void testConstructor() {
         new Scroller(mTargetContext);
 
         new Scroller(mTargetContext, new LinearInterpolator());
     }
 
+    @Test
     public void testIsFinished() {
         mScroller.forceFinished(true);
         assertTrue(mScroller.isFinished());
@@ -51,6 +65,7 @@
         assertFalse(mScroller.isFinished());
     }
 
+    @Test
     public void testGetDuration() {
         assertEquals(0, mScroller.getDuration());
 
@@ -70,6 +85,7 @@
         assertTrue(mScroller.getDuration() > 0);
     }
 
+    @Test
     public void testAccessFinalX() {
         assertEquals(0, mScroller.getFinalX());
         assertTrue(mScroller.isFinished());
@@ -84,6 +100,7 @@
         assertFalse(mScroller.isFinished());
     }
 
+    @Test
     public void testAccessFinalY() {
         assertEquals(0, mScroller.getFinalY());
         assertTrue(mScroller.isFinished());
@@ -99,6 +116,8 @@
     }
 
     // We can not get the precise currX and currY when scrolling
+    @LargeTest
+    @Test
     public void testScrollMode() {
         assertEquals(0, mScroller.getFinalX());
         assertEquals(0, mScroller.getFinalY());
@@ -114,11 +133,7 @@
         assertEquals(5000, mScroller.getDuration());
         assertFalse(mScroller.isFinished());
 
-        try {
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(1000);
 
         assertTrue(mScroller.computeScrollOffset());
         // between the start and final position
@@ -131,11 +146,7 @@
         int curX = mScroller.getCurrX();
         int curY = mScroller.getCurrY();
 
-        try {
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(1000);
 
         assertTrue(mScroller.computeScrollOffset());
         // between the start and final position
@@ -148,11 +159,7 @@
         assertTrue(mScroller.getCurrY() < curY);
         assertFalse(mScroller.isFinished());
 
-        try {
-            Thread.sleep(3000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(3000);
 
         assertTrue(mScroller.computeScrollOffset());
         // reach the final position
@@ -164,6 +171,8 @@
     }
 
     // We can not get the precise currX and currY when scrolling
+    @LargeTest
+    @Test
     public void testScrollModeWithDefaultDuration() {
         assertEquals(0, mScroller.getFinalX());
         assertEquals(0, mScroller.getFinalY());
@@ -183,11 +192,7 @@
 
         // the default duration is too short to get fine controlled
         // we just check whether the scroller reaches the destination
-        try {
-            Thread.sleep(defaultDuration);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(defaultDuration);
 
         assertTrue(mScroller.computeScrollOffset());
         // reach the final position
@@ -199,6 +204,8 @@
     }
 
     // We can not get the precise currX and currY when scrolling
+    @LargeTest
+    @Test
     public void testFlingMode() {
         assertEquals(0, mScroller.getFinalX());
         assertEquals(0, mScroller.getFinalY());
@@ -216,11 +223,7 @@
         assertTrue(duration > 0);
         assertFalse(mScroller.isFinished());
 
-        try {
-            Thread.sleep(duration / 3);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(duration / 3);
         assertTrue(mScroller.computeScrollOffset());
 
         int currX = mScroller.getCurrX();
@@ -234,11 +237,7 @@
         assertFalse(mScroller.isFinished());
 
         // wait for the same duration as the last
-        try {
-            Thread.sleep(duration / 3);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(duration / 3);
         assertTrue(mScroller.computeScrollOffset());
 
         int previousX = currX;
@@ -258,11 +257,7 @@
         assertTrue(Math.abs(currY - previousY) < Math.abs(previousY - 0));
 
         // wait until the scroll finishes
-        try {
-            Thread.sleep(duration);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(duration);
         assertTrue(mScroller.computeScrollOffset());
 
         assertEquals(mScroller.getFinalX(), mScroller.getCurrX());
@@ -272,6 +267,7 @@
         assertFalse(mScroller.computeScrollOffset());
     }
 
+    @Test
     public void testAbortAnimation() {
         mScroller.startScroll(0, 0, 2000, -2000, 5000);
         mScroller.computeScrollOffset();
@@ -296,6 +292,8 @@
     }
 
     // We can not get the precise duration after it is extended
+    @LargeTest
+    @Test
     public void testExtendDuration() {
         mScroller.startScroll(0, 0, 0, 0, 5000);
         assertEquals(5000, mScroller.getDuration());
@@ -310,11 +308,7 @@
         mScroller.startScroll(0, 0, 0, 0, 500);
         assertEquals(500, mScroller.getDuration());
 
-        try {
-            Thread.sleep(1500);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(1500);
         // the duration get extended and the scroll get started again, though the animation
         // is forced aborted, can not get the precise duration after it is extended
         mScroller.abortAnimation();
@@ -326,11 +320,7 @@
         mScroller = new Scroller(mTargetContext, new LinearInterpolator());
         mScroller.startScroll(0, 0, 5000, 5000, 5000);
 
-        try {
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(1000);
         mScroller.computeScrollOffset();
         int curX = mScroller.getCurrX();
         int curY = mScroller.getCurrY();
@@ -341,20 +331,14 @@
         assertTrue(mScroller.getCurrY() - curY < curY - 0);
     }
 
+    @LargeTest
+    @Test
     public void testTimePassed() {
-        try {
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(1000);
         // can not get precise time
         assertTrue(mScroller.timePassed() > 1000);
 
-        try {
-            Thread.sleep(2000);
-        } catch (InterruptedException e) {
-            fail("unexpected InterruptedException when sleep");
-        }
+        SystemClock.sleep(2000);
         // can not get precise time
         // time has passed more than 2000 + 1000
         assertTrue(mScroller.timePassed() > 3000);
diff --git a/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
new file mode 100644
index 0000000..5da8a32
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.SearchView;
+
+/**
+ * A minimal application for {@link SearchView} test.
+ */
+public class SearchViewCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..301cea2
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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.assertTrue;
+import static org.mockito.Mockito.anyString;
+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.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+import android.widget.SearchView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link SearchView}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SearchViewTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private SearchView mSearchView;
+
+    @Rule
+    public ActivityTestRule<SearchViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SearchViewCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+    }
+
+    @UiThreadTest
+    @Test
+    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
+    @Test
+    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());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessIconified() {
+        mSearchView.setIconified(true);
+        assertTrue(mSearchView.isIconified());
+
+        mSearchView.setIconified(false);
+        assertFalse(mSearchView.isIconified());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessIconifiedByDefault() {
+        mSearchView.setIconifiedByDefault(true);
+        assertTrue(mSearchView.isIconfiedByDefault());
+
+        mSearchView.setIconifiedByDefault(false);
+        assertFalse(mSearchView.isIconfiedByDefault());
+    }
+
+    @Test
+    public void testDenyIconifyingNonInconifiableView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mSearchView.setIconifiedByDefault(false);
+            mSearchView.setIconified(false);
+        });
+
+        mActivityRule.runOnUiThread(() -> 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());
+    }
+
+    @Test
+    public void testDenyIconifyingInconifiableView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setIconified(false);
+        });
+
+        final SearchView.OnCloseListener mockDenyCloseListener =
+                mock(SearchView.OnCloseListener.class);
+        when(mockDenyCloseListener.onClose()).thenReturn(Boolean.TRUE);
+        mSearchView.setOnCloseListener(mockDenyCloseListener);
+
+        mActivityRule.runOnUiThread(() -> 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());
+    }
+
+    @Test
+    public void testAllowIconifyingInconifiableView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setIconified(false);
+        });
+
+        final SearchView.OnCloseListener mockAllowCloseListener =
+                mock(SearchView.OnCloseListener.class);
+        when(mockAllowCloseListener.onClose()).thenReturn(Boolean.FALSE);
+        mSearchView.setOnCloseListener(mockAllowCloseListener);
+
+        mActivityRule.runOnUiThread(() -> 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());
+    }
+
+    @Test
+    public void testAccessMaxWidth() throws Throwable {
+        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
+        mActivityRule.runOnUiThread(() -> mSearchView.setIconified(false));
+
+        mActivityRule.runOnUiThread(() -> mSearchView.setMaxWidth(maxWidth1));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(maxWidth1, mSearchView.getMaxWidth());
+        assertTrue(mSearchView.getWidth() <= maxWidth1);
+
+        mActivityRule.runOnUiThread(() -> mSearchView.setMaxWidth(maxWidth2));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(maxWidth2, mSearchView.getMaxWidth());
+        assertTrue(mSearchView.getWidth() <= maxWidth2);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessQuery() {
+        mSearchView.setIconified(false);
+
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                mock(SearchView.OnQueryTextListener.class);
+        when(mockQueryTextListener.onQueryTextSubmit(anyString())).thenReturn(Boolean.TRUE);
+        mSearchView.setOnQueryTextListener(mockQueryTextListener);
+
+        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());
+
+        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");
+
+        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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessQueryHint() {
+        mSearchView.setQueryHint("hint 1");
+        assertTrue(TextUtils.equals("hint 1", mSearchView.getQueryHint()));
+
+        mSearchView.setQueryHint("hint 2");
+        assertTrue(TextUtils.equals("hint 2", mSearchView.getQueryHint()));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessInputType() {
+        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());
+
+        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());
+
+        mSearchView.setInputType(InputType.TYPE_CLASS_PHONE);
+        assertEquals(InputType.TYPE_CLASS_PHONE, mSearchView.getInputType());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAccessImeOptions() {
+        mSearchView.setImeOptions(EditorInfo.IME_ACTION_GO);
+        assertEquals(EditorInfo.IME_ACTION_GO, mSearchView.getImeOptions());
+
+        mSearchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        assertEquals(EditorInfo.IME_ACTION_DONE, mSearchView.getImeOptions());
+
+        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..b1523c5
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+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.when;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.BaseColumns;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+import android.widget.CursorAdapter;
+import android.widget.SearchView;
+import android.widget.SimpleCursorAdapter;
+
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link SearchView} with {@link Cursor}-backed suggestions adapter.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SearchView_CursorTest {
+    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;
+        }
+    }
+
+    @Rule
+    public ActivityTestRule<SearchViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SearchViewCtsActivity.class);
+
+    @UiThreadTest
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+
+        // Local test data for the tests
+        mTextContent = new String[] { "Akon", "Bono", "Ciara", "Dido", "Diplo" };
+
+        // 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);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSuggestionFiltering() {
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                spy(new MyQueryTextListener());
+        when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+        mSearchView.setIconifiedByDefault(false);
+        mSearchView.setOnQueryTextListener(mockQueryTextListener);
+        mSearchView.requestFocus();
+
+        assertTrue(mSearchView.hasFocus());
+        assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+        mSearchView.setQuery("Bon", false);
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("Bon");
+
+        mSearchView.setQuery("Di", false);
+        verify(mockQueryTextListener, times(1)).onQueryTextChange("Di");
+    }
+
+    @Test
+    public void testSuggestionSelection() throws Throwable {
+        final SearchView.OnSuggestionListener mockSuggestionListener =
+                spy(new MySuggestionListener());
+        when(mockSuggestionListener.onSuggestionClick(anyInt())).thenCallRealMethod();
+
+        final SearchView.OnQueryTextListener mockQueryTextListener =
+                spy(new MyQueryTextListener());
+        when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+        mActivityRule.runOnUiThread(() -> {
+                    mSearchView.setIconifiedByDefault(false);
+                    mSearchView.setOnQueryTextListener(mockQueryTextListener);
+                    mSearchView.setOnSuggestionListener(mockSuggestionListener);
+                    mSearchView.requestFocus();
+                });
+
+        assertTrue(mSearchView.hasFocus());
+        assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+        mActivityRule.runOnUiThread(() -> 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.emulateTapOnView(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..9395db4 100644
--- a/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SeekBarTest.java
@@ -16,52 +16,73 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+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.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
+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.MotionEvent;
 import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link SeekBar}.
  */
-public class SeekBarTest extends ActivityInstrumentationTestCase2<SeekBarCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SeekBarTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private SeekBar mSeekBar;
 
-    private Activity mActivity;
+    @Rule
+    public ActivityTestRule<SeekBarCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SeekBarCtsActivity.class);
 
-    private Instrumentation mInstrumentation;
-
-    public SeekBarTest() {
-        super("android.widget.cts", SeekBarCtsActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mSeekBar = (SeekBar) mActivity.findViewById(R.id.seekBar);
     }
 
+    @Test
     public void testConstructor() {
         new SeekBar(mActivity);
 
         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);
     }
 
+    @Test
     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 +91,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..3c388fc 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
@@ -16,16 +16,29 @@
 
 package android.widget.cts;
 
-import android.R;
-
+import static org.junit.Assert.assertEquals;
+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.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+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 android.content.Context;
 import android.content.res.Resources.Theme;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -33,7 +46,12 @@
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.TwoLineListItem;
-import android.widget.SimpleAdapter.ViewBinder;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -42,12 +60,14 @@
 /**
  * Test {@link SimpleAdapter}.
  */
-public class SimpleAdapterTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SimpleAdapterTest {
     private static final int DEFAULT_ROW_COUNT = 20;
 
     private static final int DEFAULT_COLUMN_COUNT = 2;
 
-    private static final int[] VIEWS_TO = new int[] { R.id.text1 };
+    private static final int[] VIEWS_TO = new int[] { android.R.id.text1 };
 
     private static final String[] COLUMNS_FROM = new String[] { "column1" };
 
@@ -86,53 +106,54 @@
 
     private LayoutInflater mInflater;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mAdapterHost = (LinearLayout) mInflater.inflate(
-                android.widget.cts.R.layout.cursoradapter_host, null);
+                R.layout.cursoradapter_host, null);
 
         // new the SimpleAdapter instance
         mSimpleAdapter = new SimpleAdapter(mContext,
                 createTestList(DEFAULT_COLUMN_COUNT, DEFAULT_ROW_COUNT),
-                R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
+                android.R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
     }
 
+    @Test
     public void testConstructor() {
         new SimpleAdapter(mContext, createTestList(DEFAULT_COLUMN_COUNT, DEFAULT_ROW_COUNT),
-                R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
+                android.R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
     }
 
+    @Test
     public void testGetCount() {
         mSimpleAdapter = new SimpleAdapter(mContext,
                 createTestList(DEFAULT_COLUMN_COUNT, DEFAULT_ROW_COUNT),
-                R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
+                android.R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
         assertEquals(20, mSimpleAdapter.getCount());
 
         mSimpleAdapter = new SimpleAdapter(mContext, createTestList(DEFAULT_COLUMN_COUNT, 10),
-                R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
+                android.R.layout.simple_list_item_1, COLUMNS_FROM, VIEWS_TO);
         assertEquals(10, mSimpleAdapter.getCount());
     }
 
+    @Test
     public void testGetItem() {
         assertEquals("01", ((Map<?, ?>) mSimpleAdapter.getItem(0)).get("column1"));
         assertEquals("191", ((Map<?, ?>) mSimpleAdapter.getItem(19)).get("column1"));
-
-        try {
-            mSimpleAdapter.getItem(-1);
-            fail("Should throw IndexOutOfBoundsException if index is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleAdapter.getItem(20);
-            fail("Should throw IndexOutOfBoundsException if index is beyond the list's size");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetItemIndexTooLow() {
+        mSimpleAdapter.getItem(-1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetItemIndexTooHigh() {
+        mSimpleAdapter.getItem(20);
+    }
+
+    @Test
     public void testGetItemId() {
         assertEquals(0, mSimpleAdapter.getItemId(0));
 
@@ -144,6 +165,8 @@
         assertEquals(20, mSimpleAdapter.getItemId(20));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetView() {
         // use the layout passed in to constructor
         View result = mSimpleAdapter.getView(0, null, mAdapterHost);
@@ -165,45 +188,50 @@
         result = mSimpleAdapter.getView(10, convertView, null);
         assertEquals("101", ((TextView) result).getText().toString());
 
-        // the binder takes care of binding, the param ViewGroup is never readed
-        MockViewBinder binder = new MockViewBinder(true);
+        // the binder takes care of binding, the param ViewGroup is never read
+        SimpleAdapter.ViewBinder binder = mock(SimpleAdapter.ViewBinder.class);
+        doReturn(true).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
         mSimpleAdapter.setViewBinder(binder);
-        binder.reset();
         mSimpleAdapter.getView(0, null, mAdapterHost);
-        assertTrue(binder.hasCalledSetViewValue());
+        verify(binder, times(1)).setViewValue(any(View.class), eq("01"), anyString());
 
         // binder try binding but fail
-        binder = new MockViewBinder(false);
-        mSimpleAdapter.setViewBinder(binder);
-        binder.reset();
+        doReturn(false).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
+        reset(binder);
         result = mSimpleAdapter.getView(0, null, mAdapterHost);
-        assertTrue(binder.hasCalledSetViewValue());
+        verify(binder, times(1)).setViewValue(any(View.class), eq("01"), anyString());
         assertEquals("01", ((TextView) result).getText().toString());
-
-        try {
-            mSimpleAdapter.getView(-1, convertView, null);
-            fail("Should throw IndexOutOfBoundsException if index is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleAdapter.getView(20, convertView, null);
-            fail("Should throw IndexOutOfBoundsException if index is beyond the list's size");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetViewIndexTooLow() {
+        View result = mSimpleAdapter.getView(0, null, mAdapterHost);
+        mSimpleAdapter.getView(-1, result, null);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetViewIndexTooHigh() {
+        View result = mSimpleAdapter.getView(0, null, mAdapterHost);
+        mSimpleAdapter.getView(20, result, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetDropDownViewResource() {
-        mSimpleAdapter.setDropDownViewResource(R.layout.simple_list_item_2);
+        mSimpleAdapter.setDropDownViewResource(android.R.layout.simple_list_item_2);
         View result = mSimpleAdapter.getDropDownView(0, null, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertEquals("01", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("01",
+                ((TextView) result.findViewById(android.R.id.text1)).getText().toString());
 
         result = mSimpleAdapter.getDropDownView(19, null, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertEquals("191", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("191",
+                ((TextView) result.findViewById(android.R.id.text1)).getText().toString());
 
-        mSimpleAdapter.setDropDownViewResource(R.layout.simple_list_item_1);
+        mSimpleAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1);
         result = mSimpleAdapter.getDropDownView(0, null, mAdapterHost);
         assertTrue(result instanceof TextView);
         assertEquals("01", ((TextView) result).getText().toString());
@@ -213,6 +241,8 @@
         assertEquals("191", ((TextView) result).getText().toString());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetDropDownView() {
         View result = mSimpleAdapter.getDropDownView(0, null, mAdapterHost);
         assertTrue(result instanceof TextView);
@@ -233,51 +263,55 @@
         result = mSimpleAdapter.getDropDownView(10, convertView, null);
         assertEquals("101", ((TextView) result).getText().toString());
 
-        // the binder takes care of binding, the param ViewGroup is never readed
-        MockViewBinder binder = new MockViewBinder(true);
+        // the binder takes care of binding, the param ViewGroup is never read
+        SimpleAdapter.ViewBinder binder = mock(SimpleAdapter.ViewBinder.class);
+        doReturn(true).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
         mSimpleAdapter.setViewBinder(binder);
-        binder.reset();
         mSimpleAdapter.getDropDownView(19, null, mAdapterHost);
-        assertTrue(binder.hasCalledSetViewValue());
+        verify(binder, times(1)).setViewValue(any(View.class), eq("191"), anyString());
 
         // binder try binding but fail
-        binder = new MockViewBinder(false);
-        mSimpleAdapter.setViewBinder(binder);
-        binder.reset();
+        doReturn(false).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
+        reset(binder);
         result = mSimpleAdapter.getDropDownView(19, null, mAdapterHost);
-        assertTrue(binder.hasCalledSetViewValue());
-        assertEquals("191", ((TextView)result).getText().toString());
-
-        try {
-            mSimpleAdapter.getDropDownView(-1, convertView, null);
-            fail("Should throw IndexOutOfBoundsException if index is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleAdapter.getDropDownView(20, convertView, null);
-            fail("Should throw IndexOutOfBoundsException if index is beyond the list's size");
-        } catch (IndexOutOfBoundsException e) {
-        }
+        verify(binder, times(1)).setViewValue(any(View.class), eq("191"), anyString());
+        assertEquals("191", ((TextView) result).getText().toString());
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetDropDownViewIndexTooLow() {
+        View result = mSimpleAdapter.getDropDownView(0, null, mAdapterHost);
+        mSimpleAdapter.getDropDownView(-1, result, null);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetDropDownViewIndexTooHigh() {
+        View result = mSimpleAdapter.getDropDownView(0, null, mAdapterHost);
+        mSimpleAdapter.getDropDownView(20, result, null);
+    }
+
+    @Test
     public void testAccessDropDownViewTheme() {
         Theme theme = mContext.getResources().newTheme();
         mSimpleAdapter.setDropDownViewTheme(theme);
         assertSame(theme, mSimpleAdapter.getDropDownViewTheme());
     }
 
+    @Test
     public void testAccessViewBinder() {
         // no binder default
         assertNull(mSimpleAdapter.getViewBinder());
 
         // binder takes care of binding
-        MockViewBinder binder = new MockViewBinder(true);
+        SimpleAdapter.ViewBinder binder = mock(SimpleAdapter.ViewBinder.class);
+        doReturn(true).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
         mSimpleAdapter.setViewBinder(binder);
         assertSame(binder, mSimpleAdapter.getViewBinder());
 
         // binder try binding but fail
-        binder = new MockViewBinder(false);
+        doReturn(false).when(binder).setViewValue(any(View.class), any(Object.class), anyString());
         mSimpleAdapter.setViewBinder(binder);
         assertSame(binder, mSimpleAdapter.getViewBinder());
 
@@ -285,13 +319,13 @@
         assertNull(mSimpleAdapter.getViewBinder());
     }
 
+    @Test
     public void testSetViewImage() {
         // String represents resId
         ImageView view = new ImageView(mContext);
         assertNull(view.getDrawable());
-        mSimpleAdapter.setViewImage(view, String.valueOf(android.widget.cts.R.drawable.scenery));
-        BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(
-                android.widget.cts.R.drawable.scenery);
+        mSimpleAdapter.setViewImage(view, String.valueOf(R.drawable.scenery));
+        BitmapDrawable d = (BitmapDrawable) mContext.getDrawable(R.drawable.scenery);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) view.getDrawable()).getBitmap());
 
@@ -314,9 +348,8 @@
         // resId
         view = new ImageView(mContext);
         assertNull(view.getDrawable());
-        mSimpleAdapter.setViewImage(view, android.widget.cts.R.drawable.scenery);
-        d = (BitmapDrawable) mContext.getResources()
-                .getDrawable(android.widget.cts.R.drawable.scenery);
+        mSimpleAdapter.setViewImage(view, R.drawable.scenery);
+        d = (BitmapDrawable) mContext.getDrawable(R.drawable.scenery);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) view.getDrawable()).getBitmap());
 
@@ -331,17 +364,19 @@
         assertNull(view.getDrawable());
         try {
             mSimpleAdapter.setViewImage(view, SimpleCursorAdapterTest.createTestImage(mContext,
-                    "testimage", android.widget.cts.R.raw.testimage));
+                    "testimage", R.raw.testimage));
             assertNotNull(view.getDrawable());
             Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
-            Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
-                    android.widget.cts.R.raw.testimage, actualBitmap.getConfig());
+            Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
+                    mContext.getResources(), R.raw.testimage, actualBitmap.getConfig());
             WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
         } finally {
             SimpleCursorAdapterTest.destroyTestImage(mContext,"testimage");
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testSetViewText() {
         TextView view = new TextView(mContext);
         mSimpleAdapter.setViewText(view, "expected");
@@ -352,6 +387,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetFilter() {
         assertNotNull(mSimpleAdapter.getFilter());
     }
@@ -367,14 +403,14 @@
      *         column1=>21} }
      */
     private ArrayList<HashMap<String, String>> createTestList(int colCount, int rowCount) {
-        ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
+        ArrayList<HashMap<String, String>> list = new ArrayList<>();
         String[] columns = new String[colCount];
         for (int i = 0; i < colCount; i++) {
             columns[i] = "column" + i;
         }
 
         for (int i = 0; i < rowCount; i++) {
-            HashMap<String, String> row = new HashMap<String, String>();
+            HashMap<String, String> row = new HashMap<>();
             for (int j = 0; j < colCount; j++) {
                 row.put(columns[j], "" + i + "" + j);
             }
@@ -383,27 +419,4 @@
 
         return list;
     }
-
-    private class MockViewBinder implements ViewBinder {
-        private boolean mExpectedResult;
-
-        private boolean mHasCalledSetViewValue;
-
-        public MockViewBinder(boolean expectedResult) {
-            mExpectedResult = expectedResult;
-        }
-
-        public void reset(){
-            mHasCalledSetViewValue = false;
-        }
-
-        public boolean hasCalledSetViewValue() {
-            return mHasCalledSetViewValue;
-        }
-
-        public boolean setViewValue(View view, Object data, String textRepresentation) {
-            mHasCalledSetViewValue = true;
-            return mExpectedResult;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
index 469e581..880da98 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
@@ -16,17 +16,29 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+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 android.content.Context;
-import android.cts.util.WidgetTestUtils;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -34,8 +46,12 @@
 import android.widget.LinearLayout;
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
-import android.widget.SimpleCursorAdapter.CursorToStringConverter;
-import android.widget.SimpleCursorAdapter.ViewBinder;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -47,7 +63,9 @@
  * {@link SimpleCursorAdapterTest#mCursor} It will use internal
  * R.layout.simple_list_item_1.
  */
-public class SimpleCursorAdapterTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SimpleCursorAdapterTest {
     private static final int ADAPTER_ROW_COUNT = 20;
 
     private static final int DEFAULT_COLUMN_COUNT = 2;
@@ -88,10 +106,9 @@
      */
     private Cursor mCursor;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
 
         mCursor = createTestCursor(DEFAULT_COLUMN_COUNT, ADAPTER_ROW_COUNT);
     }
@@ -102,6 +119,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new SimpleCursorAdapter(mContext, R.layout.cursoradapter_item0,
                 createTestCursor(DEFAULT_COLUMN_COUNT, ADAPTER_ROW_COUNT),
@@ -109,6 +127,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testBindView() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         TextView listItem = (TextView) simpleCursorAdapter.newView(mContext, null, null);
@@ -124,20 +143,20 @@
 
         // the binder take care of binding
         listItem.setText("");
-        MockViewBinder binder = new MockViewBinder(true);
+        SimpleCursorAdapter.ViewBinder binder = mock(SimpleCursorAdapter.ViewBinder.class);
+        doReturn(true).when(binder).setViewValue(any(View.class), any(Cursor.class), anyInt());
         simpleCursorAdapter.setViewBinder(binder);
-        binder.reset();
         mCursor.moveToFirst();
         simpleCursorAdapter.bindView(listItem, null, mCursor);
-        assertTrue(binder.hasCalledSetViewValueCalledCount());
+        verify(binder, times(1)).setViewValue(any(View.class), eq(mCursor), eq(1));
         assertEquals("", listItem.getText().toString());
 
         // the binder try to bind but fail
-        binder = new MockViewBinder(false);
-        simpleCursorAdapter.setViewBinder(binder);
+        doReturn(false).when(binder).setViewValue(any(View.class), any(Cursor.class), anyInt());
+        reset(binder);
         mCursor.moveToLast();
         simpleCursorAdapter.bindView(listItem, null, mCursor);
-        assertTrue(binder.hasCalledSetViewValueCalledCount());
+        verify(binder, times(1)).setViewValue(any(View.class), eq(mCursor), eq(1));
         assertEquals("191", listItem.getText().toString());
 
         final int [] to = { R.id.cursorAdapter_host };
@@ -154,15 +173,17 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessViewBinder() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         assertNull(simpleCursorAdapter.getViewBinder());
 
-        MockViewBinder binder = new MockViewBinder(true);
+        SimpleCursorAdapter.ViewBinder binder = mock(SimpleCursorAdapter.ViewBinder.class);
+        doReturn(true).when(binder).setViewValue(any(View.class), any(Cursor.class), anyInt());
         simpleCursorAdapter.setViewBinder(binder);
         assertSame(binder, simpleCursorAdapter.getViewBinder());
 
-        binder = new MockViewBinder(false);
+        doReturn(false).when(binder).setViewValue(any(View.class), any(Cursor.class), anyInt());
         simpleCursorAdapter.setViewBinder(binder);
         assertSame(binder, simpleCursorAdapter.getViewBinder());
 
@@ -171,6 +192,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetViewText() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         TextView view = new TextView(mContext);
@@ -182,10 +204,11 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetViewImage() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         // resId
-        int sceneryImgResId = android.widget.cts.R.drawable.scenery;
+        int sceneryImgResId = R.drawable.scenery;
         ImageView view = new ImageView(mContext);
         assertNull(view.getDrawable());
         simpleCursorAdapter.setViewImage(view, String.valueOf(sceneryImgResId));
@@ -216,13 +239,13 @@
         view = new ImageView(mContext);
         assertNull(view.getDrawable());
         try {
-            int testimgRawId = android.widget.cts.R.raw.testimage;
+            int testimgRawId = R.raw.testimage;
             simpleCursorAdapter.setViewImage(view,
                     createTestImage(mContext, SAMPLE_IMAGE_NAME, testimgRawId));
             assertNotNull(view.getDrawable());
             Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
-            Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
-                    testimgRawId, actualBitmap.getConfig());
+            Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
+                    mContext.getResources(), testimgRawId, actualBitmap.getConfig());
             WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
         } finally {
             destroyTestImage(mContext, SAMPLE_IMAGE_NAME);
@@ -230,6 +253,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessStringConversionColumn() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         // default is -1
@@ -248,12 +272,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessCursorToStringConverter() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         // default is null
         assertNull(simpleCursorAdapter.getCursorToStringConverter());
 
-        CursorToStringConverter converter = new MockCursorToStringConverter();
+        SimpleCursorAdapter.CursorToStringConverter converter =
+                mock(SimpleCursorAdapter.CursorToStringConverter.class);
         simpleCursorAdapter.setCursorToStringConverter(converter);
         assertSame(converter, simpleCursorAdapter.getCursorToStringConverter());
 
@@ -262,6 +288,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testChangeCursor() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         // have "column1"
@@ -281,6 +308,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testConvertToString() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         mCursor.moveToFirst();
@@ -313,21 +341,22 @@
         assertEquals("02", simpleCursorAdapter.convertToString(curWith3Columns));
 
         // converter is not null, StringConversionColumn is 1
-        CursorToStringConverter converter = new MockCursorToStringConverter();
+        SimpleCursorAdapter.CursorToStringConverter converter =
+                mock(SimpleCursorAdapter.CursorToStringConverter.class);
         simpleCursorAdapter.setCursorToStringConverter(converter);
         simpleCursorAdapter.setStringConversionColumn(1);
-        ((MockCursorToStringConverter) converter).reset();
         simpleCursorAdapter.convertToString(curWith3Columns);
-        assertTrue(((MockCursorToStringConverter) converter).hasCalledConvertToString());
+        verify(converter, times(1)).convertToString(curWith3Columns);
     }
 
     @UiThreadTest
+    @Test
     public void testNewView() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
-                android.widget.cts.R.layout.cursoradapter_host, null);
+                R.layout.cursoradapter_host, null);
         View result = simpleCursorAdapter.newView(mContext, null, viewGroup);
         assertNotNull(result);
         assertEquals(R.id.cursorAdapter_item0, result.getId());
@@ -338,18 +367,20 @@
     }
 
     @UiThreadTest
+    @Test
     public void testNewDropDownView() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
-                android.widget.cts.R.layout.cursoradapter_host, null);
+                R.layout.cursoradapter_host, null);
         View result = simpleCursorAdapter.newDropDownView(null, null, viewGroup);
         assertNotNull(result);
         assertEquals(R.id.cursorAdapter_item0, result.getId());
     }
 
     @UiThreadTest
+    @Test
     public void testChangeCursorAndColumns() {
         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
         assertSame(mCursor, simpleCursorAdapter.getCursor());
@@ -407,54 +438,15 @@
         return cursor;
     }
 
-    private static class MockViewBinder implements ViewBinder {
-        private boolean mExpectedResult;
-
-        private boolean mHasCalledSetViewValue;
-
-        public MockViewBinder(boolean expectedResult) {
-            mExpectedResult = expectedResult;
-        }
-
-        public void reset(){
-            mHasCalledSetViewValue = false;
-        }
-
-        public boolean hasCalledSetViewValueCalledCount() {
-            return mHasCalledSetViewValue;
-        }
-
-        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
-            mHasCalledSetViewValue = true;
-            return mExpectedResult;
-        }
-    }
-
     public static String createTestImage(Context context, String fileName, int resId) {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = context.getResources().openRawResource(resId);
-            target = context.openFileOutput(fileName, Context.MODE_PRIVATE);
-
+        try (InputStream source = context.getResources().openRawResource(resId);
+             OutputStream target = context.openFileOutput(fileName, Context.MODE_PRIVATE)) {
             byte[] buffer = new byte[1024];
             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
                 target.write(buffer, 0, len);
             }
         } catch (IOException e) {
             fail(e.getMessage());
-        } finally {
-            try {
-                if (source != null) {
-                    source.close();
-                }
-                if (target != null) {
-                    target.close();
-                }
-            } catch (IOException e) {
-                // Ignore the IOException.
-            }
         }
 
         return context.getFileStreamPath(fileName).getAbsolutePath();
@@ -463,21 +455,4 @@
     public static void destroyTestImage(Context context, String fileName) {
         context.deleteFile(fileName);
     }
-
-    private static class MockCursorToStringConverter implements CursorToStringConverter {
-        private boolean mHasCalledConvertToString;
-
-        public boolean hasCalledConvertToString() {
-            return mHasCalledConvertToString;
-        }
-
-        public void reset(){
-            mHasCalledConvertToString = false;
-        }
-
-        public CharSequence convertToString(Cursor cursor) {
-            mHasCalledConvertToString = true;
-            return null;
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
index 02941fa..fefd261 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
@@ -16,26 +16,36 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.cts.util.WidgetTestUtils;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.SimpleCursorTreeAdapter;
 import android.widget.TextView;
 
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link SimpleCursorTreeAdapter}.
  */
-public class SimpleCursorTreeAdapterTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SimpleCursorTreeAdapterTest {
     private static final int GROUP_LAYOUT = R.layout.cursoradapter_group0;
 
     private static final int CHILD_LAYOUT = R.layout.cursoradapter_item0;
@@ -66,13 +76,13 @@
 
     private Cursor mChildCursor;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         mGroupCursor = createTestCursor(2, 20, "group");
         new MockSimpleCursorTreeAdapter(mContext, mGroupCursor,
@@ -89,6 +99,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testBindChildView() {
         mGroupCursor = createTestCursor(2, 20, "group");
         mChildCursor = createTestCursor(3, 4, "child");
@@ -107,8 +118,9 @@
         assertEquals("child12", view.getText().toString());
     }
 
-    // The param context and isExpanded is never readed.
+    // The param context and isExpanded is never read.
     @UiThreadTest
+    @Test
     public void testBindGroupView() {
         mGroupCursor = createTestCursor(2, 20, "group");
         mGroupCursor.moveToFirst();
@@ -126,6 +138,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetViewImage() {
         mGroupCursor = createTestCursor(2, 20, "group");
         mSimpleCursorTreeAdapter = new MockSimpleCursorTreeAdapter(mContext, mGroupCursor,
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
index 674f427..eef0a49 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleExpandableListAdapterTest.java
@@ -16,41 +16,50 @@
 
 package android.widget.cts;
 
-import android.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.test.InstrumentationTestCase;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.SimpleExpandableListAdapter;
 import android.widget.TextView;
 import android.widget.TwoLineListItem;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 
 /**
  * Test {@link SimpleExpandableListAdapter}.
  */
-public class SimpleExpandableListAdapterTest extends InstrumentationTestCase {
-    private static final int EXPANDED_GROUP_LAYOUT = R.layout.simple_expandable_list_item_2;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SimpleExpandableListAdapterTest {
+    private static final int EXPANDED_GROUP_LAYOUT = android.R.layout.simple_expandable_list_item_2;
 
-    private static final int LAST_CHILD_LAYOUT = R.layout.simple_list_item_2;
+    private static final int LAST_CHILD_LAYOUT = android.R.layout.simple_list_item_2;
 
-    private static final int CHILD_LAYOUT = R.layout.simple_list_item_1;
+    private static final int CHILD_LAYOUT = android.R.layout.simple_list_item_1;
 
-    private static final int GROUP_LAYOUT = R.layout.simple_expandable_list_item_1;
+    private static final int GROUP_LAYOUT = android.R.layout.simple_expandable_list_item_1;
 
     private static final int[] VIEWS_GROUP_TO = new int[] {
-        R.id.text1
+            android.R.id.text1
     };
 
     private static final int[] VIEWS_CHILD_TO = new int[] {
-        R.id.text1
+            android.R.id.text1
     };
 
     private static final String[] COLUMNS_GROUP_FROM = new String[] {
@@ -80,17 +89,16 @@
 
     private LinearLayout mAdapterHost;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
         mSimpleExpandableListAdapter = null;
         mGroupList = createTestList(1, 4, "group");
-        mChildList = new ArrayList<ArrayList<HashMap<String, String>>>();
+        mChildList = new ArrayList<>();
         for (int i = 0; i < 4; i++) {
             ArrayList<HashMap<String, String>> l = createTestList(1, i + 1, "child");
             mChildList.add(l);
         }
-        mContext = getInstrumentation().getTargetContext();
 
         mSimpleExpandableListAdapter = new SimpleExpandableListAdapter(mContext,
                 mGroupList, GROUP_LAYOUT, COLUMNS_GROUP_FROM, VIEWS_GROUP_TO,
@@ -98,9 +106,10 @@
 
         mAdapterHost = (LinearLayout) ((LayoutInflater) mContext
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
-                android.widget.cts.R.layout.cursoradapter_host, null);
+                R.layout.cursoradapter_host, null);
     }
 
+    @Test
     public void testConstructor() {
         new SimpleExpandableListAdapter(mContext,
                 mGroupList, GROUP_LAYOUT, COLUMNS_GROUP_FROM, VIEWS_GROUP_TO,
@@ -118,40 +127,42 @@
                 COLUMNS_CHILD_FROM, VIEWS_CHILD_TO);
     }
 
+    @Test
     public void testGetChild() {
-        HashMap<String, String> expected = new HashMap<String, String>();
+        HashMap<String, String> expected = new HashMap<>();
         expected.put("column0", "child00");
         assertEquals(expected, mSimpleExpandableListAdapter.getChild(0, 0));
 
         expected = new HashMap<String, String>();
         expected.put("column0", "child30");
         assertEquals(expected, mSimpleExpandableListAdapter.getChild(3, 3));
-
-        try {
-            mSimpleExpandableListAdapter.getChild(-1, 0);
-            fail("Should throw exception if group position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChild(0, -1);
-            fail("Should throw exception if child position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChild(4, 0);
-            fail("Should throw exception if group position is beyond the group list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChild(0, 1);
-            fail("Should throw exception if child position is beyond the child list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildGroupPositionTooLow() {
+        mSimpleExpandableListAdapter.getChild(-1, 0);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildGroupPositionTooHigh() {
+        mSimpleExpandableListAdapter.getChild(4, 0);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildChildPositionTooLow() {
+        mSimpleExpandableListAdapter.getChild(0, -1);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildChildPositionTooHigh() {
+        mSimpleExpandableListAdapter.getChild(0, 1);
+    }
+
+    @Test
     public void testGetChildId() {
         assertEquals(0, mSimpleExpandableListAdapter.getChildId(0, 0));
         assertEquals(3, mSimpleExpandableListAdapter.getChildId(3, 3));
@@ -163,15 +174,17 @@
         assertEquals(4, mSimpleExpandableListAdapter.getChildId(0, 4));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetChildView() {
         // the normal and last use same layout
         View result = mSimpleExpandableListAdapter.getChildView(0, 0, false, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("child00", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("child00", ((TextView) result).getText().toString());
 
         result = mSimpleExpandableListAdapter.getChildView(3, 3, true, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("child30", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("child30", ((TextView) result).getText().toString());
 
         // the normal and last use different layouts
         mSimpleExpandableListAdapter = new SimpleExpandableListAdapter(mContext,
@@ -182,60 +195,63 @@
 
         result = mSimpleExpandableListAdapter.getChildView(0, 0, false, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("child00", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("child00", ((TextView) result).getText().toString());
 
         result = mSimpleExpandableListAdapter.getChildView(3, 3, true, null, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertEquals("child30", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("child30",
+                ((TextView) result.findViewById(android.R.id.text1)).getText().toString());
 
         // use convert view
         View convertView = new TextView(mContext);
-        convertView.setId(R.id.text1);
+        convertView.setId(android.R.id.text1);
         result = mSimpleExpandableListAdapter.getChildView(2, 2, false, convertView, mAdapterHost);
         assertSame(convertView, result);
         assertEquals("child20", ((TextView) result).getText().toString());
 
         // the parent can be null
         convertView = new TextView(mContext);
-        convertView.setId(R.id.text1);
+        convertView.setId(android.R.id.text1);
         result = mSimpleExpandableListAdapter.getChildView(1, 1, false, convertView, null);
         assertSame(convertView, result);
         assertEquals("child10", ((TextView) result).getText().toString());
-
-        try {
-            mSimpleExpandableListAdapter.getChildView(-1, 0, false, null, mAdapterHost);
-            fail("Should throw exception if group position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChildView(0, -1, false, null, mAdapterHost);
-            fail("Should throw exception if child position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChildView(4, 0, false, null, mAdapterHost);
-            fail("Should throw exception if group position is beyond the group list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChildView(0, 1, false, null, mAdapterHost);
-            fail("Should throw exception if child position is beyond the child list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildViewGroupPositionTooLow() {
+        mSimpleExpandableListAdapter.getChildView(-1, 0, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildViewGroupPositionTooHigh() {
+        mSimpleExpandableListAdapter.getChildView(4, 0, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildViewChildPositionTooLow() {
+        mSimpleExpandableListAdapter.getChildView(0, -1, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildViewChildPositionTooHigh() {
+        mSimpleExpandableListAdapter.getChildView(0, 1, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test
     public void testNewChildView() {
         // the normal and last use same layout
         View result = mSimpleExpandableListAdapter.newChildView(false, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         result = mSimpleExpandableListAdapter.newChildView(true, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         // the normal and last use different layouts
         mSimpleExpandableListAdapter = new SimpleExpandableListAdapter(mContext,
@@ -246,54 +262,53 @@
 
         result = mSimpleExpandableListAdapter.newChildView(false, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         result = mSimpleExpandableListAdapter.newChildView(true, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
     }
 
+    @Test
     public void testGetChildrenCount() {
         assertEquals(1, mSimpleExpandableListAdapter.getChildrenCount(0));
         assertEquals(2, mSimpleExpandableListAdapter.getChildrenCount(1));
         assertEquals(3, mSimpleExpandableListAdapter.getChildrenCount(2));
         assertEquals(4, mSimpleExpandableListAdapter.getChildrenCount(3));
-
-        try {
-            mSimpleExpandableListAdapter.getChildrenCount(-1);
-            fail("Should throw exception if group position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getChildrenCount(4);
-            fail("Should throw exception if group position is beyond the group list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildrenCountGroupPositionTooLow() {
+        mSimpleExpandableListAdapter.getChildrenCount(-1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetChildrenCountGroupPositionTooHigh() {
+        mSimpleExpandableListAdapter.getChildrenCount(4);
+    }
+
+    @Test
     public void testGetGroup() {
-        HashMap<String, String> expected = new HashMap<String, String>();
+        HashMap<String, String> expected = new HashMap<>();
         expected.put("column0", "group00");
         assertEquals(expected, mSimpleExpandableListAdapter.getGroup(0));
 
-        expected = new HashMap<String, String>();
+        expected = new HashMap<>();
         expected.put("column0", "group30");
         assertEquals(expected, mSimpleExpandableListAdapter.getGroup(3));
-
-        try {
-            mSimpleExpandableListAdapter.getGroup(-1);
-            fail("Should throw exception if group position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getGroup(4);
-            fail("Should throw exception if group position is beyond the group list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetGroupGroupPositionTooLow() {
+        mSimpleExpandableListAdapter.getGroup(-1);
+    }
+
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetGroupGroupPositionTooHigh() {
+        mSimpleExpandableListAdapter.getGroup(4);
+    }
+
+    @Test
     public void testGetGroupCount() {
         assertEquals(4, mSimpleExpandableListAdapter.getGroupCount());
 
@@ -303,6 +318,7 @@
         assertEquals(9, mSimpleExpandableListAdapter.getGroupCount());
     }
 
+    @Test
     public void testGetGroupId() {
         assertEquals(0, mSimpleExpandableListAdapter.getGroupId(0));
         assertEquals(3, mSimpleExpandableListAdapter.getGroupId(3));
@@ -312,15 +328,17 @@
         assertEquals(4, mSimpleExpandableListAdapter.getGroupId(4));
     }
 
+    @UiThreadTest
+    @Test
     public void testGetGroupView() {
         // the collapsed and expanded use same layout
         View result = mSimpleExpandableListAdapter.getGroupView(0, false, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("group00", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("group00", ((TextView) result).getText().toString());
 
         result = mSimpleExpandableListAdapter.getGroupView(3, true, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("group30", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("group30", ((TextView) result).getText().toString());
 
         // the collapsed and expanded use different layouts
         mSimpleExpandableListAdapter = new SimpleExpandableListAdapter(mContext,
@@ -331,48 +349,51 @@
 
         result = mSimpleExpandableListAdapter.getGroupView(0, true, null, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertEquals("group00", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("group00", ((TextView) result).getText().toString());
 
         result = mSimpleExpandableListAdapter.getGroupView(3, false, null, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertEquals("group30", ((TextView) result.findViewById(R.id.text1)).getText().toString());
+        assertEquals("group30",
+                ((TextView) result.findViewById(android.R.id.text1)).getText().toString());
 
         // use convert view
         View convertView = new TextView(mContext);
-        convertView.setId(R.id.text1);
+        convertView.setId(android.R.id.text1);
         result = mSimpleExpandableListAdapter.getGroupView(2, false, convertView, mAdapterHost);
         assertSame(convertView, result);
         assertEquals("group20", ((TextView) result).getText().toString());
 
         // the parent can be null
         convertView = new TextView(mContext);
-        convertView.setId(R.id.text1);
+        convertView.setId(android.R.id.text1);
         result = mSimpleExpandableListAdapter.getGroupView(1, false, convertView, null);
         assertSame(convertView, result);
         assertEquals("group10", ((TextView) result).getText().toString());
-
-        try {
-            mSimpleExpandableListAdapter.getGroupView(-1, false, null, mAdapterHost);
-            fail("Should throw exception if group position is negative");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            mSimpleExpandableListAdapter.getGroupView(4, false, null, mAdapterHost);
-            fail("Should throw exception if group position is beyond the group list'szie");
-        } catch (IndexOutOfBoundsException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetGroupViewGroupPositionTooLow() {
+        mSimpleExpandableListAdapter.getGroupView(-1, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testGetGroupViewGroupPositionTooHigh() {
+        mSimpleExpandableListAdapter.getGroupView(4, false, null, mAdapterHost);
+    }
+
+    @UiThreadTest
+    @Test
     public void testNewGroupView() {
         // the collapsed and expanded use same layout
         View result = mSimpleExpandableListAdapter.newGroupView(false, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         result = mSimpleExpandableListAdapter.newGroupView(true, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         // the collapsed and expanded use different layouts
         mSimpleExpandableListAdapter = new SimpleExpandableListAdapter(mContext,
@@ -383,13 +404,14 @@
 
         result = mSimpleExpandableListAdapter.newGroupView(true, mAdapterHost);
         assertTrue(result instanceof TextView);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
 
         result = mSimpleExpandableListAdapter.newGroupView(false, mAdapterHost);
         assertTrue(result instanceof TwoLineListItem);
-        assertNotNull(result.findViewById(R.id.text1));
+        assertNotNull(result.findViewById(android.R.id.text1));
     }
 
+    @Test
     public void testIsChildSelectable() {
         assertTrue(mSimpleExpandableListAdapter.isChildSelectable(0, 0));
         assertTrue(mSimpleExpandableListAdapter.isChildSelectable(3, 3));
@@ -401,6 +423,7 @@
         assertTrue(mSimpleExpandableListAdapter.isChildSelectable(0, 1));
     }
 
+    @Test
     public void testHasStableIds() {
         assertTrue(mSimpleExpandableListAdapter.hasStableIds());
     }
@@ -415,14 +438,14 @@
      */
     private ArrayList<HashMap<String, String>> createTestList(int colCount, int rowCount,
             String prefix) {
-        ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
+        ArrayList<HashMap<String, String>> list = new ArrayList<>();
         String[] columns = new String[colCount];
         for (int i = 0; i < colCount; i++) {
             columns[i] = "column" + i;
         }
 
         for (int i = 0; i < rowCount; i++) {
-            HashMap<String, String> row = new HashMap<String, String>();
+            HashMap<String, String> row = new HashMap<>();
             for (int j = 0; j < colCount; j++) {
                 row.put(columns[j], prefix + i + "" + j);
             }
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..1993244 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
@@ -16,52 +16,70 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
 
-
-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.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.inOrder;
+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.app.Activity;
-import android.content.Context;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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 com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 
 /**
  * Test {@link SlidingDrawer}.
  */
-public class SlidingDrawerTest
-        extends ActivityInstrumentationTestCase2<SlidingDrawerCtsActivity> {
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SlidingDrawerTest {
     private static final long TEST_TIMEOUT = 5000L;
+
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
-    private Object mLock;
+    private SlidingDrawer mDrawer;
 
-    public SlidingDrawerTest() {
-        super("android.widget.cts", SlidingDrawerCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<SlidingDrawerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SlidingDrawerCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mLock = new Object();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mDrawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() throws XmlPullParserException, IOException {
         XmlPullParser parser = mActivity.getResources().getLayout(R.layout.sliding_drawer_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -81,304 +99,173 @@
         }
     }
 
+    @Test
     public void testGetHandle() {
-        SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View handle = drawer.getHandle();
+        View handle = mDrawer.getHandle();
         assertTrue(handle instanceof ImageView);
         assertEquals(R.id.handle, handle.getId());
     }
 
+    @Test
     public void testGetContent() {
-        SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View content = drawer.getContent();
+        View content = mDrawer.getContent();
         assertTrue(content instanceof TextView);
         assertEquals(R.id.content, content.getId());
     }
 
     @UiThreadTest
+    @Test
     public void testOpenAndClose() {
-        SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View content = drawer.getContent();
-        assertFalse(drawer.isOpened());
+        View content = mDrawer.getContent();
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        drawer.open();
-        assertTrue(drawer.isOpened());
+        mDrawer.open();
+        assertTrue(mDrawer.isOpened());
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        drawer.close();
-        assertFalse(drawer.isOpened());
+        mDrawer.close();
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
     }
 
+    @Test
     public void testAnimateOpenAndClose() throws Throwable {
-        final SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View content = drawer.getContent();
-        assertFalse(drawer.isMoving());
-        assertFalse(drawer.isOpened());
+        View content = mDrawer.getContent();
+        assertFalse(mDrawer.isMoving());
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateOpen();
-            }
-        });
-        assertTrue(drawer.isMoving());
-        assertOpened(false, drawer);
+        mActivityRule.runOnUiThread(mDrawer::animateOpen);
+        assertTrue(mDrawer.isMoving());
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(true, drawer);
+        PollingCheck.waitFor(() -> !mDrawer.isMoving());
+        PollingCheck.waitFor(mDrawer::isOpened);
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateClose();
-            }
-        });
-        assertTrue(drawer.isMoving());
-        assertOpened(true, drawer);
+        mActivityRule.runOnUiThread(mDrawer::animateClose);
+        assertTrue(mDrawer.isMoving());
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(false, drawer);
+        PollingCheck.waitFor(() -> !mDrawer.isMoving());
+        PollingCheck.waitFor(() -> !mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
     }
 
+    @Test
     public void testAnimateToggle() throws Throwable {
-        final SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View content = drawer.getContent();
-        assertFalse(drawer.isMoving());
-        assertFalse(drawer.isOpened());
+        View content = mDrawer.getContent();
+        assertFalse(mDrawer.isMoving());
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateToggle();
-            }
-        });
-        assertTrue(drawer.isMoving());
-        assertOpened(false, drawer);
+        mActivityRule.runOnUiThread(mDrawer::animateToggle);
+        assertTrue(mDrawer.isMoving());
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(true, drawer);
+        PollingCheck.waitFor(() -> !mDrawer.isMoving());
+        PollingCheck.waitFor(mDrawer::isOpened);
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                drawer.animateToggle();
-            }
-        });
-        assertTrue(drawer.isMoving());
-        assertOpened(true, drawer);
+        mActivityRule.runOnUiThread(mDrawer::animateToggle);
+        assertTrue(mDrawer.isMoving());
         assertEquals(View.GONE, content.getVisibility());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return !drawer.isMoving();
-            }
-        }.run();
-        assertOpened(false, drawer);
+        PollingCheck.waitFor(() -> !mDrawer.isMoving());
+        PollingCheck.waitFor(() -> !mDrawer.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
+    @Test
     public void testToggle() {
-        SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View content = drawer.getContent();
-        assertFalse(drawer.isOpened());
+        View content = mDrawer.getContent();
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        drawer.toggle();
-        assertTrue(drawer.isOpened());
+        mDrawer.toggle();
+        assertTrue(mDrawer.isOpened());
         assertEquals(View.VISIBLE, content.getVisibility());
 
-        drawer.toggle();
-        assertFalse(drawer.isOpened());
+        mDrawer.toggle();
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
     }
 
     @UiThreadTest
+    @Test
     public void testLockAndUnlock() {
-        SlidingDrawer drawer = (SlidingDrawer) mActivity.findViewById(R.id.drawer);
-        View handle = drawer.getHandle();
-        View content = drawer.getContent();
-        assertFalse(drawer.isOpened());
+        View handle = mDrawer.getHandle();
+        View content = mDrawer.getContent();
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
         handle.performClick();
-        assertTrue(drawer.isOpened());
+        assertTrue(mDrawer.isOpened());
         assertEquals(View.VISIBLE, content.getVisibility());
 
         handle.performClick();
-        assertFalse(drawer.isOpened());
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        drawer.lock();
+        mDrawer.lock();
         handle.performClick();
-        assertFalse(drawer.isOpened());
+        assertFalse(mDrawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        drawer.unlock();
+        mDrawer.unlock();
         handle.performClick();
-        assertTrue(drawer.isOpened());
+        assertTrue(mDrawer.isOpened());
         assertEquals(View.VISIBLE, content.getVisibility());
     }
 
     @UiThreadTest
+    @Test
     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);
+        mDrawer.setOnDrawerOpenListener(mockOpenListener);
 
-        assertFalse(listener.hadOpenedDrawer());
+        verifyZeroInteractions(mockOpenListener);
 
-        drawer.open();
-        assertTrue(listener.hadOpenedDrawer());
+        mDrawer.open();
+        verify(mockOpenListener, times(1)).onDrawerOpened();
     }
 
     @UiThreadTest
+    @Test
     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);
+        mDrawer.setOnDrawerCloseListener(mockCloseListener);
 
-        assertFalse(listener.hadClosedDrawer());
+        verifyZeroInteractions(mockCloseListener);
 
-        drawer.open();
-        assertFalse(listener.hadClosedDrawer());
+        mDrawer.open();
+        verifyZeroInteractions(mockCloseListener);
 
-        drawer.close();
-        assertTrue(listener.hadClosedDrawer());
+        mDrawer.close();
+        verify(mockCloseListener, times(1)).onDrawerClosed();
     }
 
-    public void testSetOnDrawerScrollListener() throws Throwable {
+    @UiThreadTest
+    @Test
+    public void testSetOnDrawerScrollListener() {
         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 SlidingDrawer.OnDrawerScrollListener mockScrollListener =
+                mock(SlidingDrawer.OnDrawerScrollListener.class);
+        drawer.setOnDrawerScrollListener(mockScrollListener);
 
-        if ( !listener.hadEndedScroll() ) {
-            synchronized (mLock) {
-                mLock.wait(TEST_TIMEOUT);
-            }
-        }
-        assertTrue(listener.hadStartedScroll());
-        assertTrue(listener.hadEndedScroll());
-    }
+        drawer.animateOpen();
 
-    public void testOnLayout() {
-        // onLayout() is implementation details, do NOT test
-    }
+        verify(mockScrollListener, within(TEST_TIMEOUT)).onScrollStarted();
+        verify(mockScrollListener, within(TEST_TIMEOUT)).onScrollEnded();
 
-    public void testOnMeasure() {
-        // onMeasure() is implementation details, do NOT test
-    }
-
-    public void testOnFinishInflate() {
-        // onFinishInflate() is implementation details, do NOT test
-    }
-
-    public void testDispatchDraw() {
-        // dispatchDraw() is implementation details, do NOT test
-    }
-
-    public void testOnInterceptTouchEvent() {
-        // onInterceptTouchEvent() is implementation details, do NOT test
-    }
-
-    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;
-        }
+        InOrder inOrder = inOrder(mockScrollListener);
+        inOrder.verify(mockScrollListener).onScrollStarted();
+        inOrder.verify(mockScrollListener).onScrollEnded();
+        verifyNoMoreInteractions(mockScrollListener);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
new file mode 100644
index 0000000..16fb30e
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.Spinner;
+
+/**
+ * A minimal application for {@link Spinner} test.
+ */
+public class SpinnerCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..9aebd71 100644
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -16,101 +16,184 @@
 
 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.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
-
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.content.Context;
+import android.app.Instrumentation;
+import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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;
+
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Spinner}.
  */
-public class SpinnerTest extends ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
-    private Context mTargetContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SpinnerTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private Spinner mSpinnerDialogMode;
+    private Spinner mSpinnerDropdownMode;
 
-    public SpinnerTest() {
-        super("android.widget.cts", RelativeLayoutCtsActivity.class);
+    @Rule
+    public ActivityTestRule<SpinnerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SpinnerCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mSpinnerDialogMode = (Spinner) mActivity.findViewById(R.id.spinner_dialog_mode);
+        mSpinnerDropdownMode = (Spinner) mActivity.findViewById(R.id.spinner_dropdown_mode);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTargetContext = getInstrumentation().getTargetContext();
-    }
-
-    @UiThreadTest
+    @Test
     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) throws Throwable {
         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);
+        mActivityRule.runOnUiThread(() -> {
+            spinner.setAdapter(adapter);
+            assertTrue(spinner.getBaseline() > 0);
+        });
     }
 
-    @UiThreadTest
-    public void testSetOnItemClickListener() {
-        Spinner spinner = new Spinner(mTargetContext);
+    @Test
+    public void testGetBaseline() throws Throwable {
+        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 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?
+    @Test
+    public void testSetOnItemClickListener() {
+        verifySetOnItemClickListener(mSpinnerDialogMode);
+        verifySetOnItemClickListener(mSpinnerDropdownMode);
     }
 
-    @UiThreadTest
-    public void testOnClick() {
-        Spinner spinner = new Spinner(mTargetContext);
+    private void verifyPerformClick(Spinner spinner) throws Throwable {
+        mActivityRule.runOnUiThread(() -> assertTrue(spinner.performClick()));
+    }
+
+    @Test
+    public void testPerformClick() throws Throwable {
+        verifyPerformClick(mSpinnerDialogMode);
+        verifyPerformClick(mSpinnerDropdownMode);
+    }
+
+    private void verifyOnClick(Spinner spinner) {
         // normal value
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
         AlertDialog alertDialog = builder.show();
         assertTrue(alertDialog.isShowing());
+
         spinner.onClick(alertDialog, 10);
         assertEquals(10, spinner.getSelectedItemPosition());
         assertFalse(alertDialog.isShowing());
@@ -122,35 +205,44 @@
         } catch (NullPointerException e) {
         }
 
-        Dialog dialog = new Dialog(getActivity());
+        Dialog dialog = new Dialog(mActivity);
         dialog.show();
         assertTrue(dialog.isShowing());
+
         spinner.onClick(dialog, -10);
         assertEquals(-10, spinner.getSelectedItemPosition());
         assertFalse(dialog.isShowing());
     }
 
     @UiThreadTest
-    public void testAccessPrompt() {
+    @Test
+    public void testOnClick() {
+        verifyOnClick(mSpinnerDialogMode);
+        verifyOnClick(mSpinnerDropdownMode);
+    }
+
+    private void verifyAccessPrompt(Spinner spinner) throws Throwable {
+        final String initialPrompt = mActivity.getString(R.string.text_view_hello);
+        assertEquals(initialPrompt, spinner.getPrompt());
+
         final String promptText = "prompt text";
 
-        Spinner spinner = new Spinner(mTargetContext);
-
-        spinner.setPrompt(promptText);
+        mActivityRule.runOnUiThread(() -> 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);
+    @Test
+    public void testAccessPrompt() throws Throwable {
+        verifyAccessPrompt(mSpinnerDialogMode);
+        verifyAccessPrompt(mSpinnerDropdownMode);
+    }
 
-        spinner.setPromptId(R.string.hello_world);
-        assertEquals(mTargetContext.getString(R.string.hello_world), spinner.getPrompt());
+    private void verifySetPromptId(Spinner spinner) throws Throwable {
+        mActivityRule.runOnUiThread(() -> spinner.setPromptId(R.string.hello_world));
+        assertEquals(mActivity.getString(R.string.hello_world), spinner.getPrompt());
 
         try {
             spinner.setPromptId(-1);
@@ -165,23 +257,206 @@
         } 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?
+    @Test
+    public void testSetPromptId() throws Throwable {
+        verifySetPromptId(mSpinnerDialogMode);
+        verifySetPromptId(mSpinnerDropdownMode);
     }
 
     @UiThreadTest
+    @Test
     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) throws Throwable {
+        // 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);
+        mActivityRule.runOnUiThread(() -> spinner.setAdapter(adapter));
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, spinner, () -> {
+            spinner.setSelection(1);
+            spinner.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
+            spinner.requestLayout();
+        });
+
+        mActivityRule.runOnUiThread(() -> spinner.setGravity(Gravity.LEFT));
+        assertEquals(Gravity.LEFT, spinner.getGravity());
+
+        mActivityRule.runOnUiThread(() -> spinner.setGravity(Gravity.CENTER_HORIZONTAL));
+        assertEquals(Gravity.CENTER_HORIZONTAL, spinner.getGravity());
+
+        mActivityRule.runOnUiThread((() -> spinner.setGravity(Gravity.RIGHT)));
+        assertEquals(Gravity.RIGHT, spinner.getGravity());
+
+        mActivityRule.runOnUiThread(() -> spinner.setGravity(Gravity.START));
+        assertEquals(Gravity.START, spinner.getGravity());
+
+        mActivityRule.runOnUiThread(() -> spinner.setGravity(Gravity.END));
+        assertEquals(Gravity.END, spinner.getGravity());
+    }
+
+    @Test
+    public void testGravity() throws Throwable {
+        verifyGravity(mSpinnerDialogMode);
+        verifyGravity(mSpinnerDropdownMode);
+    }
+
+    @Test
+    public void testDropDownMetricsDropdownMode() throws Throwable {
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mActivityRule.runOnUiThread(() -> 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);
+
+        mActivityRule.runOnUiThread(() -> {
+            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(mInstrumentation, 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());
+    }
+
+    @Test
+    public void testDropDownMetricsDialogMode() throws Throwable {
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mActivityRule.runOnUiThread(() -> 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);
+
+        mActivityRule.runOnUiThread(() -> {
+            // 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(mInstrumentation, 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());
+    }
+
+    @Test
+    public void testDropDownBackgroundDropdownMode() throws Throwable {
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mActivityRule.runOnUiThread(() -> mSpinnerDropdownMode.setAdapter(adapter));
+
+        // Set blue background on the popup
+        mActivityRule.runOnUiThread(() ->
+                mSpinnerDropdownMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, 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
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        mInstrumentation.waitForIdleSync();
+        // Verify that we're not showing the popup
+        assertFalse(mSpinnerDropdownMode.isPopupShowing());
+
+        // Set yellow background on the popup
+        mActivityRule.runOnUiThread(() ->
+                mSpinnerDropdownMode.setPopupBackgroundDrawable(
+                        mActivity.getDrawable(R.drawable.yellow_fill)));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, 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);
+    }
+
+    @Test
+    public void testDropDownBackgroundDialogMode() throws Throwable {
+        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+                R.array.string, android.R.layout.simple_spinner_item);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mActivityRule.runOnUiThread(() -> mSpinnerDialogMode.setAdapter(adapter));
+
+        // Set blue background on the popup
+        mActivityRule.runOnUiThread(() ->
+                mSpinnerDialogMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, 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
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        mInstrumentation.waitForIdleSync();
+        // Verify that we're not showing the popup
+        assertFalse(mSpinnerDialogMode.isPopupShowing());
+
+        // Set yellow background on the popup
+        mActivityRule.runOnUiThread(() ->
+                mSpinnerDialogMode.setPopupBackgroundDrawable(
+                        mActivity.getDrawable(R.drawable.yellow_fill)));
+
+        // Use instrumentation to emulate a tap on the spinner to bring down its popup
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, 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..1123a4e 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -16,38 +16,62 @@
 
 package android.widget.cts;
 
+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 android.app.Activity;
+import android.app.Instrumentation;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.graphics.PorterDuff.Mode;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ContextThemeWrapper;
+import android.view.ViewGroup;
 import android.widget.Switch;
-import org.xmlpull.v1.XmlPullParserException;
+import android.widget.cts.util.TestUtils;
 
-import java.io.IOException;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link Switch}.
  */
-@SmallTest
-public class SwitchTest extends ActivityInstrumentationTestCase<SwitchCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SwitchTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
     private Switch mSwitch;
 
-    public SwitchTest() {
-        super("android.widget.cts", SwitchCtsActivity.class);
+    @Rule
+    public ActivityTestRule<SwitchCtsActivity> mActivityRule =
+            new ActivityTestRule<>(SwitchCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    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
+    @Test
     public void testConstructor() {
         new Switch(mActivity);
 
@@ -55,11 +79,17 @@
 
         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
+    @Test
     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());
 
@@ -72,7 +102,11 @@
     }
 
     @UiThreadTest
+    @Test
     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 +117,175 @@
         assertSame(colors, mSwitch.getTrackTintList());
         assertEquals(Mode.XOR, mSwitch.getTrackTintMode());
     }
+
+    @Test
+    public void testAccessThumbDrawable() throws Throwable {
+        mSwitch = findSwitchById(R.id.switch2);
+
+        // 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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);
+    }
+
+    @Test
+    public void testAccessTrackDrawable() throws Throwable {
+        mSwitch = findSwitchById(R.id.switch2);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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(mActivityRule, 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);
+    }
+
+    @Test
+    public void testAccessText() throws Throwable {
+        // 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));
+        final ViewGroup container = (ViewGroup) mActivity.findViewById(R.id.container);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, container,
+                () -> container.addView(mSwitch));
+
+        // Set "on" text and verify it
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSwitch,
+                () -> mSwitch.setTextOn("Text on"));
+        assertEquals("Text on", mSwitch.getTextOn());
+
+        // Set "off" text and verify it
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSwitch,
+                () -> mSwitch.setTextOff("Text off"));
+        assertEquals("Text off", mSwitch.getTextOff());
+
+        // Turn text display on
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, mSwitch,
+                () -> mSwitch.setSwitchTypeface(Typeface.MONOSPACE));
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(mActivityRule, mSwitch,
+                () -> mSwitch.setSwitchPadding(switchPadding));
+        assertEquals(switchPadding, mSwitch.getSwitchPadding());
+
+        // Turn text display off
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSwitch,
+                () -> mSwitch.setShowText(false));
+        assertFalse(mSwitch.getShowText());
+    }
+
+    @Test
+    public void testAccessMinWidth() throws Throwable {
+        mSwitch = findSwitchById(R.id.switch3);
+
+        // 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(mActivityRule, 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(mActivityRule, mSwitch,
+                () -> mSwitch.setSwitchMinWidth(switchMinWidth2));
+        assertEquals(switchMinWidth2, mSwitch.getSwitchMinWidth());
+        assertTrue(mSwitch.getWidth() >= switchMinWidth2);
+    }
+
+    @Test
+    public void testAccessSplitTrack() throws Throwable {
+        mSwitch = findSwitchById(R.id.switch3);
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSwitch,
+                () -> mSwitch.setSplitTrack(true));
+        assertTrue(mSwitch.getSplitTrack());
+
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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..765fd37 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHostTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHostTest.java
@@ -16,13 +16,25 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+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.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
 import android.app.Activity;
 import android.app.ActivityGroup;
+import android.app.Instrumentation;
 import android.content.Intent;
-import android.cts.util.WidgetTestUtils;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TabHost;
@@ -30,41 +42,55 @@
 import android.widget.TabHost.TabSpec;
 import android.widget.TextView;
 
-import static org.mockito.Mockito.*;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link TabHost}.
  */
 @SmallTest
-public class TabHostTest extends ActivityInstrumentationTestCase2<TabHostCtsActivity> {
+@RunWith(AndroidJUnit4.class)
+public class TabHostTest {
     private static final String TAG_TAB1 = "tab 1";
     private static final String TAG_TAB2 = "tab 2";
     private static final int TAB_HOST_ID = android.R.id.tabhost;
 
+    private Instrumentation mInstrumentation;
     private TabHostCtsActivity mActivity;
 
-    public TabHostTest() {
-        super("android.widget.cts", TabHostCtsActivity.class);
+    @Rule
+    public ActivityTestRule<TabHostCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TabHostCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new TabHost(mActivity);
 
         new TabHost(mActivity, null);
     }
 
+    @Test
     public void testNewTabSpec() {
         TabHost tabHost = new TabHost(mActivity);
 
         assertNotNull(tabHost.newTabSpec(TAG_TAB2));
+    }
 
-        assertNotNull(tabHost.newTabSpec(null));
+    @Test(expected=IllegalArgumentException.class)
+    public void testNewTabSpecWithNullTag() {
+        TabHost tabHost = new TabHost(mActivity);
+
+        tabHost.newTabSpec(null);
     }
 
     /*
@@ -72,28 +98,31 @@
      * 1. the tabWidget view and tabContent view associated with tabHost are created.
      * 2. no exception occurs when doing normal operation after setup().
      */
+    @Test
     public void testSetup1() throws Throwable {
-        final Activity activity = launchActivity("android.widget.cts", CtsActivity.class, null);
+        final Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+        launchIntent.setClassName("android.widget.cts", CtsActivity.class.getName());
+        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final Activity activity = mInstrumentation.startActivitySync(launchIntent);
+        mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                activity.setContentView(R.layout.tabhost_layout);
+        mActivityRule.runOnUiThread(() -> {
+            activity.setContentView(R.layout.tabhost_layout);
 
-                TabHost tabHost = (TabHost) activity.findViewById(TAB_HOST_ID);
-                assertNull(tabHost.getTabWidget());
-                assertNull(tabHost.getTabContentView());
-                tabHost.setup();
-                assertNotNull(tabHost.getTabWidget());
-                assertNotNull(tabHost.getTabContentView());
+            TabHost tabHost = (TabHost) activity.findViewById(TAB_HOST_ID);
+            assertNull(tabHost.getTabWidget());
+            assertNull(tabHost.getTabContentView());
+            tabHost.setup();
+            assertNotNull(tabHost.getTabWidget());
+            assertNotNull(tabHost.getTabContentView());
 
-                TabSpec tabSpec = tabHost.newTabSpec(TAG_TAB1);
-                tabSpec.setIndicator(TAG_TAB1);
-                tabSpec.setContent(new MyTabContentFactoryList());
-                tabHost.addTab(tabSpec);
-                tabHost.setCurrentTab(0);
-            }
+            TabSpec tabSpec = tabHost.newTabSpec(TAG_TAB1);
+            tabSpec.setIndicator(TAG_TAB1);
+            tabSpec.setContent(new MyTabContentFactoryList());
+            tabHost.addTab(tabSpec);
+            tabHost.setCurrentTab(0);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         activity.finish();
     }
@@ -103,41 +132,40 @@
      * 1. the tabWidget view and tabContent view associated with tabHost are created.
      * 2. no exception occurs when uses TabSpec.setContent(android.content.Intent) after setup().
      */
+    @Test
     public void testSetup2() throws Throwable {
-        final ActivityGroup activity = launchActivity("android.widget.cts",
-                ActivityGroup.class, null);
+        final Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+        launchIntent.setClassName("android.widget.cts", ActivityGroup.class.getName());
+        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        final ActivityGroup activity =
+                (ActivityGroup) mInstrumentation.startActivitySync(launchIntent);
+        mInstrumentation.waitForIdleSync();
 
+        mActivityRule.runOnUiThread(() -> {
+            activity.setContentView(R.layout.tabhost_layout);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                activity.setContentView(R.layout.tabhost_layout);
+            TabHost tabHost = (TabHost) activity.findViewById(TAB_HOST_ID);
+            assertNull(tabHost.getTabWidget());
+            assertNull(tabHost.getTabContentView());
+            tabHost.setup(activity.getLocalActivityManager());
+            assertNotNull(tabHost.getTabWidget());
+            assertNotNull(tabHost.getTabContentView());
 
-                TabHost tabHost = (TabHost) activity.findViewById(TAB_HOST_ID);
-                assertNull(tabHost.getTabWidget());
-                assertNull(tabHost.getTabContentView());
-                tabHost.setup(activity.getLocalActivityManager());
-                assertNotNull(tabHost.getTabWidget());
-                assertNotNull(tabHost.getTabContentView());
-
-                TabSpec tabSpec = tabHost.newTabSpec(TAG_TAB1);
-                tabSpec.setIndicator(TAG_TAB1);
-                Intent intent = new Intent(Intent.ACTION_VIEW, null,
-                        mActivity, CtsActivity.class);
-                tabSpec.setContent(intent);
-                tabHost.addTab(tabSpec);
-                tabHost.setCurrentTab(0);
-            }
+            TabSpec tabSpec = tabHost.newTabSpec(TAG_TAB1);
+            tabSpec.setIndicator(TAG_TAB1);
+            Intent intent = new Intent(Intent.ACTION_VIEW, null,
+                    mActivity, CtsActivity.class);
+            tabSpec.setContent(intent);
+            tabHost.addTab(tabSpec);
+            tabHost.setCurrentTab(0);
         });
-        getInstrumentation().waitForIdleSync();
+        mInstrumentation.waitForIdleSync();
 
         activity.finish();
     }
 
-    public void testOnTouchModeChanged() {
-        // implementation details
-    }
-
     @UiThreadTest
+    @Test
     public void testAddTab() {
         TabHost tabHost = mActivity.getTabHost();
         // there is a initial tab
@@ -151,27 +179,38 @@
         tabHost.setCurrentTab(1);
         assertTrue(tabHost.getCurrentView() instanceof ListView);
         assertEquals(TAG_TAB2, tabHost.getCurrentTabTag());
-
-        try {
-            tabHost.addTab(tabHost.newTabSpec("tab 3"));
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            tabHost.addTab(tabHost.newTabSpec("tab 3").setIndicator("tab 3"));
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            tabHost.addTab(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
     }
 
     @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddTabNoIndicatorNoContent() {
+        TabHost tabHost = mActivity.getTabHost();
+        tabHost.addTab(tabHost.newTabSpec("tab 3"));
+    }
+
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddTabNoContent() {
+        TabHost tabHost = mActivity.getTabHost();
+        tabHost.addTab(tabHost.newTabSpec("tab 3").setIndicator("tab 3"));
+    }
+
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddTabNoIndicator() {
+        TabHost tabHost = mActivity.getTabHost();
+        tabHost.addTab(tabHost.newTabSpec("tab 3").setContent(new MyTabContentFactoryText()));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddTabNull() {
+        TabHost tabHost = mActivity.getTabHost();
+        tabHost.addTab(null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testClearAllTabs() {
         TabHost tabHost = mActivity.getTabHost();
         MyTabContentFactoryText tcf = new MyTabContentFactoryText();
@@ -191,20 +230,19 @@
         assertNull(tabHost.getCurrentView());
     }
 
+    @Test
     public void testGetTabWidget() {
         TabHost tabHost = mActivity.getTabHost();
 
         // The attributes defined in tabhost_layout.xml
         assertEquals(android.R.id.tabs, tabHost.getTabWidget().getId());
-        WidgetTestUtils.assertScaledPixels(1, tabHost.getTabWidget().getPaddingLeft(),
-                getActivity());
-        WidgetTestUtils.assertScaledPixels(1, tabHost.getTabWidget().getPaddingRight(),
-                getActivity());
-        WidgetTestUtils.assertScaledPixels(4, tabHost.getTabWidget().getPaddingTop(),
-                getActivity());
+        WidgetTestUtils.assertScaledPixels(1, tabHost.getTabWidget().getPaddingLeft(), mActivity);
+        WidgetTestUtils.assertScaledPixels(1, tabHost.getTabWidget().getPaddingRight(), mActivity);
+        WidgetTestUtils.assertScaledPixels(4, tabHost.getTabWidget().getPaddingTop(), mActivity);
     }
 
     @UiThreadTest
+    @Test
     public void testAccessCurrentTab() {
         TabHost tabHost = mActivity.getTabHost();
         assertEquals(0, tabHost.getCurrentTab());
@@ -227,6 +265,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCurrentTabView() {
         TabHost tabHost = mActivity.getTabHost();
         // current tab view is the first child of tabWidget.
@@ -242,6 +281,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCurrentView() {
         TabHost tabHost = mActivity.getTabHost();
         TextView textView = (TextView) tabHost.getCurrentView();
@@ -256,6 +296,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetCurrentTabByTag() {
         TabHost tabHost = mActivity.getTabHost();
 
@@ -280,6 +321,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetTabContentView() {
         TabHost tabHost = mActivity.getTabHost();
         assertEquals(3, tabHost.getTabContentView().getChildCount());
@@ -309,22 +351,13 @@
         assertEquals(TabHostCtsActivity.INITIAL_VIEW_TEXT, child2.getText().toString());
     }
 
-    @UiThreadTest
-    public void testDispatchKeyEvent() {
-        // Implementation details.
-    }
-
-    @UiThreadTest
-    public void testDispatchWindowFocusChanged() {
-        // Implementation details
-    }
-
     /**
      * Check points:
      * 1. the specified callback should be invoked when the selected state of any of the items
      * in this list changes
      */
     @UiThreadTest
+    @Test
     public void testSetOnTabChangedListener() {
         TabHost tabHost = mActivity.getTabHost();
 
@@ -349,6 +382,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCurrentTabTag() {
         TabHost tabHost = mActivity.getTabHost();
         assertEquals(TabHostCtsActivity.INITIAL_TAB_TAG, tabHost.getCurrentTabTag());
@@ -361,11 +395,6 @@
         assertEquals(TAG_TAB2, tabHost.getCurrentTabTag());
     }
 
-    @UiThreadTest
-    public void testOnAttachedToAndDetachedFromWindow() {
-        // implementation details
-    }
-
     private class MyTabContentFactoryText implements TabHost.TabContentFactory {
         public View createTabContent(String tag) {
             final TextView tv = new TextView(mActivity);
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..a0498d5 100644
--- a/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabHost_TabSpecTest.java
@@ -16,8 +16,11 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+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 android.app.Activity;
 import android.app.Instrumentation;
@@ -27,38 +30,47 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TabHost;
 import android.widget.TextView;
-import android.widget.TabHost.TabSpec;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
- * Test {@link TabSpec}.
+ * Test {@link TabHost.TabSpec}.
  */
-public class TabHost_TabSpecTest extends ActivityInstrumentationTestCase2<TabHostCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TabHost_TabSpecTest {
     private static final String TAG_TAB2 = "tab 2";
 
-    private TabHost mTabHost;
     private TabHostCtsActivity mActivity;
+    private TabHost mTabHost;
 
-    public TabHost_TabSpecTest() {
-        super("android.widget.cts", TabHostCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<TabHostCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TabHostCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
         mTabHost = mActivity.getTabHost();
     }
 
     @UiThreadTest
+    @Test
     public void testSetIndicator1() {
-        TabSpec tabSpec = mTabHost.newTabSpec(TAG_TAB2);
+        TabHost.TabSpec tabSpec = mTabHost.newTabSpec(TAG_TAB2);
 
         // normal value
         tabSpec.setIndicator(TAG_TAB2).setContent(new MockTabContentFactoryText());
@@ -80,8 +92,9 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetIndicator2() {
-        TabSpec tabSpec = mTabHost.newTabSpec(TAG_TAB2);
+        TabHost.TabSpec tabSpec = mTabHost.newTabSpec(TAG_TAB2);
 
         // normal value
         Drawable d = new ColorDrawable(Color.GRAY);
@@ -133,29 +146,31 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetContent1() {
-        TabSpec tabSpec2 = mTabHost.newTabSpec("tab spec 2");
+        TabHost.TabSpec tabSpec2 = mTabHost.newTabSpec("tab spec 2");
         tabSpec2.setIndicator("tab 2");
         // TabContentFactory to create a TextView as the content of the tab.
-        tabSpec2.setContent(android.widget.cts.R.id.tabhost_textview);
+        tabSpec2.setContent(R.id.tabhost_textview);
         mTabHost.addTab(tabSpec2);
         mTabHost.setCurrentTab(1);
         TextView currentView = (TextView) mTabHost.getCurrentView();
         assertEquals(mActivity.getResources().getString(R.string.hello_world),
                 currentView.getText().toString());
 
-        TabSpec tabSpec3 = mTabHost.newTabSpec("tab spec 3");
+        TabHost.TabSpec tabSpec3 = mTabHost.newTabSpec("tab spec 3");
         tabSpec3.setIndicator("tab 3");
         // TabContentFactory to create a ListView as the content of the tab.
-        tabSpec3.setContent(android.widget.cts.R.id.tabhost_listview);
+        tabSpec3.setContent(R.id.tabhost_listview);
         mTabHost.addTab(tabSpec3);
         mTabHost.setCurrentTab(2);
         assertTrue(mTabHost.getCurrentView() instanceof ListView);
     }
 
     @UiThreadTest
+    @Test
     public void testSetContent2() {
-        TabSpec tabSpec2 = mTabHost.newTabSpec("tab spec 2");
+        TabHost.TabSpec tabSpec2 = mTabHost.newTabSpec("tab spec 2");
         tabSpec2.setIndicator("tab 2");
         // TabContentFactory to create a TextView as the content of the tab.
         tabSpec2.setContent(new MockTabContentFactoryText());
@@ -164,7 +179,7 @@
         TextView currentView = (TextView) mTabHost.getCurrentView();
         assertEquals("tab spec 2", currentView.getText().toString());
 
-        TabSpec tabSpec3 = mTabHost.newTabSpec("tab spec 3");
+        TabHost.TabSpec tabSpec3 = mTabHost.newTabSpec("tab spec 3");
         tabSpec3.setIndicator("tab 3");
         // TabContentFactory to create a ListView as the content of the tab.
         tabSpec3.setContent(new MockTabContentFactoryList());
@@ -173,22 +188,21 @@
         assertTrue(mTabHost.getCurrentView() instanceof ListView);
     }
 
+    @Test
     public void testSetContent3() {
         // The scheme of uri string must be "ctstest" to launch MockURLSpanTestActivity
         Uri uri = Uri.parse("ctstest://tabhost_tabspec/test");
         final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                TabSpec tabSpec = mTabHost.newTabSpec("tab spec");
-                tabSpec.setIndicator("tab");
-                tabSpec.setContent(intent);
-                mTabHost.addTab(tabSpec);
-                mTabHost.setCurrentTab(1);
-            }
+        mActivity.runOnUiThread(() -> {
+            TabHost.TabSpec tabSpec = mTabHost.newTabSpec("tab spec");
+            tabSpec.setIndicator("tab");
+            tabSpec.setContent(intent);
+            mTabHost.addTab(tabSpec);
+            mTabHost.setCurrentTab(1);
         });
 
-        Instrumentation instrumentation = getInstrumentation();
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
                 null, false);
 
diff --git a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
index 58fbf46..c798a0e 100644
--- a/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TabWidgetTest.java
@@ -16,13 +16,19 @@
 
 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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-import android.app.Activity;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -33,23 +39,31 @@
 import android.widget.TextView;
 import android.widget.cts.util.TestUtils;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link TabWidget}.
  */
-@SmallTest
-public class TabWidgetTest extends ActivityInstrumentationTestCase2<TabHostCtsActivity> {
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TabWidgetTest {
+    private TabHostCtsActivity mActivity;
+    private TabWidget mTabWidget;
 
-    public TabWidgetTest() {
-        super("android.widget.cts", TabHostCtsActivity.class);
+    @Rule
+    public ActivityTestRule<TabHostCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TabHostCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mTabWidget = mActivity.getTabWidget();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         new TabWidget(mActivity);
 
@@ -58,6 +72,7 @@
         new TabWidget(mActivity, null, 0);
     }
 
+    @Test
     public void testConstructorWithStyle() {
         TabWidget tabWidget = new TabWidget(mActivity, null, 0, R.style.TabWidgetCustomStyle);
 
@@ -76,6 +91,7 @@
                 true, 0xFFFF0000, 1, false);
     }
 
+    @Test
     public void testInflateFromXml() {
         LayoutInflater inflater = LayoutInflater.from(mActivity);
         TabWidget tabWidget = (TabWidget) inflater.inflate(R.layout.tabhost_custom, null, false);
@@ -96,38 +112,36 @@
     }
 
     @UiThreadTest
+    @Test
     public void testTabCount() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-
         // We have one tab added in onCreate() of our activity
-        assertEquals(1, tabWidget.getTabCount());
+        assertEquals(1, mTabWidget.getTabCount());
 
         for (int i = 1; i < 10; i++) {
-            tabWidget.addView(new TextView(mActivity));
-            assertEquals(i + 1, tabWidget.getTabCount());
+            mTabWidget.addView(new TextView(mActivity));
+            assertEquals(i + 1, mTabWidget.getTabCount());
         }
     }
 
     @UiThreadTest
+    @Test
     public void testTabViews() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-
         // We have one tab added in onCreate() of our activity. We "reach" into the default tab
         // indicator layout in the same way we do in TabHost_TabSpecTest tests.
-        TextView tab0 = (TextView) tabWidget.getChildTabViewAt(0).findViewById(android.R.id.title);
+        TextView tab0 = (TextView) mTabWidget.getChildTabViewAt(0).findViewById(android.R.id.title);
         assertNotNull(tab0);
         assertEquals(TabHostCtsActivity.INITIAL_TAB_LABEL, tab0.getText());
 
         for (int i = 1; i < 10; i++) {
             TextView toAdd = new TextView(mActivity);
             toAdd.setText("Tab #" + i);
-            tabWidget.addView(toAdd);
-            assertEquals(toAdd, tabWidget.getChildTabViewAt(i));
+            mTabWidget.addView(toAdd);
+            assertEquals(toAdd, mTabWidget.getChildTabViewAt(i));
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testChildDrawableStateChanged() {
         MockTabWidget mockTabWidget = new MockTabWidget(mActivity);
         TextView tv0 = new TextView(mActivity);
@@ -148,93 +162,84 @@
         assertFalse(mockTabWidget.hasCalledInvalidate());
     }
 
-    public void testDispatchDraw() {
-        // implementation details
-    }
-
     @UiThreadTest
+    @Test
     public void testSetCurrentTab() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-        tabWidget.addView(new TextView(mActivity));
+        mTabWidget.addView(new TextView(mActivity));
 
-        assertTrue(tabWidget.getChildAt(0).isSelected());
-        assertFalse(tabWidget.getChildAt(1).isSelected());
-        assertTrue(tabWidget.getChildAt(0).isFocused());
-        assertFalse(tabWidget.getChildAt(1).isFocused());
+        assertTrue(mTabWidget.getChildAt(0).isSelected());
+        assertFalse(mTabWidget.getChildAt(1).isSelected());
+        assertTrue(mTabWidget.getChildAt(0).isFocused());
+        assertFalse(mTabWidget.getChildAt(1).isFocused());
 
-        tabWidget.setCurrentTab(1);
-        assertFalse(tabWidget.getChildAt(0).isSelected());
-        assertTrue(tabWidget.getChildAt(1).isSelected());
-        assertTrue(tabWidget.getChildAt(0).isFocused());
-        assertFalse(tabWidget.getChildAt(1).isFocused());
+        mTabWidget.setCurrentTab(1);
+        assertFalse(mTabWidget.getChildAt(0).isSelected());
+        assertTrue(mTabWidget.getChildAt(1).isSelected());
+        assertTrue(mTabWidget.getChildAt(0).isFocused());
+        assertFalse(mTabWidget.getChildAt(1).isFocused());
     }
 
     @UiThreadTest
+    @Test
     public void testFocusCurrentTab() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-        tabWidget.addView(new TextView(mActivity));
+        mTabWidget.addView(new TextView(mActivity));
 
-        assertTrue(tabWidget.getChildAt(0).isSelected());
-        assertFalse(tabWidget.getChildAt(1).isSelected());
-        assertEquals(tabWidget.getChildAt(0), tabWidget.getFocusedChild());
-        assertTrue(tabWidget.getChildAt(0).isFocused());
-        assertFalse(tabWidget.getChildAt(1).isFocused());
+        assertTrue(mTabWidget.getChildAt(0).isSelected());
+        assertFalse(mTabWidget.getChildAt(1).isSelected());
+        assertEquals(mTabWidget.getChildAt(0), mTabWidget.getFocusedChild());
+        assertTrue(mTabWidget.getChildAt(0).isFocused());
+        assertFalse(mTabWidget.getChildAt(1).isFocused());
 
         // normal
-        tabWidget.focusCurrentTab(1);
-        assertFalse(tabWidget.getChildAt(0).isSelected());
-        assertTrue(tabWidget.getChildAt(1).isSelected());
-        assertEquals(tabWidget.getChildAt(1), tabWidget.getFocusedChild());
-        assertFalse(tabWidget.getChildAt(0).isFocused());
-        assertTrue(tabWidget.getChildAt(1).isFocused());
+        mTabWidget.focusCurrentTab(1);
+        assertFalse(mTabWidget.getChildAt(0).isSelected());
+        assertTrue(mTabWidget.getChildAt(1).isSelected());
+        assertEquals(mTabWidget.getChildAt(1), mTabWidget.getFocusedChild());
+        assertFalse(mTabWidget.getChildAt(0).isFocused());
+        assertTrue(mTabWidget.getChildAt(1).isFocused());
 
-        tabWidget.focusCurrentTab(0);
-        assertTrue(tabWidget.getChildAt(0).isSelected());
-        assertFalse(tabWidget.getChildAt(1).isSelected());
-        assertEquals(tabWidget.getChildAt(0), tabWidget.getFocusedChild());
-        assertTrue(tabWidget.getChildAt(0).isFocused());
-        assertFalse(tabWidget.getChildAt(1).isFocused());
-
-        // exceptional
-        try {
-            tabWidget.focusCurrentTab(-1);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
-
-        try {
-            tabWidget.focusCurrentTab(tabWidget.getChildCount() + 1);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-            // expected exception
-        }
+        mTabWidget.focusCurrentTab(0);
+        assertTrue(mTabWidget.getChildAt(0).isSelected());
+        assertFalse(mTabWidget.getChildAt(1).isSelected());
+        assertEquals(mTabWidget.getChildAt(0), mTabWidget.getFocusedChild());
+        assertTrue(mTabWidget.getChildAt(0).isFocused());
+        assertFalse(mTabWidget.getChildAt(1).isFocused());
     }
 
     @UiThreadTest
-    public void testSetEnabled() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-
-        tabWidget.addView(new TextView(mActivity));
-        tabWidget.addView(new TextView(mActivity));
-        assertTrue(tabWidget.isEnabled());
-        assertTrue(tabWidget.getChildAt(0).isEnabled());
-        assertTrue(tabWidget.getChildAt(1).isEnabled());
-
-        tabWidget.setEnabled(false);
-        assertFalse(tabWidget.isEnabled());
-        assertFalse(tabWidget.getChildAt(0).isEnabled());
-        assertFalse(tabWidget.getChildAt(1).isEnabled());
-
-        tabWidget.setEnabled(true);
-        assertTrue(tabWidget.isEnabled());
-        assertTrue(tabWidget.getChildAt(0).isEnabled());
-        assertTrue(tabWidget.getChildAt(1).isEnabled());
+    @Test(expected=NullPointerException.class)
+    public void testFocusCurrentTabIndexTooLow() {
+        mTabWidget.focusCurrentTab(-1);
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testFocusCurrentTabIndexTooHigh() {
+        mTabWidget.focusCurrentTab(mTabWidget.getChildCount() + 1);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetEnabled() {
+        mTabWidget.addView(new TextView(mActivity));
+        mTabWidget.addView(new TextView(mActivity));
+        assertTrue(mTabWidget.isEnabled());
+        assertTrue(mTabWidget.getChildAt(0).isEnabled());
+        assertTrue(mTabWidget.getChildAt(1).isEnabled());
+
+        mTabWidget.setEnabled(false);
+        assertFalse(mTabWidget.isEnabled());
+        assertFalse(mTabWidget.getChildAt(0).isEnabled());
+        assertFalse(mTabWidget.getChildAt(1).isEnabled());
+
+        mTabWidget.setEnabled(true);
+        assertTrue(mTabWidget.isEnabled());
+        assertTrue(mTabWidget.getChildAt(0).isEnabled());
+        assertTrue(mTabWidget.getChildAt(1).isEnabled());
+    }
+
+    @UiThreadTest
+    @Test
     public void testAddView() {
         MockTabWidget mockTabWidget = new MockTabWidget(mActivity);
 
@@ -256,66 +261,62 @@
         View view2 = new RelativeLayout(mActivity);
         mockTabWidget.addView(view2);
         assertSame(view2, mockTabWidget.getChildAt(1));
+    }
 
-        try {
-            mockTabWidget.addView(new ListView(mActivity));
-            fail("did not throw RuntimeException when adding invalid view");
-        } catch (RuntimeException e) {
-            // issue 1695243
-        }
+    @Test(expected=RuntimeException.class)
+    public void testAddAdapterView() {
+        MockTabWidget mockTabWidget = new MockTabWidget(mActivity);
+        // Since TabWidget registers a click listener on each child, this is expected
+        // to fail with anything that extends AdapterView
+        mockTabWidget.addView(new ListView(mActivity));
+    }
 
-        try {
-            mockTabWidget.addView(null);
-            fail("did not throw NullPointerException when child is null");
-        } catch (NullPointerException e) {
-            // issue 1695243
-        }
+    @Test(expected=NullPointerException.class)
+    public void testAddNullView() {
+        MockTabWidget mockTabWidget = new MockTabWidget(mActivity);
+        // Since TabWidget registers a click listener on each child, this is expected
+        // to fail with anything that extends AdapterView
+        mockTabWidget.addView(null);
     }
 
     @UiThreadTest
+    @Test
     public void testStripEnabled() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
+        mTabWidget.setStripEnabled(true);
+        assertTrue(mTabWidget.isStripEnabled());
 
-        tabWidget.setStripEnabled(true);
-        assertTrue(tabWidget.isStripEnabled());
-
-        tabWidget.setStripEnabled(false);
-        assertFalse(tabWidget.isStripEnabled());
+        mTabWidget.setStripEnabled(false);
+        assertFalse(mTabWidget.isStripEnabled());
     }
 
     @UiThreadTest
+    @Test
     public void testStripDrawables() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-
         // Test setting left strip drawable
-        tabWidget.setLeftStripDrawable(R.drawable.icon_green);
-        Drawable leftStripDrawable = tabWidget.getLeftStripDrawable();
+        mTabWidget.setLeftStripDrawable(R.drawable.icon_green);
+        Drawable leftStripDrawable = mTabWidget.getLeftStripDrawable();
         assertNotNull(leftStripDrawable);
         TestUtils.assertAllPixelsOfColor("Left strip green", leftStripDrawable,
                 leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
                 true, 0xFF00FF00, 1, false);
 
-        tabWidget.setLeftStripDrawable(activity.getResources().getDrawable(
-                R.drawable.icon_red, null));
-        leftStripDrawable = tabWidget.getLeftStripDrawable();
+        mTabWidget.setLeftStripDrawable(mActivity.getDrawable(R.drawable.icon_red));
+        leftStripDrawable = mTabWidget.getLeftStripDrawable();
         assertNotNull(leftStripDrawable);
         TestUtils.assertAllPixelsOfColor("Left strip red", leftStripDrawable,
                 leftStripDrawable.getIntrinsicWidth(), leftStripDrawable.getIntrinsicHeight(),
                 true, 0xFFFF0000, 1, false);
 
         // Test setting right strip drawable
-        tabWidget.setRightStripDrawable(R.drawable.icon_red);
-        Drawable rightStripDrawable = tabWidget.getRightStripDrawable();
+        mTabWidget.setRightStripDrawable(R.drawable.icon_red);
+        Drawable rightStripDrawable = mTabWidget.getRightStripDrawable();
         assertNotNull(rightStripDrawable);
         TestUtils.assertAllPixelsOfColor("Right strip red", rightStripDrawable,
                 rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
                 true, 0xFFFF0000, 1, false);
 
-        tabWidget.setRightStripDrawable(activity.getResources().getDrawable(
-                R.drawable.icon_green, null));
-        rightStripDrawable = tabWidget.getRightStripDrawable();
+        mTabWidget.setRightStripDrawable(mActivity.getDrawable(R.drawable.icon_green));
+        rightStripDrawable = mTabWidget.getRightStripDrawable();
         assertNotNull(rightStripDrawable);
         TestUtils.assertAllPixelsOfColor("Left strip green", rightStripDrawable,
                 rightStripDrawable.getIntrinsicWidth(), rightStripDrawable.getIntrinsicHeight(),
@@ -323,20 +324,17 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDividerDrawables() {
-        TabHostCtsActivity activity = getActivity();
-        TabWidget tabWidget = activity.getTabWidget();
-
-        tabWidget.setDividerDrawable(R.drawable.icon_blue);
-        Drawable dividerDrawable = tabWidget.getDividerDrawable();
+        mTabWidget.setDividerDrawable(R.drawable.icon_blue);
+        Drawable dividerDrawable = mTabWidget.getDividerDrawable();
         assertNotNull(dividerDrawable);
         TestUtils.assertAllPixelsOfColor("Divider blue", dividerDrawable,
                 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
                 true, 0xFF0000FF, 1, false);
 
-        tabWidget.setDividerDrawable(activity.getResources().getDrawable(
-                R.drawable.icon_yellow, null));
-        dividerDrawable = tabWidget.getDividerDrawable();
+        mTabWidget.setDividerDrawable(mActivity.getDrawable(R.drawable.icon_yellow));
+        dividerDrawable = mTabWidget.getDividerDrawable();
         assertNotNull(dividerDrawable);
         TestUtils.assertAllPixelsOfColor("Divider yellow", dividerDrawable,
                 dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
@@ -344,14 +342,6 @@
 
     }
 
-    public void testOnFocusChange() {
-        // onFocusChange() is implementation details, do NOT test
-    }
-
-    public void testOnSizeChanged() {
-        // implementation details
-    }
-
     /*
      * Mock class for TabWidget to be used in test cases.
      */
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..3532e99 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -16,18 +16,30 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+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 android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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;
@@ -35,197 +47,199 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link TableLayout}.
  */
-public class TableLayoutTest extends ActivityInstrumentationTestCase2<TableCtsActivity> {
-    private Context mContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TableLayoutTest {
+    private TableCtsActivity mActivity;
+    private TableLayout mTableDefault;
+    private TableLayout mTableEmpty;
+    private MockTableLayout mTableCustomEmpty;
 
-    public TableLayoutTest() {
-        super("android.widget.cts", TableCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<TableCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TableCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getContext();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mTableDefault = (TableLayout) mActivity.findViewById(R.id.table1);
+        mTableEmpty = (TableLayout) mActivity.findViewById(R.id.table_empty);
+        mTableCustomEmpty = (MockTableLayout) mActivity.findViewById(R.id.table_custom_empty);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-        new TableLayout(mContext);
+        new TableLayout(mActivity);
 
-        new TableLayout(mContext, null);
+        new TableLayout(mActivity, null);
 
-        TableCtsActivity activity = getActivity();
-        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
-        TableLayout tableLayout = (TableLayout) activity
-                .findViewById(android.widget.cts.R.id.table1);
-        assertTrue(tableLayout.isColumnCollapsed(0));
-        assertTrue(tableLayout.isColumnStretchable(2));
+        assertTrue(mTableDefault.isColumnCollapsed(0));
+        assertTrue(mTableDefault.isColumnStretchable(2));
 
-        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
+        mActivity.setContentView(R.layout.table_layout_2);
+        TableLayout tableLayout = (TableLayout) mActivity.findViewById(R.id.table2);
         assertTrue(tableLayout.isColumnShrinkable(1));
     }
 
+    @UiThreadTest
+    @Test
     public void testSetOnHierarchyChangeListener() {
-        TableLayout tableLayout = new TableLayout(mContext);
+        ViewGroup.OnHierarchyChangeListener mockHierarchyChangeListener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
+        mTableEmpty.setOnHierarchyChangeListener(mockHierarchyChangeListener);
 
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        tableLayout.setOnHierarchyChangeListener(listener);
+        View toAdd = new TextView(mActivity);
+        mTableEmpty.addView(toAdd);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewAdded(mTableEmpty, toAdd);
+        mTableEmpty.removeViewAt(0);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewRemoved(mTableEmpty, toAdd);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
 
-        tableLayout.addView(new TextView(mContext));
-        assertTrue(listener.hasCalledOnChildViewAdded());
-        tableLayout.removeViewAt(0);
-        assertTrue(listener.hasCalledOnChildViewRemoved());
-
-        listener.reset();
-
-        tableLayout.setOnHierarchyChangeListener(null);
-        tableLayout.addView(new TextView(mContext));
-        assertFalse(listener.hasCalledOnChildViewAdded());
-        tableLayout.removeViewAt(0);
-        assertFalse(listener.hasCalledOnChildViewRemoved());
+        mTableEmpty.setOnHierarchyChangeListener(null);
+        mTableEmpty.addView(new TextView(mActivity));
+        mTableEmpty.removeViewAt(0);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
     }
 
+    @UiThreadTest
+    @Test
     public void testRequestLayout() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        tableLayout.addView(new TextView(mContext));
-        tableLayout.addView(new ListView(mContext));
-        tableLayout.layout(0, 0, 200, 300);
-        assertFalse(tableLayout.isLayoutRequested());
-        assertFalse(tableLayout.getChildAt(0).isLayoutRequested());
-        assertFalse(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.addView(new TextView(mActivity));
+        mTableEmpty.addView(new ListView(mActivity));
+        mTableEmpty.layout(0, 0, 200, 300);
+        assertFalse(mTableEmpty.isLayoutRequested());
+        assertFalse(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertFalse(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.requestLayout();
-        assertTrue(tableLayout.isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.requestLayout();
+        assertTrue(mTableEmpty.isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessShrinkAllColumns() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        assertFalse(tableLayout.isShrinkAllColumns());
+        assertFalse(mTableEmpty.isShrinkAllColumns());
 
-        tableLayout.setShrinkAllColumns(true);
-        assertTrue(tableLayout.isShrinkAllColumns());
-        tableLayout.setShrinkAllColumns(false);
-        assertFalse(tableLayout.isShrinkAllColumns());
+        mTableEmpty.setShrinkAllColumns(true);
+        assertTrue(mTableEmpty.isShrinkAllColumns());
+        mTableEmpty.setShrinkAllColumns(false);
+        assertFalse(mTableEmpty.isShrinkAllColumns());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessStretchAllColumns() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        assertFalse(tableLayout.isStretchAllColumns());
+        assertFalse(mTableEmpty.isStretchAllColumns());
 
-        tableLayout.setStretchAllColumns(true);
-        assertTrue(tableLayout.isStretchAllColumns());
-        tableLayout.setStretchAllColumns(false);
-        assertFalse(tableLayout.isStretchAllColumns());
+        mTableEmpty.setStretchAllColumns(true);
+        assertTrue(mTableEmpty.isStretchAllColumns());
+        mTableEmpty.setStretchAllColumns(false);
+        assertFalse(mTableEmpty.isStretchAllColumns());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessColumnCollapsed() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        tableLayout.addView(new TextView(mContext));
-        tableLayout.addView(new TextView(mContext));
-        assertFalse(tableLayout.isColumnCollapsed(0));
-        assertFalse(tableLayout.isColumnCollapsed(1));
+        mTableEmpty.addView(new TextView(mActivity));
+        mTableEmpty.addView(new TextView(mActivity));
+        assertFalse(mTableEmpty.isColumnCollapsed(0));
+        assertFalse(mTableEmpty.isColumnCollapsed(1));
 
-        tableLayout.layout(0, 0, 200, 300);
-        assertFalse(tableLayout.getChildAt(0).isLayoutRequested());
-        assertFalse(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.layout(0, 0, 200, 300);
+        assertFalse(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertFalse(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.setColumnCollapsed(0, true);
-        assertTrue(tableLayout.isColumnCollapsed(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnCollapsed(0, true);
+        assertTrue(mTableEmpty.isColumnCollapsed(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnCollapsed(1, true);
-        assertTrue(tableLayout.isColumnCollapsed(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnCollapsed(1, true);
+        assertTrue(mTableEmpty.isColumnCollapsed(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnCollapsed(0, false);
-        assertFalse(tableLayout.isColumnCollapsed(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnCollapsed(0, false);
+        assertFalse(mTableEmpty.isColumnCollapsed(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnCollapsed(1, false);
-        assertFalse(tableLayout.isColumnCollapsed(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnCollapsed(1, false);
+        assertFalse(mTableEmpty.isColumnCollapsed(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessColumnStretchable() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        tableLayout.addView(new TableRow(mContext));
-        tableLayout.addView(new TableRow(mContext));
-        assertFalse(tableLayout.isColumnStretchable(0));
-        assertFalse(tableLayout.isColumnStretchable(1));
+        mTableEmpty.addView(new TableRow(mActivity));
+        mTableEmpty.addView(new TableRow(mActivity));
+        assertFalse(mTableEmpty.isColumnStretchable(0));
+        assertFalse(mTableEmpty.isColumnStretchable(1));
 
-        tableLayout.layout(0, 0, 200, 300);
-        assertFalse(tableLayout.getChildAt(0).isLayoutRequested());
-        assertFalse(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.layout(0, 0, 200, 300);
+        assertFalse(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertFalse(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.setColumnStretchable(0, true);
-        assertTrue(tableLayout.isColumnStretchable(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnStretchable(0, true);
+        assertTrue(mTableEmpty.isColumnStretchable(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnStretchable(1, true);
-        assertTrue(tableLayout.isColumnStretchable(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnStretchable(1, true);
+        assertTrue(mTableEmpty.isColumnStretchable(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnStretchable(0, false);
-        assertFalse(tableLayout.isColumnStretchable(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnStretchable(0, false);
+        assertFalse(mTableEmpty.isColumnStretchable(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnStretchable(1, false);
-        assertFalse(tableLayout.isColumnStretchable(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnStretchable(1, false);
+        assertFalse(mTableEmpty.isColumnStretchable(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
     }
 
-    public void testColumnStretchableEffect() {
-        final TableCtsActivity activity = getActivity();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                activity.setContentView(android.widget.cts.R.layout.table_layout_1);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        final TableLayout tableLayout =
-                (TableLayout) activity.findViewById(android.widget.cts.R.id.table1);
-
+    @Test
+    public void testColumnStretchableEffect() throws Throwable {
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         // Preparation: remove Collapsed mark for column 0.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setColumnCollapsed(0, false);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertFalse(tableLayout.isColumnStretchable(0));
-        assertFalse(tableLayout.isColumnStretchable(1));
-        assertTrue(tableLayout.isColumnStretchable(2));
+        mActivityRule.runOnUiThread(() -> mTableDefault.setColumnCollapsed(0, false));
+        instrumentation.waitForIdleSync();
+        assertFalse(mTableDefault.isColumnStretchable(0));
+        assertFalse(mTableDefault.isColumnStretchable(1));
+        assertTrue(mTableDefault.isColumnStretchable(2));
 
-        TextView column0 = (TextView) ((TableRow) tableLayout.getChildAt(0)).getChildAt(0);
-        TextView column1 = (TextView) ((TableRow) tableLayout.getChildAt(0)).getChildAt(1);
-        TextView column2 = (TextView) ((TableRow) tableLayout.getChildAt(0)).getChildAt(2);
+        TextView column0 = (TextView) ((TableRow) mTableDefault.getChildAt(0)).getChildAt(0);
+        TextView column1 = (TextView) ((TableRow) mTableDefault.getChildAt(0)).getChildAt(1);
+        TextView column2 = (TextView) ((TableRow) mTableDefault.getChildAt(0)).getChildAt(2);
         int oldWidth0 = column0.getWidth();
         int oldWidth1 = column1.getWidth();
         int oldWidth2 = column2.getWidth();
@@ -235,16 +249,12 @@
         int orignalWidth1 = column1.getMeasuredWidth();
         column2.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY);
         int orignalWidth2 = column2.getMeasuredWidth();
-        int totalSpace = tableLayout.getWidth() - orignalWidth0
+        int totalSpace = mTableDefault.getWidth() - orignalWidth0
                 - orignalWidth1 - orignalWidth2;
 
         // Test: set column 1 is able to be stretched.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setColumnStretchable(1, true);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mTableDefault.setColumnStretchable(1, true));
+        instrumentation.waitForIdleSync();
         assertEquals(oldWidth0, column0.getWidth());
         assertTrue(oldWidth1 < column1.getWidth());
         assertTrue(oldWidth2 > column2.getWidth());
@@ -257,12 +267,8 @@
         oldWidth2 = column2.getWidth();
 
         // Test: set column 0 is able to be stretched.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setColumnStretchable(0, true);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mTableDefault.setColumnStretchable(0, true));
+        instrumentation.waitForIdleSync();
         assertTrue(oldWidth0 < column0.getWidth());
         assertTrue(oldWidth1 > column1.getWidth());
         assertTrue(oldWidth2 > column2.getWidth());
@@ -275,12 +281,8 @@
         oldWidth2 = column2.getWidth();
 
         // Test: set column 2 is unable to be stretched.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setColumnStretchable(2, false);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mTableDefault.setColumnStretchable(2, false));
+        instrumentation.waitForIdleSync();
         // assertTrue(oldWidth0 < column0.getWidth());
         // assertTrue(oldWidth1 < column1.getWidth());
         assertEquals(oldWidth0, column0.getWidth());
@@ -296,13 +298,11 @@
         oldWidth2 = column2.getWidth();
 
         // Test: mark all columns are able to be stretched.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setStretchAllColumns(true);
-                tableLayout.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTableDefault.setStretchAllColumns(true);
+            mTableDefault.requestLayout();
         });
-        getInstrumentation().waitForIdleSync();
+        instrumentation.waitForIdleSync();
         // assertTrue(oldWidth0 > column0.getWidth());
         // assertTrue(oldWidth1 > column1.getWidth());
         assertEquals(oldWidth0, column0.getWidth());
@@ -317,13 +317,11 @@
         oldWidth2 = column2.getWidth();
 
         // Test: Remove the mark for all columns are able to be stretched.
-        getInstrumentation().runOnMainSync(new Runnable() {
-            public void run() {
-                tableLayout.setStretchAllColumns(false);
-                tableLayout.requestLayout();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTableDefault.setStretchAllColumns(false);
+            mTableDefault.requestLayout();
         });
-        getInstrumentation().waitForIdleSync();
+        instrumentation.waitForIdleSync();
         // assertTrue(oldWidth0 > column0.getWidth());
         // assertTrue(oldWidth1 > column1.getWidth());
         assertEquals(oldWidth0, column0.getWidth());
@@ -334,335 +332,303 @@
         assertEquals(orignalWidth2, column2.getWidth());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessColumnShrinkable() {
-        TableLayout tableLayout = new TableLayout(mContext);
-        tableLayout.addView(new TableRow(mContext));
-        tableLayout.addView(new TableRow(mContext));
-        assertFalse(tableLayout.isColumnShrinkable(0));
-        assertFalse(tableLayout.isColumnShrinkable(1));
+        mTableEmpty.addView(new TableRow(mActivity));
+        mTableEmpty.addView(new TableRow(mActivity));
+        assertFalse(mTableEmpty.isColumnShrinkable(0));
+        assertFalse(mTableEmpty.isColumnShrinkable(1));
 
-        tableLayout.layout(0, 0, 200, 300);
-        assertFalse(tableLayout.getChildAt(0).isLayoutRequested());
-        assertFalse(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.layout(0, 0, 200, 300);
+        assertFalse(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertFalse(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.setColumnShrinkable(0, true);
-        assertTrue(tableLayout.isColumnShrinkable(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnShrinkable(0, true);
+        assertTrue(mTableEmpty.isColumnShrinkable(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnShrinkable(1, true);
-        assertTrue(tableLayout.isColumnShrinkable(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnShrinkable(1, true);
+        assertTrue(mTableEmpty.isColumnShrinkable(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnShrinkable(0, false);
-        assertFalse(tableLayout.isColumnShrinkable(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnShrinkable(0, false);
+        assertFalse(mTableEmpty.isColumnShrinkable(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.setColumnShrinkable(1, false);
-        assertFalse(tableLayout.isColumnShrinkable(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.setColumnShrinkable(1, false);
+        assertFalse(mTableEmpty.isColumnShrinkable(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
     }
 
-    public void testAddView1() {
-        TableLayout tableLayout = new TableLayout(mContext);
+    @UiThreadTest
+    @Test
+    public void testAddView() {
+        View child1 = new TextView(mActivity);
+        mTableEmpty.addView(child1);
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
 
-        View child1 = new TextView(mContext);
-        tableLayout.addView(child1);
-        assertSame(child1, tableLayout.getChildAt(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.layout(0, 0, 200, 300);
+        View child2 = new RelativeLayout(mActivity);
+        mTableEmpty.addView(child2);
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertSame(child2, mTableEmpty.getChildAt(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        View child2 = new RelativeLayout(mContext);
-        tableLayout.addView(child2);
-        assertSame(child1, tableLayout.getChildAt(0));
-        assertSame(child2, tableLayout.getChildAt(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        tableLayout.layout(0, 0, 200, 300);
-
-        View child3 = new ListView(mContext);
-        tableLayout.addView(child3);
-        assertSame(child1, tableLayout.getChildAt(0));
-        assertSame(child2, tableLayout.getChildAt(1));
-        assertSame(child3, tableLayout.getChildAt(2));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(2).isLayoutRequested());
-
-        // exceptional
-        try {
-            tableLayout.addView(null);
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+        View child3 = new ListView(mActivity);
+        mTableEmpty.addView(child3);
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertSame(child2, mTableEmpty.getChildAt(1));
+        assertSame(child3, mTableEmpty.getChildAt(2));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(2).isLayoutRequested());
     }
 
-    public void testAddView2() {
-        TableLayout tableLayout = new TableLayout(mContext);
-
-        View child1 = new TextView(mContext);
-        tableLayout.addView(child1, 0);
-        assertSame(child1, tableLayout.getChildAt(0));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-
-        tableLayout.layout(0, 0, 200, 300);
-
-        View child2 = new RelativeLayout(mContext);
-        tableLayout.addView(child2, 0);
-        assertSame(child2, tableLayout.getChildAt(0));
-        assertSame(child1, tableLayout.getChildAt(1));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
-
-        tableLayout.layout(0, 0, 200, 300);
-
-        View child3 = new ListView(mContext);
-        tableLayout.addView(child3, -1);
-        assertSame(child2, tableLayout.getChildAt(0));
-        assertSame(child1, tableLayout.getChildAt(1));
-        assertSame(child3, tableLayout.getChildAt(2));
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(2).isLayoutRequested());
-
-        try {
-            tableLayout.addView(new ListView(mContext), Integer.MAX_VALUE);
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            tableLayout.addView(null, -1);
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddViewNull() {
+        mTableEmpty.addView(null);
     }
 
-    public void testAddView3() {
-        TableLayout tableLayout = new TableLayout(mContext);
+    @UiThreadTest
+    @Test
+    public void testAddViewAtIndex() {
+        View child1 = new TextView(mActivity);
+        mTableEmpty.addView(child1, 0);
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
 
-        View child1 = new TextView(mContext);
+        mTableEmpty.layout(0, 0, 200, 300);
+
+        View child2 = new RelativeLayout(mActivity);
+        mTableEmpty.addView(child2, 0);
+        assertSame(child2, mTableEmpty.getChildAt(0));
+        assertSame(child1, mTableEmpty.getChildAt(1));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
+
+        mTableEmpty.layout(0, 0, 200, 300);
+
+        View child3 = new ListView(mActivity);
+        mTableEmpty.addView(child3, -1);
+        assertSame(child2, mTableEmpty.getChildAt(0));
+        assertSame(child1, mTableEmpty.getChildAt(1));
+        assertSame(child3, mTableEmpty.getChildAt(2));
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(2).isLayoutRequested());
+    }
+
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddViewAtIndexTooLow() {
+        mTableEmpty.addView(null, -1);
+    }
+
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testAddViewAtIndexTooHigh() {
+        mTableEmpty.addView(new ListView(mActivity), Integer.MAX_VALUE);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAddViewWithLayoutParams() {
+        View child1 = new TextView(mActivity);
         assertNull(child1.getLayoutParams());
-        tableLayout.addView(child1, new ViewGroup.LayoutParams(100, 200));
-        assertSame(child1, tableLayout.getChildAt(0));
-        assertEquals(100, tableLayout.getChildAt(0).getLayoutParams().width);
-        assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
+        mTableEmpty.addView(child1, new ViewGroup.LayoutParams(100, 200));
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(0).getLayoutParams().width);
+        assertEquals(200, mTableEmpty.getChildAt(0).getLayoutParams().height);
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        View child2 = new TableRow(mContext);
+        View child2 = new TableRow(mActivity);
         assertNull(child2.getLayoutParams());
-        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(200, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().width);
-        assertEquals(300, tableLayout.getChildAt(1).getLayoutParams().height);
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
-
-        try {
-            tableLayout.addView(null, new TableLayout.LayoutParams(200, 300));
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            tableLayout.addView(new ListView(mContext), null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        mTableEmpty.addView(child2, new TableRow.LayoutParams(200, 300, 1));
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertSame(child2, mTableEmpty.getChildAt(1));
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(0).getLayoutParams().width);
+        assertEquals(200, mTableEmpty.getChildAt(0).getLayoutParams().height);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(1).getLayoutParams().width);
+        assertEquals(300, mTableEmpty.getChildAt(1).getLayoutParams().height);
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
     }
 
-    public void testAddView4() {
-        TableLayout tableLayout = new TableLayout(mContext);
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddViewWithLayoutParamsNullView() {
+        mTableEmpty.addView(null, new TableLayout.LayoutParams(200, 300));
+    }
 
-        View child1 = new TextView(mContext);
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddViewWithLayoutParamsNullLayoutParams() {
+        mTableEmpty.addView(new ListView(mActivity), null);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAddViewAtIndexWithLayoutParams() {
+        View child1 = new TextView(mActivity);
         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(200, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
+        mTableEmpty.addView(child1, 0, new ViewGroup.LayoutParams(100, 200));
+        assertSame(child1, mTableEmpty.getChildAt(0));
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(0).getLayoutParams().width);
+        assertEquals(200, mTableEmpty.getChildAt(0).getLayoutParams().height);
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        View child2 = new TableRow(mContext);
+        View child2 = new TableRow(mActivity);
         assertNull(child2.getLayoutParams());
-        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(300, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(100, tableLayout.getChildAt(1).getLayoutParams().width);
-        assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().height);
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
+        mTableEmpty.addView(child2, 0, new TableRow.LayoutParams(200, 300, 1));
+        assertSame(child2, mTableEmpty.getChildAt(0));
+        assertSame(child1, mTableEmpty.getChildAt(1));
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(0).getLayoutParams().width);
+        assertEquals(300, mTableEmpty.getChildAt(0).getLayoutParams().height);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(1).getLayoutParams().width);
+        assertEquals(200, mTableEmpty.getChildAt(1).getLayoutParams().height);
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
 
-        tableLayout.layout(0, 0, 200, 300);
+        mTableEmpty.layout(0, 0, 200, 300);
 
-        View child3 = new ListView(mContext);
+        View child3 = new ListView(mActivity);
         assertNull(child3.getLayoutParams());
-        tableLayout.addView(child3, -1, new ListView.LayoutParams(300, 400));
-        assertSame(child2, tableLayout.getChildAt(0));
-        assertSame(child1, tableLayout.getChildAt(1));
-        assertSame(child3, tableLayout.getChildAt(2));
-        assertEquals(200, tableLayout.getChildAt(0).getLayoutParams().width);
-        assertEquals(300, tableLayout.getChildAt(0).getLayoutParams().height);
-        assertEquals(100, tableLayout.getChildAt(1).getLayoutParams().width);
-        assertEquals(200, tableLayout.getChildAt(1).getLayoutParams().height);
-        assertEquals(300, tableLayout.getChildAt(2).getLayoutParams().width);
-        assertEquals(400, tableLayout.getChildAt(2).getLayoutParams().height);
-        assertTrue(tableLayout.getChildAt(0).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(1).isLayoutRequested());
-        assertTrue(tableLayout.getChildAt(2).isLayoutRequested());
-
-        try {
-            tableLayout.addView(new ListView(mContext), Integer.MAX_VALUE,
-                    new TableLayout.LayoutParams(200, 300));
-            fail("Should throw IndexOutOfBoundsException");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        try {
-            tableLayout.addView(null, -1, new TableLayout.LayoutParams(200, 300));
-            fail("Should throw IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            tableLayout.addView(new ListView(mContext), -1, null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
+        mTableEmpty.addView(child3, -1, new ListView.LayoutParams(300, 400));
+        assertSame(child2, mTableEmpty.getChildAt(0));
+        assertSame(child1, mTableEmpty.getChildAt(1));
+        assertSame(child3, mTableEmpty.getChildAt(2));
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(0).getLayoutParams().width);
+        assertEquals(300, mTableEmpty.getChildAt(0).getLayoutParams().height);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(1).getLayoutParams().width);
+        assertEquals(200, mTableEmpty.getChildAt(1).getLayoutParams().height);
+        assertEquals(ViewGroup.LayoutParams.MATCH_PARENT,
+                mTableEmpty.getChildAt(2).getLayoutParams().width);
+        assertEquals(400, mTableEmpty.getChildAt(2).getLayoutParams().height);
+        assertTrue(mTableEmpty.getChildAt(0).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(1).isLayoutRequested());
+        assertTrue(mTableEmpty.getChildAt(2).isLayoutRequested());
     }
 
-    public void testGenerateLayoutParams1() {
-        TableLayout tableLayout = new TableLayout(mContext);
+    @UiThreadTest
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testAddViewAtIndexWithLayoutParamsIndexTooHigh() {
+        mTableEmpty.addView(new ListView(mActivity), Integer.MAX_VALUE,
+                new TableLayout.LayoutParams(200, 300));
+    }
 
-        TableCtsActivity activity = getActivity();
-        XmlResourceParser parser = activity.getResources().getLayout(R.layout.table_layout_1);
+    @UiThreadTest
+    @Test(expected=IllegalArgumentException.class)
+    public void testAddViewAtIndexWithLayoutParamsNullView() {
+        mTableEmpty.addView(null, -1, new TableLayout.LayoutParams(200, 300));
+    }
+
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testAddViewAtIndexWithLayoutParamsNullLayoutParams() {
+        mTableEmpty.addView(new ListView(mActivity), -1, null);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGenerateLayoutParamsFromAttributeSet() {
+        XmlResourceParser parser = mActivity.getResources().getLayout(R.layout.table_layout_1);
         AttributeSet attr = Xml.asAttributeSet(parser);
 
-        assertNotNull(tableLayout.generateLayoutParams(attr));
+        assertNotNull(mTableEmpty.generateLayoutParams(attr));
 
-        assertNotNull(tableLayout.generateLayoutParams((AttributeSet) null));
+        assertNotNull(mTableEmpty.generateLayoutParams((AttributeSet) null));
     }
 
+    @UiThreadTest
+    @Test
     public void testCheckLayoutParams() {
-        MockTableLayout mockTableLayout = new MockTableLayout(mContext);
+        assertTrue(mTableCustomEmpty.checkLayoutParams(new TableLayout.LayoutParams(200, 300)));
 
-        assertTrue(mockTableLayout.checkLayoutParams(new TableLayout.LayoutParams(200, 300)));
+        assertFalse(mTableCustomEmpty.checkLayoutParams(new ViewGroup.LayoutParams(200, 300)));
 
-        assertFalse(mockTableLayout.checkLayoutParams(new ViewGroup.LayoutParams(200, 300)));
+        assertFalse(mTableCustomEmpty.checkLayoutParams(new RelativeLayout.LayoutParams(200, 300)));
 
-        assertFalse(mockTableLayout.checkLayoutParams(new RelativeLayout.LayoutParams(200, 300)));
-
-        assertFalse(mockTableLayout.checkLayoutParams(null));
+        assertFalse(mTableCustomEmpty.checkLayoutParams(null));
     }
 
+    @UiThreadTest
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        MockTableLayout mockTableLayout = new MockTableLayout(mContext);
-
-        LinearLayout.LayoutParams layoutParams = mockTableLayout.generateDefaultLayoutParams();
+        LinearLayout.LayoutParams layoutParams = mTableCustomEmpty.generateDefaultLayoutParams();
         assertNotNull(layoutParams);
         assertTrue(layoutParams instanceof TableLayout.LayoutParams);
     }
 
-    public void testGenerateLayoutParams2() {
-        MockTableLayout mockTableLayout = new MockTableLayout(mContext);
-
-        LinearLayout.LayoutParams layoutParams = mockTableLayout.generateLayoutParams(
+    @UiThreadTest
+    @Test
+    public void testGenerateLayoutParamsFromLayoutParams() {
+        LinearLayout.LayoutParams layoutParams = mTableCustomEmpty.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);
-
-        try {
-            layoutParams = mockTableLayout.generateLayoutParams((ViewGroup.LayoutParams) null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testGenerateLayoutParamsFromLayoutParamsNull() {
+        mTableCustomEmpty.generateLayoutParams((ViewGroup.LayoutParams) null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testOnLayout() {
-        MockTableLayout mockTableLayout = new MockTableLayout(mContext);
-
-        mockTableLayout.onLayout(false, 0, 0, 20, 20);
+        mTableCustomEmpty.onLayout(false, 0, 0, 20, 20);
     }
 
+    @UiThreadTest
+    @Test
     public void testOnMeasure() {
-        MockTableLayout mockTableLayout = new MockTableLayout(mContext);
-
-        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;
-        }
+        mTableCustomEmpty.onMeasure(MeasureSpec.EXACTLY, MeasureSpec.EXACTLY);
     }
 
     /*
      * Mock class for TableLayout to test protected methods
      */
-    private class MockTableLayout extends TableLayout {
+    public static class MockTableLayout extends TableLayout {
         public MockTableLayout(Context context) {
             super(context);
         }
 
+        public MockTableLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         @Override
         protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
             return super.checkLayoutParams(p);
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..009937f 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
@@ -16,56 +16,85 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.ViewGroup;
 import android.widget.TableLayout;
 import android.widget.cts.util.XmlUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link TableLayout.LayoutParams}.
  */
-public class TableLayout_LayoutParamsTest extends InstrumentationTestCase {
-    private Context mTargetContext;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TableLayout_LayoutParamsTest {
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTargetContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
     public void testConstructor() {
-        new TableLayout.LayoutParams(mTargetContext, null);
-
-        TableLayout.LayoutParams layoutParams = new TableLayout.LayoutParams(200, 300);
+        // 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(300, layoutParams.height);
-        TableLayout.LayoutParams oldParams = layoutParams;
+        assertEquals(TableLayout.LayoutParams.WRAP_CONTENT, layoutParams.height);
 
-        layoutParams = new TableLayout.LayoutParams(200, 300, 1.2f);
+        // We expect width to be MATCH and height to be WRAP as documented in TableLayout
+        layoutParams = new TableLayout.LayoutParams(mContext, null);
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, layoutParams.width);
-        assertEquals(300, layoutParams.height);
-        assertEquals(1.2f, layoutParams.weight);
-        TableLayout.LayoutParams oldMarginParams = layoutParams;
+        assertEquals(TableLayout.LayoutParams.WRAP_CONTENT, layoutParams.height);
 
-        new TableLayout.LayoutParams();
-
-        layoutParams = new TableLayout.LayoutParams(oldParams);
+        // 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);
 
-        layoutParams = new TableLayout.LayoutParams(oldMarginParams);
+        // 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, 0.0f);
+
+        // 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(360, layoutParams.height);
+
+        // 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(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, 0.0f);
     }
 
+    @Test
     public void testSetBaseAttributes() {
         MockTableLayout_LayoutParams mockLayoutParams = new MockTableLayout_LayoutParams(200, 300);
         assertEquals(TableLayout.LayoutParams.MATCH_PARENT, mockLayoutParams.width);
@@ -73,7 +102,7 @@
 
         // base_attr_pixel: layout_width = 400px, layout_height = 600px
         AttributeSet attrs = getAttrs("base_attr_pixel");
-        TypedArray a = mTargetContext.obtainStyledAttributes(attrs,
+        TypedArray a = mContext.obtainStyledAttributes(attrs,
                 android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
@@ -89,7 +118,7 @@
         a.recycle();
         // base_attr_fillwrap: layout_width = "match_parent", layout_height = "wrap_content"
         attrs = getAttrs("base_attr_fillwrap");
-        a = mTargetContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
+        a = mContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
                 android.R.styleable.ViewGroup_Layout_layout_height);
@@ -104,7 +133,7 @@
         a.recycle();
         // base_attr_noheight: layout_width = 600px, no layout_height.
         attrs = getAttrs("base_attr_noheight");
-        a = mTargetContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
+        a = mContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
                 android.R.styleable.ViewGroup_Layout_layout_height);
@@ -140,7 +169,7 @@
         XmlResourceParser parser = null;
         AttributeSet attrs = null;
         try {
-            parser = mTargetContext.getResources().getXml(R.xml.base_attributes);
+            parser = mContext.getResources().getXml(R.xml.base_attributes);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/tests/tests/widget/src/android/widget/cts/TableRowTest.java b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
index 2e917f8..330a818 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRowTest.java
@@ -16,79 +16,95 @@
 
 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.assertNull;
+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 android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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;
-
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link TableRow}.
  */
-public class TableRowTest extends ActivityInstrumentationTestCase2<TableCtsActivity> {
-    Context mContext;
-    Context mTargetContext;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TableRowTest {
+    private Activity mActivity;
 
-    public TableRowTest() {
-        super("android.widget.cts", TableCtsActivity.class);
+    @Rule
+    public ActivityTestRule<TableCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TableCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getContext();
-        mTargetContext = getInstrumentation().getTargetContext();
-    }
-
+    @Test
     public void testConstructor() {
-        new TableRow(mContext);
+        new TableRow(mActivity);
 
-        new TableRow(mContext, null);
-    }
-
-    public void testSetOnHierarchyChangeListener() {
-        TableRow tableRow = new TableRow(mContext);
-
-        MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
-        tableRow.setOnHierarchyChangeListener(listener);
-
-        tableRow.addView(new TextView(mContext));
-        assertTrue(listener.hasCalledOnChildViewAdded());
-        tableRow.removeViewAt(0);
-        assertTrue(listener.hasCalledOnChildViewRemoved());
-
-        listener.reset();
-
-        tableRow.setOnHierarchyChangeListener(null);
-        tableRow.addView(new TextView(mContext));
-        assertFalse(listener.hasCalledOnChildViewAdded());
-        tableRow.removeViewAt(0);
-        assertFalse(listener.hasCalledOnChildViewRemoved());
+        new TableRow(mActivity, null);
     }
 
     @UiThreadTest
+    @Test
+    public void testSetOnHierarchyChangeListener() {
+        TableRow tableRow = new TableRow(mActivity);
+
+        ViewGroup.OnHierarchyChangeListener mockHierarchyChangeListener =
+                mock(ViewGroup.OnHierarchyChangeListener.class);
+        tableRow.setOnHierarchyChangeListener(mockHierarchyChangeListener);
+
+        View toAdd = new TextView(mActivity);
+        tableRow.addView(toAdd);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewAdded(tableRow, toAdd);
+        tableRow.removeViewAt(0);
+        verify(mockHierarchyChangeListener, times(1)).onChildViewRemoved(tableRow, toAdd);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
+
+        tableRow.setOnHierarchyChangeListener(null);
+        tableRow.addView(new TextView(mActivity));
+        tableRow.removeViewAt(0);
+        verifyNoMoreInteractions(mockHierarchyChangeListener);
+    }
+
+    @UiThreadTest
+    @Test
     public void testGetVirtualChildAt() {
-        TableCtsActivity activity = getActivity();
-        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
-        TableLayout tableLayout = (TableLayout) activity
+        mActivity.setContentView(android.widget.cts.R.layout.table_layout_1);
+        TableLayout tableLayout = (TableLayout) mActivity
                 .findViewById(android.widget.cts.R.id.table1);
 
         TableRow tableRow = (TableRow) tableLayout.getChildAt(0);
-        Resources resources = activity.getResources();
+        Resources resources = mActivity.getResources();
         assertEquals(resources.getString(R.string.table_layout_first),
                 ((TextView) tableRow.getVirtualChildAt(0)).getText().toString());
         assertEquals(resources.getString(R.string.table_layout_second),
@@ -96,8 +112,8 @@
         assertEquals(resources.getString(R.string.table_layout_third),
                 ((TextView) tableRow.getVirtualChildAt(2)).getText().toString());
 
-        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
+        mActivity.setContentView(android.widget.cts.R.layout.table_layout_2);
+        tableLayout = (TableLayout) mActivity.findViewById(android.widget.cts.R.id.table2);
 
         tableRow = (TableRow) tableLayout.getChildAt(0);
         assertNull(tableRow.getVirtualChildAt(0));
@@ -112,26 +128,27 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetVirtualChildCount() {
-        TableCtsActivity activity = getActivity();
-        activity.setContentView(android.widget.cts.R.layout.table_layout_1);
-        TableLayout tableLayout = (TableLayout) activity
+        mActivity.setContentView(android.widget.cts.R.layout.table_layout_1);
+        TableLayout tableLayout = (TableLayout) mActivity
                 .findViewById(android.widget.cts.R.id.table1);
 
         TableRow tableRow = (TableRow) tableLayout.getChildAt(0);
         assertEquals(3, tableRow.getVirtualChildCount());
 
-        activity.setContentView(android.widget.cts.R.layout.table_layout_2);
-        tableLayout = (TableLayout) activity.findViewById(android.widget.cts.R.id.table2);
+        mActivity.setContentView(android.widget.cts.R.layout.table_layout_2);
+        tableLayout = (TableLayout) mActivity.findViewById(android.widget.cts.R.id.table2);
 
         tableRow = (TableRow) tableLayout.getChildAt(0);
         assertEquals(5, tableRow.getVirtualChildCount());
     }
 
-    public void testGenerateLayoutParams() {
-        TableRow tableRow = new TableRow(mContext);
+    @Test
+    public void testGenerateLayoutParamsFromAttributeSet() {
+        TableRow tableRow = new TableRow(mActivity);
 
-        Resources resources = mTargetContext.getResources();
+        Resources resources = mActivity.getResources();
         XmlResourceParser parser = resources.getLayout(R.layout.table_layout_1);
         AttributeSet attr = Xml.asAttributeSet(parser);
 
@@ -140,8 +157,9 @@
         assertNotNull(tableRow.generateLayoutParams((AttributeSet) null));
     }
 
+    @Test
     public void testCheckLayoutParams() {
-        MockTableRow mockTableRow = new MockTableRow(mContext);
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
 
         assertTrue(mockTableRow.checkLayoutParams(new TableRow.LayoutParams(200, 300)));
 
@@ -152,16 +170,18 @@
         assertFalse(mockTableRow.checkLayoutParams(null));
     }
 
+    @Test
     public void testGenerateDefaultLayoutParams() {
-        MockTableRow mockTableRow = new MockTableRow(mContext);
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
 
         LinearLayout.LayoutParams layoutParams = mockTableRow.generateDefaultLayoutParams();
         assertNotNull(layoutParams);
         assertTrue(layoutParams instanceof TableRow.LayoutParams);
     }
 
-    public void testGenerateLayoutParams2() {
-        MockTableRow mockTableRow = new MockTableRow(mContext);
+    @Test
+    public void testGenerateLayoutParamsFromLayoutParams() {
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
 
         LinearLayout.LayoutParams layoutParams = mockTableRow.generateLayoutParams(
                 new ViewGroup.LayoutParams(200, 300));
@@ -169,66 +189,29 @@
         assertEquals(200, layoutParams.width);
         assertEquals(300, layoutParams.height);
         assertTrue(layoutParams instanceof TableRow.LayoutParams);
-
-        try {
-            layoutParams = mockTableRow.generateLayoutParams((ViewGroup.LayoutParams) null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testGenerateLayoutParamsFromLayoutParamsNull() {
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
+
+        mockTableRow.generateLayoutParams((ViewGroup.LayoutParams) null);
+    }
+
+    @Test
     public void testOnLayout() {
-        MockTableRow mockTableRow = new MockTableRow(mContext);
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
 
         mockTableRow.onLayout(false, 0, 0, 200, 300);
     }
 
+    @Test
     public void testOnMeasure() {
-        MockTableRow mockTableRow = new MockTableRow(mContext);
+        MockTableRow mockTableRow = new MockTableRow(mActivity);
 
         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..453b0c1 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
@@ -16,15 +16,16 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
+import android.app.Activity;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -34,26 +35,33 @@
 import android.widget.TableRow;
 import android.widget.cts.util.XmlUtils;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link TableRow.LayoutParams}.
  */
-public class TableRow_LayoutParamsTest
-        extends ActivityInstrumentationTestCase2<TableCtsActivity> {
-    Context mTargetContext;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TableRow_LayoutParamsTest {
+    private Activity mActivity;
 
-    public TableRow_LayoutParamsTest() {
-        super("android.widget.cts", TableCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<TableCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TableCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTargetContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-        new TableRow.LayoutParams(mTargetContext, null);
+        new TableRow.LayoutParams(mActivity, null);
 
         TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(200, 300);
         assertEquals(200, layoutParams.width);
@@ -65,7 +73,7 @@
         layoutParams = new TableRow.LayoutParams(200, 300, 1.2f);
         assertEquals(200, layoutParams.width);
         assertEquals(300, layoutParams.height);
-        assertEquals(1.2f, layoutParams.weight);
+        assertEquals(1.2f, layoutParams.weight, 0.0f);
         assertEquals(-1, layoutParams.column);
         assertEquals(1, layoutParams.span);
         MarginLayoutParams oldMarginParams = layoutParams;
@@ -90,17 +98,15 @@
         assertEquals(0, layoutParams.column);
         assertEquals(0, layoutParams.span);
 
-        TableCtsActivity activity = getActivity();
-        activity.setContentView(R.layout.table_layout_2);
+        mActivity.setContentView(R.layout.table_layout_2);
         int idTable = R.id.table2;
-        TableLayout tableLayout = (TableLayout) activity.findViewById(idTable);
-        View vVitural1 = ((TableRow) tableLayout.getChildAt(0)).getVirtualChildAt(1);
-        layoutParams = (TableRow.LayoutParams) vVitural1.getLayoutParams();
+        TableLayout tableLayout = (TableLayout) mActivity.findViewById(idTable);
+        View vVirtual1 = ((TableRow) tableLayout.getChildAt(0)).getVirtualChildAt(1);
+        layoutParams = (TableRow.LayoutParams) vVirtual1.getLayoutParams();
         assertEquals(1, layoutParams.column);
-        View vVitural2 = ((TableRow) tableLayout.getChildAt(0)).getVirtualChildAt(2);
-        layoutParams = (TableRow.LayoutParams) vVitural2.getLayoutParams();
+        View vVirtual2 = ((TableRow) tableLayout.getChildAt(0)).getVirtualChildAt(2);
+        layoutParams = (TableRow.LayoutParams) vVirtual2.getLayoutParams();
         assertEquals(2, layoutParams.span);
-
     }
 
     /**
@@ -109,6 +115,7 @@
      * setBaseAttributes(android.content.res.TypedArray, int, int)}
      * .
      */
+    @Test
     public void testSetBaseAttributes() {
         MockTableRow_LayoutParams mockLayoutParams = new MockTableRow_LayoutParams(200, 300);
         assertEquals(200, mockLayoutParams.width);
@@ -116,7 +123,7 @@
 
         // base_attr_pixel: layout_width = 400px, layout_height = 600px
         AttributeSet attrs = getAttrs("base_attr_pixel");
-        TypedArray a = mTargetContext.obtainStyledAttributes(attrs,
+        TypedArray a = mActivity.obtainStyledAttributes(attrs,
                 android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
@@ -132,7 +139,7 @@
         a.recycle();
         // base_attr_fillwrap: layout_width = "match_parent", layout_height = "wrap_content"
         attrs = getAttrs("base_attr_fillwrap");
-        a = mTargetContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
+        a = mActivity.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
                 android.R.styleable.ViewGroup_Layout_layout_height);
@@ -147,7 +154,7 @@
         a.recycle();
         // base_attr_noheight: layout_width = 600px, no layout_height.
         attrs = getAttrs("base_attr_noheight");
-        a = mTargetContext.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
+        a = mActivity.obtainStyledAttributes(attrs, android.R.styleable.ViewGroup_Layout);
 
         mockLayoutParams.setBaseAttributes(a, android.R.styleable.ViewGroup_Layout_layout_width,
                 android.R.styleable.ViewGroup_Layout_layout_height);
@@ -186,7 +193,7 @@
         XmlResourceParser parser = null;
         AttributeSet attrs = null;
         try {
-            parser = mTargetContext.getResources().getXml(R.xml.base_attributes);
+            parser = mActivity.getResources().getXml(R.xml.base_attributes);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/tests/tests/widget/src/android/widget/cts/TextSwitcherCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TextSwitcherCtsActivity.java
new file mode 100644
index 0000000..ef7fc1d
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/TextSwitcherCtsActivity.java
@@ -0,0 +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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class TextSwitcherCtsActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.textswitcher_layout);
+    }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/TextSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/TextSwitcherTest.java
index 7812807..fb99cc7 100644
--- a/tests/tests/widget/src/android/widget/cts/TextSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextSwitcherTest.java
@@ -16,20 +16,31 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
 
-import android.content.Context;
-import android.test.InstrumentationTestCase;
+import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.ViewGroup;
 import android.widget.ListView;
 import android.widget.TextSwitcher;
 import android.widget.TextView;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link TextSwitcher}.
  */
-public class TextSwitcherTest extends InstrumentationTestCase {
-    private Context mContext;
-
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TextSwitcherTest {
     /**
      * test width to be used in addView() method.
      */
@@ -39,157 +50,165 @@
      */
     private static final int PARAMS_HEIGHT = 300;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getContext();
+    private Activity mActivity;
+    private TextSwitcher mTextSwitcher;
+
+    @Rule
+    public ActivityTestRule<TextSwitcherCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TextSwitcherCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mTextSwitcher = (TextSwitcher) mActivity.findViewById(R.id.switcher);
     }
 
+    @Test
     public void testConstructor() {
-        new TextSwitcher(mContext);
+        new TextSwitcher(mActivity);
 
-        new TextSwitcher(mContext, null);
+        new TextSwitcher(mActivity, null);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetText() {
         final String viewText1 = "Text 1";
         final String viewText2 = "Text 2";
         final String changedText = "Changed";
 
-        TextSwitcher textSwitcher = new TextSwitcher(mContext);
-
-        TextView tv1 = new TextView(mContext);
-        TextView tv2 = new TextView(mContext);
+        TextView tv1 = new TextView(mActivity);
+        TextView tv2 = new TextView(mActivity);
         tv1.setText(viewText1);
         tv2.setText(viewText2);
-        textSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
-        textSwitcher.addView(tv2, 1, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+        mTextSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+        mTextSwitcher.addView(tv2, 1, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
 
-        TextView tvChild1 = (TextView) textSwitcher.getChildAt(0);
-        TextView tvChild2 = (TextView) textSwitcher.getChildAt(1);
+        TextView tvChild1 = (TextView) mTextSwitcher.getChildAt(0);
+        TextView tvChild2 = (TextView) mTextSwitcher.getChildAt(1);
         assertEquals(viewText1, (tvChild1.getText().toString()));
         assertEquals(viewText2, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
 
         // tvChild2's text is changed
-        textSwitcher.setText(changedText);
+        mTextSwitcher.setText(changedText);
         assertEquals(viewText1, (tvChild1.getText().toString()));
         assertEquals(changedText, (tvChild2.getText().toString()));
-        assertSame(tv2, textSwitcher.getCurrentView());
+        assertSame(tv2, mTextSwitcher.getCurrentView());
 
         // tvChild1's text is changed
-        textSwitcher.setText(changedText);
+        mTextSwitcher.setText(changedText);
         assertEquals(changedText, (tvChild1.getText().toString()));
         assertEquals(changedText, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
 
         // tvChild2's text is changed
-        textSwitcher.setText(null);
+        mTextSwitcher.setText(null);
         assertEquals(changedText, (tvChild1.getText().toString()));
         assertEquals("", (tvChild2.getText().toString()));
-        assertSame(tv2, textSwitcher.getCurrentView());
+        assertSame(tv2, mTextSwitcher.getCurrentView());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetCurrentText() {
         final String viewText1 = "Text 1";
         final String viewText2 = "Text 2";
         final String changedText1 = "Changed 1";
         final String changedText2 = "Changed 2";
 
-        TextSwitcher textSwitcher = new TextSwitcher(mContext);
-
-        TextView tv1 = new TextView(mContext);
-        TextView tv2 = new TextView(mContext);
+        TextView tv1 = new TextView(mActivity);
+        TextView tv2 = new TextView(mActivity);
         tv1.setText(viewText1);
         tv2.setText(viewText2);
-        textSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
-        textSwitcher.addView(tv2, 1, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+        mTextSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+        mTextSwitcher.addView(tv2, 1, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
 
-        TextView tvChild1 = (TextView) textSwitcher.getChildAt(0);
-        TextView tvChild2 = (TextView) textSwitcher.getChildAt(1);
+        TextView tvChild1 = (TextView) mTextSwitcher.getChildAt(0);
+        TextView tvChild2 = (TextView) mTextSwitcher.getChildAt(1);
         assertEquals(viewText1, (tvChild1.getText().toString()));
         assertEquals(viewText2, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
 
         // tvChild1's text is changed
-        textSwitcher.setCurrentText(changedText1);
+        mTextSwitcher.setCurrentText(changedText1);
         assertEquals(changedText1, (tvChild1.getText().toString()));
         assertEquals(viewText2, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
 
         // tvChild1's text is changed
-        textSwitcher.setCurrentText(changedText2);
+        mTextSwitcher.setCurrentText(changedText2);
         assertEquals(changedText2, (tvChild1.getText().toString()));
         assertEquals(viewText2, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
 
         // tvChild1's text is changed
-        textSwitcher.setCurrentText(null);
+        mTextSwitcher.setCurrentText(null);
         assertEquals("", (tvChild1.getText().toString()));
         assertEquals(viewText2, (tvChild2.getText().toString()));
-        assertSame(tv1, textSwitcher.getCurrentView());
+        assertSame(tv1, mTextSwitcher.getCurrentView());
     }
 
+    @UiThreadTest
+    @Test
     public void testAddView() {
-        TextSwitcher textSwitcher = new TextSwitcher(mContext);
+        TextView tv1 = new TextView(mActivity);
+        TextView tv2 = new TextView(mActivity);
 
-        TextView tv1 = new TextView(mContext);
-        TextView tv2 = new TextView(mContext);
-
-        textSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
-        assertSame(tv1, textSwitcher.getChildAt(0));
-        assertEquals(1, textSwitcher.getChildCount());
+        mTextSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+        assertSame(tv1, mTextSwitcher.getChildAt(0));
+        assertEquals(1, mTextSwitcher.getChildCount());
 
         try {
             // tv1 already has a parent
-            textSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+            mTextSwitcher.addView(tv1, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
             fail("Should throw IllegalStateException");
         } catch (IllegalStateException e) {
             // expected
         }
 
         try {
-            textSwitcher.addView(tv2, Integer.MAX_VALUE,
+            mTextSwitcher.addView(tv2, Integer.MAX_VALUE,
                     new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
             fail("Should throw IndexOutOfBoundsException");
         } catch (IndexOutOfBoundsException e) {
             // expected
         }
 
-        textSwitcher.addView(tv2, 1,
+        mTextSwitcher.addView(tv2, 1,
                 new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
-        assertSame(tv2, textSwitcher.getChildAt(1));
-        assertEquals(2, textSwitcher.getChildCount());
+        assertSame(tv2, mTextSwitcher.getChildAt(1));
+        assertEquals(2, mTextSwitcher.getChildCount());
 
-        TextView tv3 = new TextView(mContext);
+        TextView tv3 = new TextView(mActivity);
 
         try {
-            // textSwitcher already has 2 children.
-            textSwitcher.addView(tv3, 2, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+            // mTextSwitcher already has 2 children.
+            mTextSwitcher.addView(tv3, 2, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
             fail("Should throw IllegalStateException");
         } catch (IllegalStateException e) {
             // expected
         }
 
-        textSwitcher = new TextSwitcher(mContext);
-        ListView lv = new ListView(mContext);
+        mTextSwitcher = new TextSwitcher(mActivity);
+        ListView lv = new ListView(mActivity);
 
         try {
-            textSwitcher.addView(lv, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+            mTextSwitcher.addView(lv, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
             fail("Should throw IllegalArgumentException");
         } catch (IllegalArgumentException e) {
             // expected
         }
 
         try {
-            textSwitcher.addView(null, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
+            mTextSwitcher.addView(null, 0, new ViewGroup.LayoutParams(PARAMS_WIDTH, PARAMS_HEIGHT));
             fail("Should throw IllegalArgumentException");
         } catch (IllegalArgumentException e) {
             // expected
         }
 
         try {
-            textSwitcher.addView(tv3, 0, null);
+            mTextSwitcher.addView(tv3, 0, null);
             fail("Should throw NullPointerException");
         } catch (NullPointerException e) {
             // expected
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..7c7b892 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewFadingEdgeTest.java
@@ -16,22 +16,42 @@
 
 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;
 
-public class TextViewFadingEdgeTest extends ActivityInstrumentationTestCase2<EmptyCtsActivity> {
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+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.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TextViewFadingEdgeTest {
+    private Activity mActivity;
+
+    @Rule
+    public ActivityTestRule<EmptyCtsActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyCtsActivity.class);
 
     public static final float DELTA = 0.01f;
     private static final String LONG_RTL_STRING = "مرحبا الروبوت مرحبا الروبوت مرحبا الروبوت";
@@ -113,22 +133,14 @@
                     LONG_RTL_STRING, true, NO_GRAVITY, TEXT_ALIGNMENT_INHERIT, true, 1f, 1f)
     };
 
-    public TextViewFadingEdgeTest() {
-        super("android.widget.cts", EmptyCtsActivity.class);
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return getActivity().hasWindowFocus();
-            }
-        }.run();
-    }
-
-    public void testFadingEdge() {
+    @Test
+    public void testFadingEdge() throws Throwable {
         for (TestCase data : TEST_DATA) {
             MockTextView textView = createTextView(data.text, data.horizontalFadingEnabled,
                     data.gravity, data.textAlignment, data.scrollToMiddle);
@@ -141,8 +153,8 @@
     }
 
     private final MockTextView createTextView(String text, boolean horizontalFadingEnabled,
-            int gravity, int textAlignment, boolean scrollToMiddle) {
-        final MockTextView textView = new MockTextView(getActivity());
+            int gravity, int textAlignment, boolean scrollToMiddle) throws Throwable {
+        final MockTextView textView = new MockTextView(mActivity);
         textView.setSingleLine(true);
         textView.setTextSize(30);
         textView.setPadding(ANY_PADDING, ANY_PADDING, ANY_PADDING, ANY_PADDING);
@@ -154,32 +166,24 @@
         textView.setGravity(gravity);
         textView.setTextAlignment(textAlignment);
 
-        final FrameLayout layout = new FrameLayout(getActivity());
+        final FrameLayout layout = new FrameLayout(mActivity);
         ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT);
         layout.setLayoutParams(layoutParams);
         layout.addView(textView);
 
-        getActivity().runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        if(scrollToMiddle) {
-            getActivity().runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    float lineMid = (textView.getLayout().getLineLeft(0) +
-                            textView.getLayout().getLineRight(0)) / 2;
-                    int scrollPosition = (int) lineMid;
-                    textView.setScrollX(scrollPosition);
-                }
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        if (scrollToMiddle) {
+            mActivityRule.runOnUiThread(() -> {
+                float lineMid = (textView.getLayout().getLineLeft(0) +
+                        textView.getLayout().getLineRight(0)) / 2;
+                int scrollPosition = (int) lineMid;
+                textView.setScrollX(scrollPosition);
             });
         }
-        getInstrumentation().waitForIdleSync();
+        instrumentation.waitForIdleSync();
         return textView;
     }
 
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index fea0a55..29b7ed9 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -16,20 +16,42 @@
 
 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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.refEq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+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;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
 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.PollingCheck;
-import android.cts.util.WidgetTestUtils;
-import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -39,13 +61,18 @@
 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.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
@@ -73,37 +100,55 @@
 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;
 import android.text.util.Linkify;
 import android.util.DisplayMetrics;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ActionMode;
 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.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 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 com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -112,11 +157,14 @@
 /**
  * Test {@link TextView}.
  */
-public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewCtsActivity> {
-
-    private TextView mTextView;
-    private Activity mActivity;
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TextViewTest {
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private TextView mTextView;
+    private TextView mSecondTextView;
+
     private static final String 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. "
@@ -124,50 +172,62 @@
             + "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);
-    }
+    @Rule
+    public ActivityTestRule<TextViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TextViewCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-                protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
-        mKeyEventUtil = new KeyEventUtil(mInstrumentation);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        PollingCheck.waitFor(mActivity::hasWindowFocus);
     }
 
     /**
-     * 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 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() throws Throwable {
+        mActivityRule.runOnUiThread(this::initTextViewForTyping);
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testConstructor() {
+    @UiThreadTest
+    @Test
+    public void testConstructorOnUiThread() {
+        verifyConstructor();
+    }
+
+    @Test
+    public void testConstructorOffUiThread() {
+        verifyConstructor();
+    }
+
+    private void verifyConstructor() {
         new TextView(mActivity);
-
         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
+    @Test
     public void testAccessText() {
         TextView tv = findTextView(R.id.textview_text);
 
@@ -179,6 +239,8 @@
         assertEquals("", tv.getText().toString());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetLineHeight() {
         mTextView = new TextView(mActivity);
         assertTrue(mTextView.getLineHeight() > 0);
@@ -187,12 +249,11 @@
         assertTrue(mTextView.getLineHeight() > 0);
     }
 
-    public void testGetLayout() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-                mTextView.setGravity(Gravity.CENTER);
-            }
+    @Test
+    public void testGetLayout() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setGravity(Gravity.CENTER);
         });
         mInstrumentation.waitForIdleSync();
         assertNotNull(mTextView.getLayout());
@@ -204,44 +265,34 @@
                 saveLayout();
             }
         };
-        mActivity.runOnUiThread(runnable);
+        mActivityRule.runOnUiThread(runnable);
         mInstrumentation.waitForIdleSync();
         assertNull(runnable.getLayout());
         assertNotNull(mTextView.getLayout());
     }
 
-    public void testAccessKeyListener() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = findTextView(R.id.textview_text);
-            }
-        });
+    @Test
+    public void testAccessKeyListener() throws Throwable {
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setKeyListener(qwertyKeyListener));
         mInstrumentation.waitForIdleSync();
         assertSame(qwertyKeyListener, mTextView.getKeyListener());
     }
 
-    public void testAccessMovementMethod() {
+    @Test
+    public void testAccessMovementMethod() throws Throwable {
         final CharSequence LONG_TEXT = "Scrolls the specified widget to the specified "
                 + "coordinates, except constrains the X scrolling position to the horizontal "
                 + "regions of the text that will be visible after scrolling to "
@@ -249,48 +300,45 @@
         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();
-            }
+        mActivityRule.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()));
-        mKeyEventUtil.sendKeys(mTextView, 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();
-            }
+        mActivityRule.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()));
-        mKeyEventUtil.sendKeys(mTextView, 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()));
     }
 
     @UiThreadTest
+    @Test
     public void testLength() {
         mTextView = findTextView(R.id.textview_text);
 
@@ -306,6 +354,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessGravity() {
         mActivity.setContentView(R.layout.textview_gravity);
 
@@ -348,15 +397,14 @@
         assertEquals(-1, mTextView.getGravity());
     }
 
-    public void testAccessAutoLinkMask() {
+    @Test
+    public void testAccessAutoLinkMask() throws Throwable {
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setAutoLinkMask(Linkify.ALL);
+            mTextView.setText(text1, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(Linkify.ALL, mTextView.getAutoLinkMask());
@@ -370,11 +418,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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setAutoLinkMask(Linkify.PHONE_NUMBERS);
+            mTextView.setText(text2, BufferType.EDITABLE);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(Linkify.PHONE_NUMBERS, mTextView.getAutoLinkMask());
@@ -402,6 +448,8 @@
                 getAutoLinkMask(R.id.autolink_compound4));
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessTextSize() {
         DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
 
@@ -428,6 +476,8 @@
                 mTextView.getTextSize(), 0.01f);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessTextColor() {
         mTextView = new TextView(mActivity);
 
@@ -460,6 +510,7 @@
         }
     }
 
+    @Test
     public void testGetTextColor() {
         // TODO: How to get a suitable TypedArray to test this method.
 
@@ -470,41 +521,84 @@
         }
     }
 
-    public void testSetHighlightColor() {
-        mTextView = new TextView(mActivity);
+    @Test
+    public void testAccessHighlightColor() throws Throwable {
+        final TextView textView = (TextView) mActivity.findViewById(R.id.textview_text);
 
-        mTextView.setHighlightColor(0x00ff00ff);
-    }
+        mActivityRule.runOnUiThread(() -> {
+            textView.setTextIsSelectable(true);
+            textView.setText("abcd", BufferType.EDITABLE);
+            textView.setHighlightColor(Color.BLUE);
+        });
+        mInstrumentation.waitForIdleSync();
 
-    public void testSetShadowLayer() {
-        MockTextView textView = new MockTextView(mActivity);
+        assertTrue(textView.isTextSelectable());
+        assertEquals(Color.BLUE, textView.getHighlightColor());
 
-        // 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());
+        // 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.emulateLongPressOnViewCenter(mInstrumentation, textView);
 
-        // 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());
+        // 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.
+        mActivityRule.runOnUiThread(() -> textView.setHighlightColor(Color.RED));
+        mInstrumentation.waitForIdleSync();
 
-        // 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());
+        assertEquals(Color.RED, textView.getHighlightColor());
+        assertTrue(TextUtils.equals("abcd", textView.getText()));
+
+        // Remove the selection
+        mActivityRule.runOnUiThread(() -> Selection.removeSelection((Spannable) textView.getText()));
+        mInstrumentation.waitForIdleSync();
+
+        // And switch highlight to green after the selection has been removed
+        mActivityRule.runOnUiThread(() -> textView.setHighlightColor(Color.GREEN));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(Color.GREEN, textView.getHighlightColor());
+        assertTrue(TextUtils.equals("abcd", textView.getText()));
     }
 
     @UiThreadTest
+    @Test
+    public void testSetShadowLayer() {
+        // 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(), 0.0f);
+        assertEquals(0.4f, mockTextView.getShadowDy(), 0.0f);
+        assertEquals(1.0f, mockTextView.getShadowRadius(), 0.0f);
+
+        // shadow is placed to the left and below the text
+        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
+        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
+        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
+    @Test
     public void testSetSelectAllOnFocus() {
         mActivity.setContentView(R.layout.textview_selectallonfocus);
         String content = "This is the content";
@@ -565,6 +659,8 @@
         assertEquals(0, mTextView.getSelectionEnd());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetPaint() {
         mTextView = new TextView(mActivity);
         TextPaint tp = mTextView.getPaint();
@@ -574,6 +670,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessLinksClickable() {
         mActivity.setContentView(R.layout.textview_hint_linksclickable_freezestext);
 
@@ -603,6 +700,8 @@
         assertTrue(mTextView.getMovementMethod() instanceof LinkMovementMethod);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessHintTextColor() {
         mTextView = new TextView(mActivity);
         // using int values
@@ -634,6 +733,8 @@
         assertEquals(mTextView.getCurrentTextColor(), mTextView.getCurrentHintTextColor());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessLinkTextColor() {
         mTextView = new TextView(mActivity);
         // normal
@@ -661,6 +762,8 @@
         assertEquals(Color.BLACK, mTextView.getPaint().linkColor);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessPaintFlags() {
         mTextView = new TextView(mActivity);
         assertEquals(Paint.DEV_KERN_TEXT_FLAG | Paint.EMBEDDED_BITMAP_TEXT_FLAG
@@ -675,118 +778,205 @@
                 mTextView.getPaintFlags());
     }
 
-    public void testHeightAndWidth() {
+    @Test
+    public void testHeight() throws Throwable {
         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());
     }
 
-    public void testSetMinEms() {
+    @Test
+    public void testWidth() throws Throwable {
+        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());
+    }
+
+    @Test
+    public void testSetMinEms() throws Throwable {
         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());
     }
 
-    public void testSetMaxEms() {
+    @Test
+    public void testSetMaxEms() throws Throwable {
         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());
     }
 
-    public void testSetEms() {
+    @Test
+    public void testSetEms() throws Throwable {
         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() {
-        mTextView = new TextView(mActivity);
+    @Test
+    public void testSetLineSpacing() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         int originalLineHeight = mTextView.getLineHeight();
 
         // normal
@@ -827,43 +1017,31 @@
         assertEquals(0, mTextView.getLineHeight());
     }
 
-    public void testSetElegantLineHeight() {
+    @Test
+    public void testSetElegantLineHeight() throws Throwable {
         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);
-            }
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setElegantTextHeight(true));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mTextView.getPaint().isElegantTextHeight());
         assertTrue(mTextView.getHeight() > oldHeight);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setElegantTextHeight(false);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setElegantTextHeight(false));
         mInstrumentation.waitForIdleSync();
         assertFalse(mTextView.getPaint().isElegantTextHeight());
         assertTrue(mTextView.getHeight() == oldHeight);
     }
 
-    public void testInstanceState() {
-        // Do not test. Implementation details.
-    }
-
+    @Test
     public void testAccessFreezesText() throws Throwable {
         layout(R.layout.textview_hint_linksclickable_freezestext);
 
@@ -880,31 +1058,24 @@
         assertFalse(mTextView.getFreezesText());
 
         final CharSequence text = "Hello, TextView.";
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(text);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
 
         final URLSpan urlSpan = new URLSpan("ctstest://TextView/test");
         // TODO: How to simulate the TextView in frozen icicles.
-        Instrumentation instrumentation = getInstrumentation();
-        ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
+        ActivityMonitor am = mInstrumentation.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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Uri uri = Uri.parse(urlSpan.getURL());
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            mActivity.startActivity(intent);
         });
 
         Activity newActivity = am.waitForActivityWithTimeout(TIMEOUT);
         assertNotNull(newActivity);
         newActivity.finish();
-        instrumentation.removeMonitor(am);
+        mInstrumentation.removeMonitor(am);
         // the text of TextView is removed.
         mTextView = findTextView(R.id.freezesText_false);
 
@@ -913,22 +1084,16 @@
         mTextView.setFreezesText(true);
         assertTrue(mTextView.getFreezesText());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(text);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
         // TODO: How to simulate the TextView in frozen icicles.
-        am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
+        am = mInstrumentation.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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            Uri uri = Uri.parse(urlSpan.getURL());
+            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+            mActivity.startActivity(intent);
         });
 
         Activity oldActivity = newActivity;
@@ -940,40 +1105,41 @@
             }
         }
         newActivity.finish();
-        instrumentation.removeMonitor(am);
+        mInstrumentation.removeMonitor(am);
         // the text of TextView is still there.
         mTextView = findTextView(R.id.freezesText_false);
         assertEquals(text.toString(), mTextView.getText().toString());
     }
 
+    @UiThreadTest
+    @Test
     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);
@@ -982,34 +1148,35 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     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);
@@ -1018,6 +1185,8 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testTextChangedListener() {
         mTextView = new TextView(mActivity);
         MockTextWatcher watcher0 = new MockTextWatcher();
@@ -1082,6 +1251,8 @@
         assertFalse(watcher1.hasCalledAfterTextChanged());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetTextKeepState1() {
         mTextView = new TextView(mActivity);
 
@@ -1131,6 +1302,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetEditableText() {
         TextView tv = findTextView(R.id.textview_text);
 
@@ -1157,6 +1329,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetText2() {
         String string = "This is a test for setting text content by char array";
         char[] input = string.toCharArray();
@@ -1191,6 +1364,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetText1() {
         mTextView = findTextView(R.id.textview_text);
 
@@ -1290,6 +1464,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetText3() {
         TextView tv = findTextView(R.id.textview_text);
 
@@ -1306,35 +1481,31 @@
         }
     }
 
-    @MediumTest
-    public void testSetText_updatesHeightAfterRemovingImageSpan() {
+    @Test
+    public void testSetTextUpdatesHeightAfterRemovingImageSpan() throws Throwable {
         // Height calculation had problems when TextView had width: match_parent
         final int textViewWidth = ViewGroup.LayoutParams.MATCH_PARENT;
         final Spannable text = new SpannableString("some text");
         final int spanHeight = 100;
 
         // prepare TextView, width: MATCH_PARENT
-        TextView textView = new TextView(getActivity());
-        textView.setSingleLine(true);
-        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 2);
-        textView.setPadding(0, 0, 0, 0);
-        textView.setIncludeFontPadding(false);
-        textView.setText(text);
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+        mTextView.setSingleLine(true);
+        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 2);
+        mTextView.setPadding(0, 0, 0, 0);
+        mTextView.setIncludeFontPadding(false);
+        mTextView.setText(text);
         final FrameLayout layout = new FrameLayout(mActivity);
         final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(textViewWidth,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
-        layout.addView(textView, layoutParams);
+        layout.addView(mTextView, layoutParams);
         layout.setLayoutParams(layoutParams);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
 
         // measure height of text with no span
-        final int heightWithoutSpan = textView.getHeight();
+        final int heightWithoutSpan = mTextView.getHeight();
         assertTrue("Text height should be smaller than span height",
                 heightWithoutSpan < spanHeight);
 
@@ -1343,127 +1514,110 @@
         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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
 
         // measure height with span
-        final int heightWithSpan = textView.getHeight();
+        final int heightWithSpan = mTextView.getHeight();
         assertTrue("Text height should be greater or equal than span height",
                 heightWithSpan >= spanHeight);
 
         // remove the span
         text.removeSpan(span);
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                textView.setText(text);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setText(text));
         mInstrumentation.waitForIdleSync();
 
-        final int heightAfterRemoveSpan = textView.getHeight();
+        final int heightAfterRemoveSpan = mTextView.getHeight();
         assertEquals("Text height should be same after removing the span",
                 heightWithoutSpan, heightAfterRemoveSpan);
     }
 
-    public void testRemoveSelectionWithSelectionHandles() {
-        initTextViewForTyping();
+    @Test
+    public void testRemoveSelectionWithSelectionHandles() throws Throwable {
+        initTextViewForTypingOnUiThread();
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTextView.setTextIsSelectable(true);
-                mTextView.setText("abcd", BufferType.EDITABLE);
-            }
+        assertFalse(mTextView.isTextSelectable());
+        mActivityRule.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.emulateLongPressOnViewCenter(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}.
+        mActivityRule.runOnUiThread(() -> Selection.removeSelection((Spannable) mTextView.getText()));
         mInstrumentation.waitForIdleSync();
+
+        assertTrue(TextUtils.equals("abcd", mTextView.getText()));
     }
 
-    public void testUndo_insert() {
-        initTextViewForTyping();
+    @Test
+    public void testUndo_insert() throws Throwable {
+        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");
+        mActivityRule.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();
+    @Test
+    public void testUndo_delete() throws Throwable {
+        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);
+        mActivityRule.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 +1625,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.
@@ -1484,6 +1642,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testUndo_imeInsertLatin() {
         InputConnection input = initTextViewForSimulatedIme();
 
@@ -1504,6 +1663,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testUndo_imeInsertJapanese() {
         InputConnection input = initTextViewForSimulatedIme();
 
@@ -1527,6 +1687,87 @@
     }
 
     @UiThreadTest
+    @Test
+    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
+    @Test
+    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
+    @Test
+    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
+    @Test
     public void testUndo_imeCancel() {
         InputConnection input = initTextViewForSimulatedIme();
         mTextView.setText("flower");
@@ -1540,14 +1781,14 @@
         // 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());
     }
 
     @UiThreadTest
+    @Test
     public void testUndo_imeEmptyBatch() {
         InputConnection input = initTextViewForSimulatedIme();
         mTextView.setText("flower");
@@ -1563,409 +1804,377 @@
         assertEquals("flower", mTextView.getText().toString());
     }
 
-    public void testUndo_setText() {
-        initTextViewForTyping();
+    @Test
+    public void testUndo_setText() throws Throwable {
+        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);
+        mActivityRule.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();
+    @Test
+    public void testRedo_setText() throws Throwable {
+        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");
+        mActivityRule.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();
+    @Test
+    public void testUndo_directAppend() throws Throwable {
+        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");
+        mActivityRule.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();
+    @Test
+    public void testUndo_directInsert() throws Throwable {
+        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");
+        mActivityRule.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
+    @Test
     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();
+    @Test
+    public void testUndo_textWatcher() throws Throwable {
+        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");
+        mActivityRule.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
+    @Test
     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();
+    @Test
+    public void testUndo_shortcuts() throws Throwable {
+        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");
+        mActivityRule.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();
+    @Test
+    public void testUndo_saveInstanceState() throws Throwable {
+        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");
+        mActivityRule.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);
+        mActivityRule.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();
+    @Test
+    public void testUndo_saveInstanceStateEmpty() throws Throwable {
+        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);
+        mActivityRule.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);
+        mActivityRule.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
+    @Test
     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();
+    @Test
+    public void testCopyAndPaste_byKey() throws Throwable {
+        initTextViewForTypingOnUiThread();
 
         // Type "abc".
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Select "bc"
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivityRule.runOnUiThread(() -> {
+            // Select "bc"
+            Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
         });
         mInstrumentation.waitForIdleSync();
         // Copy "bc"
-        mKeyEventUtil.sendKeys(mTextView, 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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            // Set cursor between 'b' and 'c'.
+            Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
         });
         mInstrumentation.waitForIdleSync();
         // Paste "bc"
-        mKeyEventUtil.sendKeys(mTextView, 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());
+        mActivityRule.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
+    @Test
     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();
+    @Test
+    public void testCutAndPaste_byKey() throws Throwable {
+        initTextViewForTypingOnUiThread();
 
         // Type "abc".
-        mKeyEventUtil.sendString(mTextView, "abc");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                // Select "bc"
-                Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
-            }
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "abc");
+        mActivityRule.runOnUiThread(() -> {
+            // Select "bc"
+            Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
         });
         mInstrumentation.waitForIdleSync();
         // Cut "bc"
-        mKeyEventUtil.sendKeys(mTextView, 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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals("a", mTextView.getText().toString());
+            // Move cursor to the head
+            Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
         });
         mInstrumentation.waitForIdleSync();
         // Paste "bc"
-        mKeyEventUtil.sendKeys(mTextView, 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());
+        mActivityRule.runOnUiThread(() -> {
+            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();
     }
@@ -1976,41 +2185,40 @@
         return spannable.getSpans(at, at, type).length > 0;
     }
 
+    @UiThreadTest
+    @Test
     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
+    @Test
     public void testSaveInstanceState() {
         // should save text when freezesText=true
         TextView originalTextView = new TextView(mActivity);
@@ -2025,6 +2233,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testOnSaveInstanceState_whenFreezesTextIsFalse() {
         final String text = "This is a string";
         { // should not save text when freezesText=false
@@ -2062,6 +2271,7 @@
 
     @UiThreadTest
     @SmallTest
+    @Test
     public void testOnSaveInstanceState_doesNotSaveSelectionWhenDoesNotExist() {
         // prepare TextView for before saveInstanceState
         final String text = "This is a string";
@@ -2081,6 +2291,7 @@
 
     @UiThreadTest
     @SmallTest
+    @Test
     public void testOnSaveInstanceState_doesNotRestoreSelectionWhenTextIsAbsent() {
         // prepare TextView for before saveInstanceState
         final String text = "This is a string";
@@ -2105,6 +2316,7 @@
 
     @UiThreadTest
     @SmallTest
+    @Test
     public void testOnSaveInstanceState_savesSelectionWhenExists() {
         final String text = "This is a string";
         // prepare TextView for before saveInstanceState
@@ -2126,6 +2338,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetText() {
         TextView tv = findTextView(R.id.textview_text);
 
@@ -2148,6 +2361,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessHint() {
         mActivity.setContentView(R.layout.textview_hint_linksclickable_freezestext);
 
@@ -2180,99 +2394,83 @@
         }
     }
 
-    public void testAccessError() {
+    @Test
+    public void testAccessError() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         assertNull(mTextView.getError());
 
         final String errorText = "Oops! There is an error";
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setError(null);
-            }
-        });
+        mActivityRule.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);
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(DigitsKeyListener.getInstance(""));
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.setError(errorText);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
         assertEquals(errorText, mTextView.getError().toString());
 
-        mKeyEventUtil.sendString(mTextView, "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();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(DigitsKeyListener.getInstance());
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.setError(errorText);
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
 
-        mKeyEventUtil.sendString(mTextView, "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.
         assertNull(mTextView.getError());
     }
 
-    public void testAccessFilters() {
+    @Test
+    public void testAccessFilters() throws Throwable {
         final InputFilter[] expected = { new InputFilter.AllCaps(),
                 new InputFilter.LengthFilter(2) };
 
         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();
-            }
+        mActivityRule.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());
 
-        mKeyEventUtil.sendString(mTextView, "a");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
         // the text is capitalized by InputFilter.AllCaps
         assertEquals("A", mTextView.getText().toString());
-        mKeyEventUtil.sendString(mTextView, "b");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "b");
         // the text is capitalized by InputFilter.AllCaps
         assertEquals("AB", mTextView.getText().toString());
-        mKeyEventUtil.sendString(mTextView, "c");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "c");
         // 'C' could not be accepted, because there is a length filter.
         assertEquals("AB", mTextView.getText().toString());
 
@@ -2283,11 +2481,13 @@
         }
     }
 
-    public void testGetFocusedRect() {
+    @Test
+    public void testGetFocusedRect() throws Throwable {
         Rect rc = new Rect();
 
         // Basic
-        mTextView = new TextView(mActivity);
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
         assertEquals(mTextView.getScrollX(), rc.left);
         assertEquals(mTextView.getScrollX() + mTextView.getWidth(), rc.right);
@@ -2302,13 +2502,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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 3, 13);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2323,13 +2521,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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 13, 3);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2347,13 +2543,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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setSelected(true);
+            SpannableString text = new SpannableString(mTextView.getText());
+            Selection.setSelection(text, 2, 4);
+            mTextView.setText(text);
         });
         mInstrumentation.waitForIdleSync();
         mTextView.getFocusedRect(rc);
@@ -2363,13 +2557,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);
-            }
+        mActivityRule.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);
@@ -2378,8 +2570,8 @@
         RectF rcf = new RectF();
         path.computeBounds(rcf, true);
         assertNotNull(mTextView.getLayout());
-        assertEquals(rcf.left - 1, (float) rc.left);
-        assertEquals(rcf.right + 1, (float) rc.right);
+        assertEquals(rcf.left - 1, (float) rc.left, 0.0f);
+        assertEquals(rcf.right + 1, (float) rc.right, 0.0f);
         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
         assertEquals(mTextView.getLayout().getLineBottom(1), rc.bottom);
 
@@ -2391,8 +2583,10 @@
         }
     }
 
-    public void testGetLineCount() {
-        mTextView = findTextView(R.id.textview_text);
+    @Test
+    public void testGetLineCount() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = findTextView(R.id.textview_text));
+        mInstrumentation.waitForIdleSync();
         // this is an one line text with default setting.
         assertEquals(1, mTextView.getLineCount());
 
@@ -2408,15 +2602,18 @@
         setMinLines(12);
         assertEquals(1, mTextView.getLineCount());
 
-        mTextView = new TextView(mActivity);
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         // the internal Layout has not been built.
         assertNull(mTextView.getLayout());
         assertEquals(0, mTextView.getLineCount());
     }
 
-    public void testGetLineBounds() {
+    @Test
+    public void testGetLineBounds() throws Throwable {
         Rect rc = new Rect();
-        mTextView = new TextView(mActivity);
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         assertEquals(0, mTextView.getLineBounds(0, null));
 
         assertEquals(0, mTextView.getLineBounds(0, rc));
@@ -2434,11 +2631,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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getBaseline(), mTextView.getLineBounds(0, rc));
@@ -2448,59 +2643,57 @@
         assertEquals(mTextView.getHeight() - mTextView.getTotalPaddingBottom(), rc.bottom);
     }
 
-    public void testGetBaseLine() {
-        mTextView = new TextView(mActivity);
+    @Test
+    public void testGetBaseLine() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         assertEquals(-1, mTextView.getBaseline());
 
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setPadding(1, 2, 3, 4);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         int expected = mTextView.getTotalPaddingTop() + mTextView.getLayout().getLineBaseline(0);
         assertEquals(expected, mTextView.getBaseline());
     }
 
-    public void testPressKey() {
-        initTextViewForTyping();
+    @Test
+    public void testPressKey() throws Throwable {
+        initTextViewForTypingOnUiThread();
 
-        mKeyEventUtil.sendString(mTextView, "a");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "a");
         assertEquals("a", mTextView.getText().toString());
-        mKeyEventUtil.sendString(mTextView, "b");
+        CtsKeyEventUtil.sendString(mInstrumentation, mTextView, "b");
         assertEquals("ab", mTextView.getText().toString());
-        mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, KeyEvent.KEYCODE_DEL);
         assertEquals("a", mTextView.getText().toString());
     }
 
-    public void testSetIncludeFontPadding() {
+    @Test
+    public void testSetIncludeFontPadding() throws Throwable {
         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);
-            }
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setIncludeFontPadding(false));
         mInstrumentation.waitForIdleSync();
 
         assertTrue(mTextView.getHeight() < oldHeight);
         assertFalse(mTextView.getIncludeFontPadding());
     }
 
+    @UiThreadTest
+    @Test
     public void testScroll() {
         mTextView = new TextView(mActivity);
 
@@ -2525,16 +2718,22 @@
         assertEquals(480, mTextView.getScrollY());
     }
 
-    public void testDebug() {
-        mTextView = new TextView(mActivity);
-        mTextView.debug(0);
+    @Test
+    public void testDebug() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.debug(0);
+            mTextView.setText("Hello!");
+        });
+        mInstrumentation.waitForIdleSync();
 
-        mTextView.setText("Hello!");
         layout(mTextView);
         mTextView.debug(1);
     }
 
-    public void testSelection() {
+    @UiThreadTest
+    @Test
+    public void testSelection() throws Throwable {
         mTextView = new TextView(mActivity);
         String text = "This is the content";
         mTextView.setText(text, BufferType.SPANNABLE);
@@ -2558,7 +2757,34 @@
         assertTrue(mTextView.hasSelection());
     }
 
+    @Test
+    public void testOnSelectionChangedIsTriggeredWhenSelectionChanges() throws Throwable {
+        final String text = "any text";
+        mActivityRule.runOnUiThread(() -> mTextView = spy(new MockTextView(mActivity)));
+        mInstrumentation.waitForIdleSync();
+        mTextView.setText(text, BufferType.SPANNABLE);
+
+        // assert that there is currently no selection
+        assertFalse(mTextView.hasSelection());
+
+        // select all
+        Selection.selectAll((Spannable) mTextView.getText());
+        // After selectAll OnSelectionChanged should have been called
+        ((MockTextView) verify(mTextView, times(1))).onSelectionChanged(0, text.length());
+
+        reset(mTextView);
+        // change selection
+        Selection.setSelection((Spannable) mTextView.getText(), 1, 5);
+        ((MockTextView) verify(mTextView, times(1))).onSelectionChanged(1, 5);
+
+        reset(mTextView);
+        // clear selection
+        Selection.removeSelection((Spannable) mTextView.getText());
+        ((MockTextView) verify(mTextView, times(1))).onSelectionChanged(-1, -1);
+    }
+
     @UiThreadTest
+    @Test
     public void testAccessEllipsize() {
         mActivity.setContentView(R.layout.textview_ellipsize);
 
@@ -2598,135 +2824,245 @@
         // there is no method to check if '...yLongVeryLongWord' is painted in the screen.
     }
 
-    public void testEllipsizeEndAndNoEllipsizeHasSameBaselineForSingleLine() {
-        int textWidth = calculateTextWidth(LONG_TEXT);
+    @Test
+    public void testEllipsizeAndMaxLinesForSingleLine() throws Throwable {
+        // no maxline or ellipsize set, single line text
+        final TextView tvNoMaxLine = new TextView(mActivity);
+        tvNoMaxLine.setLineSpacing(0, 1.5f);
+        tvNoMaxLine.setText("a");
 
-        TextView tvEllipsizeEnd = new TextView(getActivity());
+        // maxline set, no ellipsize, text with two lines
+        final TextView tvEllipsizeNone = new TextView(mActivity);
+        tvEllipsizeNone.setMaxLines(1);
+        tvEllipsizeNone.setLineSpacing(0, 1.5f);
+        tvEllipsizeNone.setText("a\na");
+
+        // maxline set, ellipsize end, text with two lines
+        final TextView tvEllipsizeEnd = new TextView(mActivity);
         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");
+        tvEllipsizeEnd.setLineSpacing(0, 1.5f);
+        tvEllipsizeEnd.setText("a\na");
 
         final FrameLayout layout = new FrameLayout(mActivity);
         ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
         layout.addView(tvEllipsizeEnd, layoutParams);
         layout.addView(tvEllipsizeNone, layoutParams);
-        layout.setLayoutParams(layoutParams);
+        layout.addView(tvNoMaxLine, layoutParams);
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout,
+                new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT)));
+        mInstrumentation.waitForIdleSync();
 
-        assertEquals("Ellipsized and non ellipsized single line texts should have the same " +
-                        "baseline",
-                tvEllipsizeEnd.getLayout().getLineBaseline(0),
+        assertEquals(tvEllipsizeEnd.getHeight(), tvEllipsizeNone.getHeight());
+
+        assertEquals(tvEllipsizeEnd.getHeight(), tvNoMaxLine.getHeight());
+
+        assertEquals(tvEllipsizeEnd.getLayout().getLineBaseline(0),
                 tvEllipsizeNone.getLayout().getLineBaseline(0));
+
+        assertEquals(tvEllipsizeEnd.getLayout().getLineBaseline(0),
+                tvNoMaxLine.getLayout().getLineBaseline(0));
     }
 
-    public void testEllipsizeEndAndNoEllipsizeHasSameBaselineForMultiLine() {
-        int textWidth = calculateTextWidth(LONG_TEXT);
+    @Test
+    public void testEllipsizeAndMaxLinesForMultiLine() throws Throwable {
+        // no maxline, no ellipsize, text with two lines
+        final TextView tvNoMaxLine = new TextView(mActivity);
+        tvNoMaxLine.setLineSpacing(0, 1.5f);
+        tvNoMaxLine.setText("a\na");
 
-        TextView tvEllipsizeEnd = new TextView(getActivity());
+        // maxline set, no ellipsize, text with three lines
+        final TextView tvEllipsizeNone = new TextView(mActivity);
+        tvEllipsizeNone.setMaxLines(2);
+        tvEllipsizeNone.setLineSpacing(0, 1.5f);
+        tvEllipsizeNone.setText("a\na\na");
+
+        // maxline set, ellipsize end, text with three lines
+        final TextView tvEllipsizeEnd = new TextView(mActivity);
         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);
+        tvEllipsizeEnd.setLineSpacing(0, 1.5f);
+        tvEllipsizeEnd.setText("a\na\na");
 
         final FrameLayout layout = new FrameLayout(mActivity);
         ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
 
+        layout.addView(tvNoMaxLine, layoutParams);
         layout.addView(tvEllipsizeEnd, layoutParams);
         layout.addView(tvEllipsizeNone, layoutParams);
-        layout.setLayoutParams(layoutParams);
 
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().setContentView(layout);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(() ->  mActivity.setContentView(layout,
+                new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT)));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(tvEllipsizeEnd.getHeight(), tvEllipsizeNone.getHeight());
+
+        assertEquals(tvEllipsizeEnd.getHeight(), tvNoMaxLine.getHeight());
 
         for (int i = 0; i < tvEllipsizeEnd.getLineCount(); i++) {
-            assertEquals("Ellipsized and non ellipsized multi line texts should have the same " +
-                            "baseline for line " + i,
+            assertEquals("Should have the same baseline for line " + i,
                     tvEllipsizeEnd.getLayout().getLineBaseline(i),
                     tvEllipsizeNone.getLayout().getLineBaseline(i));
+
+            assertEquals("Should have the same baseline for line " + i,
+                    tvEllipsizeEnd.getLayout().getLineBaseline(i),
+                    tvNoMaxLine.getLayout().getLineBaseline(i));
         }
     }
 
-    public void testSetCursorVisible() {
+    @Test
+    public void testEllipsizeAndMaxLinesForHint() throws Throwable {
+        // no maxline, no ellipsize, hint with two lines
+        final TextView tvTwoLines = new TextView(mActivity);
+        tvTwoLines.setLineSpacing(0, 1.5f);
+        tvTwoLines.setHint("a\na");
+
+        // no maxline, no ellipsize, hint with three lines
+        final TextView tvThreeLines = new TextView(mActivity);
+        tvThreeLines.setLineSpacing(0, 1.5f);
+        tvThreeLines.setHint("a\na\na");
+
+        // maxline set, ellipsize end, hint with three lines
+        final TextView tvEllipsizeEnd = new TextView(mActivity);
+        tvEllipsizeEnd.setEllipsize(TruncateAt.END);
+        tvEllipsizeEnd.setMaxLines(2);
+        tvEllipsizeEnd.setLineSpacing(0, 1.5f);
+        tvEllipsizeEnd.setHint("a\na\na");
+
+        // maxline set, no ellipsize, hint with three lines
+        final TextView tvEllipsizeNone = new TextView(mActivity);
+        tvEllipsizeNone.setMaxLines(2);
+        tvEllipsizeNone.setLineSpacing(0, 1.5f);
+        tvEllipsizeNone.setHint("a\na\na");
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+
+        layout.addView(tvTwoLines, layoutParams);
+        layout.addView(tvEllipsizeEnd, layoutParams);
+        layout.addView(tvEllipsizeNone, layoutParams);
+        layout.addView(tvThreeLines, layoutParams);
+
+        mActivityRule.runOnUiThread(() ->  mActivity.setContentView(layout,
+                new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT)));
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals("Non-ellipsized hint should not crop text at maxLines",
+                tvThreeLines.getHeight(), tvEllipsizeNone.getHeight());
+
+        assertEquals("Ellipsized hint should crop text at maxLines",
+                tvTwoLines.getHeight(), tvEllipsizeEnd.getHeight());
+    }
+
+    @Test
+    public void testTextViewInWeigthenedLayoutChangesWidthAfterSetText() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setEllipsize(TruncateAt.END);
+            mTextView.setSingleLine(true);
+            mTextView.setText("a");
+
+            mSecondTextView = new TextView(mActivity);
+            mSecondTextView.setSingleLine(true);
+            mSecondTextView.setText("any");
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final LinearLayout layout = new LinearLayout(mActivity);
+        layout.setOrientation(LinearLayout.HORIZONTAL);
+
+        // TextView under test has weight 1, and width 0
+        layout.addView(mTextView, new LinearLayout.LayoutParams(0,
+                ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
+
+        // other TextView has default weight
+        layout.addView(mSecondTextView, 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));
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        int oldWidth = mTextView.getWidth();
+
+        mActivityRule.runOnUiThread(() -> mTextView.setText("aaa"));
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue("TextView should have larger width after a longer text is set",
+                mTextView.getWidth() > oldWidth);
+    }
+
+
+    @UiThreadTest
+    @Test
+    public void testAccessCursorVisible() {
         mTextView = new TextView(mActivity);
 
         mTextView.setCursorVisible(true);
+        assertTrue(mTextView.isCursorVisible());
         mTextView.setCursorVisible(false);
-    }
-
-    public void testOnWindowFocusChanged() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnTouchEvent() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnTrackballEvent() {
-        // Do not test. Implementation details.
-    }
-
-    public void testGetTextColors() {
-        // TODO: How to get a suitable TypedArray to test this method.
-    }
-
-    public void testOnKeyShortcut() {
-        // Do not test. Implementation details.
+        assertFalse(mTextView.isCursorVisible());
     }
 
     @UiThreadTest
+    @Test
     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
+    @Test
     public void testTextAttr() {
         mTextView = findTextView(R.id.textview_textAttr);
         // getText
@@ -2785,6 +3121,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend() {
         mTextView = new TextView(mActivity);
 
@@ -2832,6 +3169,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_doesNotAddLinksWhenAppendedTextDoesNotContainLinks() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2846,6 +3184,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_doesNotAddLinksWhenAutoLinkIsNotEnabled() {
         mTextView = new TextView(mActivity);
         mTextView.setText("text without URL");
@@ -2859,6 +3198,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_addsLinksWhenAutoLinkIsEnabled() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2875,6 +3215,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_addsLinksEvenWhenThereAreUrlsSetBefore() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2894,6 +3235,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_setsMovementMethodWhenTextContainsUrlAndAutoLinkIsEnabled() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2908,6 +3250,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_addsLinksWhenTextIsSpannableAndContainsUrlAndAutoLinkIsEnabled() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2923,6 +3266,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_addsLinkIfAppendedTextCompletesPartialUrlAtTheEndOfExistingText() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2939,6 +3283,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAppend_addsLinkIfAppendedTextUpdatesUrlAtTheEndOfExistingText() {
         mTextView = new TextView(mActivity);
         mTextView.setAutoLinkMask(Linkify.ALL);
@@ -2953,8 +3298,279 @@
                 urlSpans[0].getURL(), "http://android.com/textview");
     }
 
+    @UiThreadTest
+    @Test
+    public void testGetLetterSpacing_returnsValueThatWasSet() {
+        mTextView = new TextView(mActivity);
+        mTextView.setLetterSpacing(2f);
+        assertEquals("getLetterSpacing should return the value that was set",
+                2f, mTextView.getLetterSpacing(), 0.0f);
+    }
 
-    public void testAccessTransformationMethod() {
+    @Test
+    public void testSetLetterSpacingChangesTextWidth() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText("aa");
+            mTextView.setLetterSpacing(0f);
+            mTextView.setTextSize(8f);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        layout.addView(mTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        // measure text with zero letter spacing
+        final float zeroSpacing = mTextView.getLayout().getLineWidth(0);
+
+        mActivityRule.runOnUiThread(() -> mTextView.setLetterSpacing(1f));
+        mInstrumentation.waitForIdleSync();
+
+        // measure text with single letter spacing
+        final float singleSpacing = mTextView.getLayout().getLineWidth(0);
+
+        mActivityRule.runOnUiThread(() -> mTextView.setLetterSpacing(2f));
+        mInstrumentation.waitForIdleSync();
+
+        // measure text with double letter spacing
+        final float doubleSpacing = mTextView.getLayout().getLineWidth(0);
+
+        assertEquals("Double spacing should have two times the spacing of single spacing",
+                doubleSpacing - zeroSpacing, 2f * (singleSpacing - zeroSpacing), 1f);
+    }
+
+    @UiThreadTest
+    @Test
+    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());
+    }
+
+    @Test
+    public void testGetOffsetForPositionSingleLineLtr() throws Throwable {
+        // asserts getOffsetPosition returns correct values for a single line LTR text
+        final String text = "aaaaa";
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText(text);
+            mTextView.setTextSize(8f);
+            mTextView.setSingleLine(true);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // 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);
+        mTextView.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(mTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivityRule.runOnUiThread(() -> mActivity.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 = mTextView.getHeight() / 2f;
+        assertEquals(firstOffset, mTextView.getOffsetForPosition(x, y));
+
+        // right edge of text
+        x = mTextView.getLayout().getLineWidth(0) - 1f;
+        assertEquals(lastOffset, mTextView.getOffsetForPosition(x, y));
+
+        // right edge of view
+        x = mTextView.getWidth();
+        assertEquals(lastOffset + 1, mTextView.getOffsetForPosition(x, y));
+
+        // left edge of view - out of bounds
+        x = -1f;
+        assertEquals(firstOffset, mTextView.getOffsetForPosition(x, y));
+
+        // horizontal center of text
+        x = (float) Math.floor(mTextView.getLayout().getLineWidth(0) / 2f + 0.5f);
+        assertEquals(midOffset, mTextView.getOffsetForPosition(x, y));
+    }
+
+    @Test
+    public void testGetOffsetForPositionMultiLineLtr() throws Throwable {
+        final String line = "aaa\n";
+        final String threeLines = line + line + line;
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText(threeLines);
+            mTextView.setTextSize(8f);
+            mTextView.setLines(2);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // 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);
+        mTextView.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(mTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        final Rect lineBounds = new Rect();
+        mTextView.getLayout().getLineBounds(0, lineBounds);
+
+        // left edge of view at first line
+        float x = 0f;
+        float y = lineBounds.height() / 2f;
+        assertEquals(0, mTextView.getOffsetForPosition(x, y));
+
+        // right edge of view at first line
+        x = mTextView.getWidth() - 1f;
+        assertEquals(line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // update lineBounds to be the second line
+        mTextView.getLayout().getLineBounds(1, lineBounds);
+        y = lineBounds.top + lineBounds.height() / 2;
+
+        // left edge of view at second line
+        x = 0f;
+        assertEquals(line.length(), mTextView.getOffsetForPosition(x, y));
+
+        // right edge of text at second line
+        x = mTextView.getLayout().getLineWidth(1) - 1f;
+        assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // right edge of view at second line
+        x = mTextView.getWidth() - 1f;
+        assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // horizontal center of text at second line
+        x = (float) Math.floor(mTextView.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, mTextView.getOffsetForPosition(x, y));
+    }
+
+    @Test
+    public void testGetOffsetForPositionMultiLineRtl() throws Throwable {
+        final String line = "\u0635\u0635\u0635\n";
+        final String threeLines = line + line + line;
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = new TextView(mActivity);
+            mTextView.setText(threeLines);
+            mTextView.setTextSize(8f);
+            mTextView.setLines(2);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // 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);
+        mTextView.setCompoundDrawables(drawable, drawable, drawable, drawable);
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        final LayoutParams layoutParams = new LayoutParams(
+                LayoutParams.MATCH_PARENT,
+                LayoutParams.WRAP_CONTENT);
+        layout.addView(mTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        final Rect lineBounds = new Rect();
+        mTextView.getLayout().getLineBounds(0, lineBounds);
+
+        // right edge of view at first line
+        float x = mTextView.getWidth() - 1f;
+        float y = lineBounds.height() / 2f;
+        assertEquals(0, mTextView.getOffsetForPosition(x, y));
+
+        // left edge of view at first line
+        x = 0f;
+        assertEquals(line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // update lineBounds to be the second line
+        mTextView.getLayout().getLineBounds(1, lineBounds);
+        y = lineBounds.top + lineBounds.height() / 2f;
+
+        // right edge of view at second line
+        x = mTextView.getWidth() - 1f;
+        assertEquals(line.length(), mTextView.getOffsetForPosition(x, y));
+
+        // left edge of view at second line
+        x = 0f;
+        assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // right edge of text at second line
+        x = mTextView.getWidth() - mTextView.getLayout().getLineWidth(1) + 1f;
+        assertEquals(line.length() + line.length() - 1, mTextView.getOffsetForPosition(x, y));
+
+        // horizontal center of text at second line
+        x = mTextView.getWidth() - (float) Math.floor(
+                mTextView.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, mTextView.getOffsetForPosition(x, y));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testIsTextSelectable_returnsFalseByDefault() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("any text");
+        assertFalse(textView.isTextSelectable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testIsTextSelectable_returnsTrueIfSetTextIsSelectableCalledWithTrue() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("any text");
+        textView.setTextIsSelectable(true);
+        assertTrue(textView.isTextSelectable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetIsTextSelectable() {
+        final TextView textView = new TextView(mActivity);
+
+        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());
+    }
+
+    @Test
+    public void testAccessTransformationMethod() throws Throwable {
         // check the password attribute in xml
         mTextView = findTextView(R.id.textview_password);
         assertNotNull(mTextView);
@@ -2971,48 +3587,34 @@
                 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);
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(qwertyKeyListener);
+            mTextView.setTransformationMethod(method);
+            mTransformedText = method.getTransformation(mTextView.getText(), mTextView);
 
-                mTextView.requestFocus();
-            }
+            mTextView.requestFocus();
         });
         mInstrumentation.waitForIdleSync();
         assertSame(PasswordTransformationMethod.getInstance(),
                 mTextView.getTransformationMethod());
 
-        mKeyEventUtil.sendKeys(mTextView, "H E 2*L O");
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.append(" ");
-            }
-        });
+        CtsKeyEventUtil.sendKeys(mInstrumentation, mTextView, "H E 2*L O");
+        mActivityRule.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);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setTransformationMethod(null));
         mInstrumentation.waitForIdleSync();
         assertNull(mTextView.getTransformationMethod());
     }
 
     @UiThreadTest
+    @Test
     public void testCompound() {
         mTextView = new TextView(mActivity);
         int padding = 3;
@@ -3032,20 +3634,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);
@@ -3096,79 +3698,122 @@
         assertEquals(mTextView.getPaddingBottom(), mTextView.getCompoundPaddingBottom());
     }
 
-    public void testSingleLine() {
-        final TextView textView = new TextView(mActivity);
-        setSpannableText(textView, "This is a really long sentence"
+    @UiThreadTest
+    @Test
+    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]);
+    }
+
+    @Test
+    public void testSingleLine() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
+
+        setSpannableText(mTextView, "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);
+        innerLayout.addView(mTextView);
 
         final FrameLayout layout = new FrameLayout(mActivity);
         layout.addView(innerLayout);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layout);
-                textView.setSingleLine(true);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mActivity.setContentView(layout);
+            mTextView.setSingleLine(true);
         });
         mInstrumentation.waitForIdleSync();
 
         assertEquals(SingleLineTransformationMethod.getInstance(),
-                textView.getTransformationMethod());
+                mTextView.getTransformationMethod());
 
         int singleLineWidth = 0;
         int singleLineHeight = 0;
 
-        if (textView.getLayout() != null) {
-            singleLineWidth = textView.getLayout().getWidth();
-            singleLineHeight = textView.getLayout().getHeight();
+        if (mTextView.getLayout() != null) {
+            singleLineWidth = mTextView.getLayout().getWidth();
+            singleLineHeight = mTextView.getLayout().getHeight();
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setSingleLine(false);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setSingleLine(false));
         mInstrumentation.waitForIdleSync();
-        assertEquals(null, textView.getTransformationMethod());
+        assertEquals(null, mTextView.getTransformationMethod());
 
-        if (textView.getLayout() != null) {
-            assertTrue(textView.getLayout().getHeight() > singleLineHeight);
-            assertTrue(textView.getLayout().getWidth() < singleLineWidth);
+        if (mTextView.getLayout() != null) {
+            assertTrue(mTextView.getLayout().getHeight() > singleLineHeight);
+            assertTrue(mTextView.getLayout().getWidth() < singleLineWidth);
         }
 
         // same behaviours as setSingLine(true)
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setSingleLine();
-            }
-        });
+        mActivityRule.runOnUiThread(mTextView::setSingleLine);
         mInstrumentation.waitForIdleSync();
         assertEquals(SingleLineTransformationMethod.getInstance(),
-                textView.getTransformationMethod());
+                mTextView.getTransformationMethod());
 
-        if (textView.getLayout() != null) {
-            assertEquals(singleLineHeight, textView.getLayout().getHeight());
-            assertEquals(singleLineWidth, textView.getLayout().getWidth());
+        if (mTextView.getLayout() != null) {
+            assertEquals(singleLineHeight, mTextView.getLayout().getHeight());
+            assertEquals(singleLineWidth, mTextView.getLayout().getWidth());
         }
     }
 
     @UiThreadTest
-    public void testSetMaxLines() {
+    @Test
+    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;
@@ -3177,24 +3822,13 @@
         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
+    @Test
     public void testHyphenationNotHappen_frequencyNone() {
         final int[] BREAK_STRATEGIES = {
             Layout.BREAK_STRATEGY_SIMPLE, Layout.BREAK_STRATEGY_HIGH_QUALITY,
@@ -3205,7 +3839,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);
@@ -3229,6 +3864,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testHyphenationNotHappen_breakStrategySimple() {
         final int[] HYPHENATION_FREQUENCIES = {
             Layout.HYPHENATION_FREQUENCY_NORMAL, Layout.HYPHENATION_FREQUENCY_FULL,
@@ -3239,7 +3875,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);
@@ -3263,6 +3900,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetMaxLinesException() {
         mTextView = new TextView(mActivity);
         mActivity.setContentView(mTextView);
@@ -3270,20 +3908,25 @@
         mTextView.setMaxLines(-1);
     }
 
-    public void testSetMinLines() {
+    @Test
+    public void testAccessMinLines() throws Throwable {
         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() {
+    @Test
+    public void testSetLines() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         // make it multiple lines
         setWidth(mTextView.getWidth() >> 3);
@@ -3297,6 +3940,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetLinesException() {
         mTextView = new TextView(mActivity);
         mActivity.setContentView(mTextView);
@@ -3305,13 +3949,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetExtendedPaddingTop() {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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());
@@ -3324,13 +3969,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetExtendedPaddingBottom() {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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());
@@ -3342,20 +3988,19 @@
         assertTrue(mTextView.getExtendedPaddingBottom() > 0);
     }
 
-    public void testGetTotalPaddingTop() {
+    @Test
+    public void testGetTotalPaddingTop() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setCompoundDrawables(null, top, null, null);
+            mTextView.setLines(mTextView.getLineCount() - 1);
+            mTextView.setGravity(Gravity.BOTTOM);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getExtendedPaddingTop(), mTextView.getTotalPaddingTop());
@@ -3368,20 +4013,19 @@
         assertEquals(expected, mTextView.getTotalPaddingTop());
     }
 
-    public void testGetTotalPaddingBottom() {
+    @Test
+    public void testGetTotalPaddingBottom() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setCompoundDrawables(null, null, null, bottom);
+            mTextView.setLines(mTextView.getLineCount() - 1);
+            mTextView.setGravity(Gravity.CENTER_VERTICAL);
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(mTextView.getExtendedPaddingBottom(), mTextView.getTotalPaddingBottom());
@@ -3397,13 +4041,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetTotalPaddingLeft() {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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);
@@ -3415,13 +4060,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetTotalPaddingRight() {
         mTextView = findTextView(R.id.textview_text);
         // Initialized value
         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);
@@ -3432,6 +4078,8 @@
         assertEquals(mTextView.getCompoundPaddingRight(), mTextView.getTotalPaddingRight());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetUrls() {
         mTextView = new TextView(mActivity);
 
@@ -3463,6 +4111,8 @@
         assertEquals(2, spans.length);
     }
 
+    @UiThreadTest
+    @Test
     public void testSetPadding() {
         mTextView = new TextView(mActivity);
 
@@ -3479,6 +4129,8 @@
         assertEquals(40, mTextView.getPaddingBottom());
     }
 
+    @UiThreadTest
+    @Test
     public void testDeprecatedSetTextAppearance() {
         mTextView = new TextView(mActivity);
 
@@ -3508,6 +4160,8 @@
         assertEquals(null, mTextView.getTypeface());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetTextAppearance() {
         mTextView = new TextView(mActivity);
 
@@ -3520,6 +4174,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),
@@ -3528,6 +4184,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);
@@ -3537,10 +4195,8 @@
         assertEquals(null, mTextView.getTypeface());
     }
 
-    public void testOnPreDraw() {
-        // Do not test. Implementation details.
-    }
-
+    @UiThreadTest
+    @Test
     public void testAccessCompoundDrawableTint() {
         mTextView = new TextView(mActivity);
 
@@ -3568,7 +4224,8 @@
         assertEquals(PorterDuff.Mode.XOR, mTextView.getCompoundDrawableTintMode());
     }
 
-    public void testSetHorizontallyScrolling() {
+    @Test
+    public void testSetHorizontallyScrolling() throws Throwable {
         // make the text view has more than one line
         mTextView = findTextView(R.id.textview_text);
         setWidth(mTextView.getWidth() >> 1);
@@ -3581,49 +4238,65 @@
         assertTrue(mTextView.getLineCount() > 1);
     }
 
-    public void testComputeHorizontalScrollRange() {
-        MockTextView textView = new MockTextView(mActivity);
+    @Test
+    public void testComputeHorizontalScrollRange() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new MockTextView(mActivity));
+        mInstrumentation.waitForIdleSync();
         // test when layout is null
-        assertNull(textView.getLayout());
-        assertEquals(textView.getWidth(), textView.computeHorizontalScrollRange());
+        assertNull(mTextView.getLayout());
+        assertEquals(mTextView.getWidth(),
+                ((MockTextView) mTextView).computeHorizontalScrollRange());
 
-        textView.setFrame(0, 0, 40, 50);
-        assertEquals(textView.getWidth(), textView.computeHorizontalScrollRange());
+        mActivityRule.runOnUiThread(() -> ((MockTextView) mTextView).setFrame(0, 0, 40, 50));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mTextView.getWidth(),
+                ((MockTextView) mTextView).computeHorizontalScrollRange());
 
         // set the layout
-        layout(textView);
-        assertEquals(textView.getLayout().getWidth(), textView.computeHorizontalScrollRange());
+        layout(mTextView);
+        assertEquals(mTextView.getLayout().getWidth(),
+                ((MockTextView) mTextView).computeHorizontalScrollRange());
     }
 
-    public void testComputeVerticalScrollRange() {
-        MockTextView textView = new MockTextView(mActivity);
-        // test when layout is null
-        assertNull(textView.getLayout());
-        assertEquals(0, textView.computeVerticalScrollRange());
+    @Test
+    public void testComputeVerticalScrollRange() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = new MockTextView(mActivity));
+        mInstrumentation.waitForIdleSync();
 
-        textView.setFrame(0, 0, 40, 50);
-        assertEquals(textView.getHeight(), textView.computeVerticalScrollRange());
+        // test when layout is null
+        assertNull(mTextView.getLayout());
+        assertEquals(0, ((MockTextView) mTextView).computeVerticalScrollRange());
+
+        mActivityRule.runOnUiThread(() -> ((MockTextView) mTextView).setFrame(0, 0, 40, 50));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(mTextView.getHeight(), ((MockTextView) mTextView).computeVerticalScrollRange());
 
         //set the layout
-        layout(textView);
-        assertEquals(textView.getLayout().getHeight(), textView.computeVerticalScrollRange());
+        layout(mTextView);
+        assertEquals(mTextView.getLayout().getHeight(),
+                ((MockTextView) mTextView).computeVerticalScrollRange());
     }
 
-    public void testDrawableStateChanged() {
-        MockTextView textView = new MockTextView(mActivity);
-
-        textView.reset();
-        textView.refreshDrawableState();
-        assertTrue(textView.hasCalledDrawableStateChanged());
+    @Test
+    public void testDrawableStateChanged() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = spy(new MockTextView(mActivity)));
+        mInstrumentation.waitForIdleSync();
+        reset(mTextView);
+        mTextView.refreshDrawableState();
+        ((MockTextView) verify(mTextView, times(1))).drawableStateChanged();
     }
 
+    @UiThreadTest
+    @Test
     public void testGetDefaultEditable() {
-        MockTextView textView = new MockTextView(mActivity);
+        mTextView = new MockTextView(mActivity);
 
         //the TextView#getDefaultEditable() does nothing, and always return false.
-        assertFalse(textView.getDefaultEditable());
+        assertFalse(((MockTextView) mTextView).getDefaultEditable());
     }
 
+    @UiThreadTest
+    @Test
     public void testGetDefaultMovementMethod() {
         MockTextView textView = new MockTextView(mActivity);
 
@@ -3631,337 +4304,312 @@
         assertNull(textView.getDefaultMovementMethod());
     }
 
-    public void testOnCreateContextMenu() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnDetachedFromWindow() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnDraw() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnFocusChanged() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnMeasure() {
-        // Do not test. Implementation details.
-    }
-
-    public void testOnTextChanged() {
-        // Do not test. Implementation details.
-    }
-
+    @UiThreadTest
+    @Test
     public void testSetFrame() {
         MockTextView textView = new MockTextView(mActivity);
 
         //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);
-        textView.setText(LONG_TEXT);
-        textView.setSingleLine();
-        textView.setEllipsize(TruncateAt.MARQUEE);
-        textView.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+    @Test
+    public void testMarquee() throws Throwable {
+        // 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.
+        mActivityRule.runOnUiThread(() -> {
+            mSecondTextView = new MockTextView(mActivity);
 
-        final FrameLayout layout = new FrameLayout(mActivity);
-        layout.addView(textView);
-
-        // make the fading to be shown
-        textView.setHorizontalFadingEdgeEnabled(true);
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layout);
-            }
+            mTextView = mSecondTextView;
+            mTextView.setText(LONG_TEXT);
+            mTextView.setSingleLine();
+            mTextView.setEllipsize(TruncateAt.MARQUEE);
+            mTextView.setLayoutParams(new LayoutParams(100, 100));
         });
         mInstrumentation.waitForIdleSync();
 
-        TestSelectedRunnable runnable = new TestSelectedRunnable(textView) {
+        final FrameLayout layout = new FrameLayout(mActivity);
+        layout.addView(mTextView);
+
+        // make the fading to be shown
+        mTextView.setHorizontalFadingEdgeEnabled(true);
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        TestSelectedRunnable runnable = new TestSelectedRunnable(mTextView) {
             public void run() {
-                textView.setMarqueeRepeatLimit(-1);
+                mTextView.setMarqueeRepeatLimit(-1);
                 // force the marquee to start
                 saveIsSelected1();
-                textView.setSelected(true);
+                mTextView.setSelected(true);
                 saveIsSelected2();
             }
         };
-        mActivity.runOnUiThread(runnable);
+        mActivityRule.runOnUiThread(runnable);
 
         // 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) mSecondTextView).getLeftFadingEdgeStrength() > 0.0f
+                        && ((MockTextView) mSecondTextView).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) mSecondTextView).getLeftFadingEdgeStrength() > 0.99f);
+
         assertFalse(runnable.getIsSelected1());
         assertTrue(runnable.getIsSelected2());
+        assertEquals(-1, mTextView.getMarqueeRepeatLimit());
 
-        runnable = new TestSelectedRunnable(textView) {
+        runnable = new TestSelectedRunnable(mTextView) {
             public void run() {
-                textView.setMarqueeRepeatLimit(0);
+                mTextView.setMarqueeRepeatLimit(0);
                 // force the marquee to stop
                 saveIsSelected1();
-                textView.setSelected(false);
+                mTextView.setSelected(false);
                 saveIsSelected2();
-                textView.setGravity(Gravity.LEFT);
+                mTextView.setGravity(Gravity.LEFT);
             }
         };
         // force the marquee to stop
-        mActivity.runOnUiThread(runnable);
+        mActivityRule.runOnUiThread(runnable);
         mInstrumentation.waitForIdleSync();
         assertTrue(runnable.getIsSelected1());
         assertFalse(runnable.getIsSelected2());
-        assertEquals(0.0f, textView.getLeftFadingEdgeStrength(), 0.01f);
-        assertTrue(textView.getRightFadingEdgeStrength() > 0.0f);
+        assertEquals(0.0f, ((MockTextView) mSecondTextView).getLeftFadingEdgeStrength(), 0.01f);
+        assertTrue(((MockTextView) mSecondTextView).getRightFadingEdgeStrength() > 0.0f);
+        assertEquals(0, mTextView.getMarqueeRepeatLimit());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setGravity(Gravity.RIGHT);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.setGravity(Gravity.RIGHT));
         mInstrumentation.waitForIdleSync();
-        assertTrue(textView.getLeftFadingEdgeStrength() > 0.0f);
-        assertEquals(0.0f, textView.getRightFadingEdgeStrength(), 0.01f);
+        assertTrue(((MockTextView) mSecondTextView).getLeftFadingEdgeStrength() > 0.0f);
+        assertEquals(0.0f, ((MockTextView) mSecondTextView).getRightFadingEdgeStrength(), 0.01f);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                textView.setGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.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) mSecondTextView).getLeftFadingEdgeStrength(), 0.01f);
+        assertTrue(((MockTextView) mSecondTextView).getRightFadingEdgeStrength() > 0.0f);
     }
 
-    public void testOnKeyMultiple() {
-        // Do not test. Implementation details.
+    @UiThreadTest
+    @Test
+    public void testGetMarqueeRepeatLimit() {
+        final TextView textView = new TextView(mActivity);
+
+        textView.setMarqueeRepeatLimit(10);
+        assertEquals(10, textView.getMarqueeRepeatLimit());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessInputExtras() throws XmlPullParserException, IOException {
-        TextView textView = new TextView(mActivity);
-        textView.setText(null, BufferType.EDITABLE);
-        textView.setInputType(InputType.TYPE_CLASS_TEXT);
+        mTextView = new TextView(mActivity);
+        mTextView.setText(null, BufferType.EDITABLE);
+        mTextView.setInputType(InputType.TYPE_CLASS_TEXT);
 
         // do not create the extras
-        assertNull(textView.getInputExtras(false));
+        assertNull(mTextView.getInputExtras(false));
 
         // create if it does not exist
-        Bundle inputExtras = textView.getInputExtras(true);
+        Bundle inputExtras = mTextView.getInputExtras(true);
         assertNotNull(inputExtras);
         assertTrue(inputExtras.isEmpty());
 
         // it is created already
-        assertNotNull(textView.getInputExtras(false));
+        assertNotNull(mTextView.getInputExtras(false));
 
         try {
-            textView.setInputExtras(R.xml.input_extras);
+            mTextView.setInputExtras(R.xml.input_extras);
             fail("Should throw NullPointerException!");
         } catch (NullPointerException e) {
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessContentType() {
-        TextView textView = new TextView(mActivity);
-        textView.setText(null, BufferType.EDITABLE);
-        textView.setKeyListener(null);
-        textView.setTransformationMethod(null);
+        mTextView = new TextView(mActivity);
+        mTextView.setText(null, BufferType.EDITABLE);
+        mTextView.setKeyListener(null);
+        mTextView.setTransformationMethod(null);
 
-        textView.setInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_NORMAL);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_NORMAL, textView.getInputType());
-        assertTrue(textView.getKeyListener() instanceof DateTimeKeyListener);
+                | InputType.TYPE_DATETIME_VARIATION_NORMAL, mTextView.getInputType());
+        assertTrue(mTextView.getKeyListener() instanceof DateTimeKeyListener);
 
-        textView.setInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_DATE);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_DATE, textView.getInputType());
-        assertTrue(textView.getKeyListener() instanceof DateKeyListener);
+                | InputType.TYPE_DATETIME_VARIATION_DATE, mTextView.getInputType());
+        assertTrue(mTextView.getKeyListener() instanceof DateKeyListener);
 
-        textView.setInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_TIME);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_TIME, textView.getInputType());
-        assertTrue(textView.getKeyListener() instanceof TimeKeyListener);
+                | InputType.TYPE_DATETIME_VARIATION_TIME, mTextView.getInputType());
+        assertTrue(mTextView.getKeyListener() instanceof TimeKeyListener);
 
-        textView.setInputType(InputType.TYPE_CLASS_NUMBER
+        mTextView.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, textView.getInputType());
-        assertSame(textView.getKeyListener(), DigitsKeyListener.getInstance(true, true));
+                | InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
+        assertSame(mTextView.getKeyListener(), DigitsKeyListener.getInstance(true, true));
 
-        textView.setInputType(InputType.TYPE_CLASS_PHONE);
-        assertEquals(InputType.TYPE_CLASS_PHONE, textView.getInputType());
-        assertTrue(textView.getKeyListener() instanceof DialerKeyListener);
+        mTextView.setInputType(InputType.TYPE_CLASS_PHONE);
+        assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
+        assertTrue(mTextView.getKeyListener() instanceof DialerKeyListener);
 
-        textView.setInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, textView.getInputType());
-        assertSame(textView.getKeyListener(), TextKeyListener.getInstance(true, Capitalize.NONE));
+                | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, mTextView.getInputType());
+        assertSame(mTextView.getKeyListener(), TextKeyListener.getInstance(true, Capitalize.NONE));
 
-        textView.setSingleLine();
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        textView.setInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setSingleLine();
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        mTextView.setInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
         assertEquals(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
-                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, textView.getInputType());
-        assertSame(textView.getKeyListener(),
+                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, mTextView.getInputType());
+        assertSame(mTextView.getKeyListener(),
                 TextKeyListener.getInstance(false, Capitalize.CHARACTERS));
-        assertNull(textView.getTransformationMethod());
+        assertNull(mTextView.getTransformationMethod());
 
-        textView.setInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_CAP_WORDS, textView.getInputType());
-        assertSame(textView.getKeyListener(),
+                | InputType.TYPE_TEXT_FLAG_CAP_WORDS, mTextView.getInputType());
+        assertSame(mTextView.getKeyListener(),
                 TextKeyListener.getInstance(false, Capitalize.WORDS));
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
 
-        textView.setInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, textView.getInputType());
-        assertSame(textView.getKeyListener(),
+                | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, mTextView.getInputType());
+        assertSame(mTextView.getKeyListener(),
                 TextKeyListener.getInstance(false, Capitalize.SENTENCES));
 
-        textView.setInputType(InputType.TYPE_NULL);
-        assertEquals(InputType.TYPE_NULL, textView.getInputType());
-        assertTrue(textView.getKeyListener() instanceof TextKeyListener);
+        mTextView.setInputType(InputType.TYPE_NULL);
+        assertEquals(InputType.TYPE_NULL, mTextView.getInputType());
+        assertTrue(mTextView.getKeyListener() instanceof TextKeyListener);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessRawContentType() {
-        TextView textView = new TextView(mActivity);
-        textView.setText(null, BufferType.EDITABLE);
-        textView.setKeyListener(null);
-        textView.setTransformationMethod(null);
+        mTextView = new TextView(mActivity);
+        mTextView.setText(null, BufferType.EDITABLE);
+        mTextView.setKeyListener(null);
+        mTextView.setTransformationMethod(null);
 
-        textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setRawInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_NORMAL);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_NORMAL, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_DATETIME_VARIATION_NORMAL, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setRawInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_DATE);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_DATE, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_DATETIME_VARIATION_DATE, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
+        mTextView.setRawInputType(InputType.TYPE_CLASS_DATETIME
                 | InputType.TYPE_DATETIME_VARIATION_TIME);
         assertEquals(InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_TIME, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_DATETIME_VARIATION_TIME, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_NUMBER
+        mTextView.setRawInputType(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, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_PHONE);
-        assertEquals(InputType.TYPE_CLASS_PHONE, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+        mTextView.setRawInputType(InputType.TYPE_CLASS_PHONE);
+        assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setRawInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, textView.getInputType());
-        assertNull(textView.getTransformationMethod());
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, mTextView.getInputType());
+        assertNull(mTextView.getTransformationMethod());
+        assertNull(mTextView.getKeyListener());
 
-        textView.setSingleLine();
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        textView.setRawInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setSingleLine();
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        mTextView.setRawInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
         assertEquals(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
-                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, textView.getInputType());
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, mTextView.getInputType());
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setRawInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_CAP_WORDS, textView.getInputType());
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_TEXT_FLAG_CAP_WORDS, mTextView.getInputType());
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_CLASS_TEXT
+        mTextView.setRawInputType(InputType.TYPE_CLASS_TEXT
                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
         assertEquals(InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, textView.getInputType());
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        assertNull(textView.getKeyListener());
+                | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, mTextView.getInputType());
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        assertNull(mTextView.getKeyListener());
 
-        textView.setRawInputType(InputType.TYPE_NULL);
-        assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
-        assertNull(textView.getKeyListener());
+        mTextView.setRawInputType(InputType.TYPE_NULL);
+        assertTrue(mTextView.getTransformationMethod() instanceof SingleLineTransformationMethod);
+        assertNull(mTextView.getKeyListener());
     }
 
-    public void testOnPrivateIMECommand() {
-        // Do not test. Implementation details.
-    }
-
-    public void testFoo() {
-        // Do not test. Implementation details.
-    }
-
+    @UiThreadTest
+    @Test
     public void testVerifyDrawable() {
-        MockTextView textView = new MockTextView(mActivity);
+        mTextView = new MockTextView(mActivity);
 
-        Drawable d = getDrawable(R.drawable.pass);
-        assertFalse(textView.verifyDrawable(d));
+        Drawable d = TestUtils.getDrawable(mActivity, R.drawable.pass);
+        assertFalse(((MockTextView ) mTextView).verifyDrawable(d));
 
-        textView.setCompoundDrawables(null, d, null, null);
-        assertTrue(textView.verifyDrawable(d));
+        mTextView.setCompoundDrawables(null, d, null, null);
+        assertTrue(((MockTextView ) mTextView).verifyDrawable(d));
     }
 
+    @Test
     public void testAccessPrivateImeOptions() {
         mTextView = findTextView(R.id.textview_text);
         assertNull(mTextView.getPrivateImeOptions());
@@ -3973,19 +4621,23 @@
         assertNull(mTextView.getPrivateImeOptions());
     }
 
+    @Test
     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);
     }
 
+    @Test
     public void testAccessImeOptions() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(EditorInfo.IME_NULL, mTextView.getImeOptions());
@@ -4000,6 +4652,7 @@
         assertEquals(EditorInfo.IME_NULL, mTextView.getImeOptions());
     }
 
+    @Test
     public void testAccessImeActionLabel() {
         mTextView = findTextView(R.id.textview_text);
         assertNull(mTextView.getImeActionLabel());
@@ -4010,6 +4663,8 @@
         assertEquals(1, mTextView.getImeActionId());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessImeHintLocales() {
         final TextView textView = new TextView(mActivity);
         textView.setText("", BufferType.EDITABLE);
@@ -4033,6 +4688,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetExtractedText() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
@@ -4088,86 +4744,117 @@
         assertEquals("ctstest://TextView/test", urlSpans[0].getURL());
     }
 
+    @Test
     public void testMoveCursorToVisibleOffset() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
 
         // not a spannable text
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertFalse(mTextView.moveCursorToVisibleOffset());
-            }
-        });
+        mActivityRule.runOnUiThread(() -> assertFalse(mTextView.moveCursorToVisibleOffset()));
         mInstrumentation.waitForIdleSync();
 
         // a selection range
         final String spannableText = "text";
-        mTextView = new TextView(mActivity);
+        mActivityRule.runOnUiThread(() ->  mTextView = new TextView(mActivity));
+        mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(spannableText, BufferType.SPANNABLE);
-            }
-        });
+        mActivityRule.runOnUiThread(
+                () -> 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());
-            }
-        });
+        mActivityRule.runOnUiThread(() -> 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);
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mTextView = findTextView(R.id.textview_text);
+            mTextView.setText(spannableText, BufferType.SPANNABLE);
         });
         mInstrumentation.waitForIdleSync();
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                assertTrue(mTextView.moveCursorToVisibleOffset());
-            }
-        });
+        mActivityRule.runOnUiThread(() -> assertTrue(mTextView.moveCursorToVisibleOffset()));
         mInstrumentation.waitForIdleSync();
     }
 
+    @Test
     public void testIsInputMethodTarget() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         assertFalse(mTextView.isInputMethodTarget());
 
         assertFalse(mTextView.isFocused());
-        runTestOnUiThread(new Runnable() {
-           @Override
-            public void run() {
-               mTextView.setFocusable(true);
-               mTextView.requestFocus();
-            }
-        });
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setFocusable(true);
+            mTextView.requestFocus();
+         });
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.isFocused());
 
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mTextView.isInputMethodTarget();
-            }
-        }.run();
-    }
-
-    public void testBeginEndBatchEdit() {
-        mTextView = findTextView(R.id.textview_text);
-
-        mTextView.beginBatchEdit();
-        mTextView.endBatchEdit();
+        PollingCheck.waitFor(mTextView::isInputMethodTarget);
     }
 
     @UiThreadTest
+    @Test
+    public void testBeginEndBatchEditAreNotCalledForNonEditableText() {
+        final TextView mockTextView = spy(new TextView(mActivity));
+
+        // 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();
+    }
+
+    @Test
+    public void testBeginEndBatchEditCallbacksAreCalledForEditableText() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView = spy(new TextView(mActivity)));
+        mInstrumentation.waitForIdleSync();
+
+        final FrameLayout layout = new FrameLayout(mActivity);
+        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        layout.addView(mTextView, layoutParams);
+        layout.setLayoutParams(layoutParams);
+
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layout));
+        mInstrumentation.waitForIdleSync();
+
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
+            mTextView.setText("", BufferType.EDITABLE);
+            mTextView.requestFocus();
+        });
+        mInstrumentation.waitForIdleSync();
+
+        reset(mTextView);
+        assertTrue(mTextView.hasFocus());
+        verify(mTextView, never()).onBeginBatchEdit();
+        verify(mTextView, never()).onEndBatchEdit();
+
+        mTextView.beginBatchEdit();
+
+        verify(mTextView, times(1)).onBeginBatchEdit();
+        verify(mTextView, never()).onEndBatchEdit();
+
+        reset(mTextView);
+        mTextView.endBatchEdit();
+        verify(mTextView, never()).onBeginBatchEdit();
+        verify(mTextView, times(1)).onEndBatchEdit();
+    }
+
+    @UiThreadTest
+    @Test
     public void testBringPointIntoView() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
         assertFalse(mTextView.bringPointIntoView(1));
@@ -4176,13 +4863,15 @@
         assertFalse(mTextView.bringPointIntoView(2));
     }
 
+    @Test
     public void testCancelLongPress() {
         mTextView = findTextView(R.id.textview_text);
-        TouchUtils.longClickView(this, mTextView);
+        CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, mTextView);
         mTextView.cancelLongPress();
     }
 
     @UiThreadTest
+    @Test
     public void testClearComposingText() {
         mTextView = findTextView(R.id.textview_text);
         mTextView.setText("Hello world!", BufferType.SPANNABLE);
@@ -4200,17 +4889,20 @@
         assertEquals(-1, BaseInputConnection.getComposingSpanStart(text));
     }
 
+    @UiThreadTest
+    @Test
     public void testComputeVerticalScrollExtent() {
-        MockTextView textView = new MockTextView(mActivity);
-        assertEquals(0, textView.computeVerticalScrollExtent());
+        mTextView = new MockTextView(mActivity);
+        assertEquals(0, ((MockTextView) mTextView).computeVerticalScrollExtent());
 
-        Drawable d = getDrawable(R.drawable.pass);
-        textView.setCompoundDrawables(null, d, null, d);
+        Drawable d = TestUtils.getDrawable(mActivity, R.drawable.pass);
+        mTextView.setCompoundDrawables(null, d, null, d);
 
-        assertEquals(0, textView.computeVerticalScrollExtent());
+        assertEquals(0, ((MockTextView) mTextView).computeVerticalScrollExtent());
     }
 
     @UiThreadTest
+    @Test
     public void testDidTouchFocusSelect() {
         mTextView = new EditText(mActivity);
         assertFalse(mTextView.didTouchFocusSelect());
@@ -4220,25 +4912,24 @@
         assertTrue(mTextView.didTouchFocusSelect());
     }
 
-    public void testSelectAllJustAfterTap() {
+    @Test
+    public void testSelectAllJustAfterTap() throws Throwable {
         // Prepare an EditText with focus.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView = new EditText(mActivity);
-                mActivity.setContentView(mTextView);
+        mActivityRule.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);
@@ -4247,11 +4938,7 @@
         }
 
         // Execute SelectAll context menu.
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.onTextContextMenuItem(android.R.id.selectAll);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mTextView.onTextContextMenuItem(android.R.id.selectAll));
         mInstrumentation.waitForIdleSync();
 
         // The selection must be whole of the text contents.
@@ -4260,6 +4947,8 @@
         assertEquals(mTextView.length(), mTextView.getSelectionEnd());
     }
 
+    @UiThreadTest
+    @Test
     public void testExtractText() {
         mTextView = new TextView(mActivity);
 
@@ -4285,12 +4974,14 @@
     }
 
     @UiThreadTest
+    @Test
     public void testTextDirectionDefault() {
         TextView tv = new TextView(mActivity);
         assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getRawTextDirection());
     }
 
     @UiThreadTest
+    @Test
     public void testSetGetTextDirection() {
         TextView tv = new TextView(mActivity);
 
@@ -4320,6 +5011,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextDirectionLtr() {
         TextView tv = new TextView(mActivity);
         tv.setText("this is a test");
@@ -4352,6 +5044,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextDirectionLtrWithInheritance() {
         LinearLayout ll = new LinearLayout(mActivity);
         ll.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
@@ -4386,6 +5079,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextDirectionRtl() {
         TextView tv = new TextView(mActivity);
         tv.setText("\u05DD\u05DE"); // hebrew
@@ -4418,6 +5112,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextDirectionRtlWithInheritance() {
         LinearLayout ll = new LinearLayout(mActivity);
         ll.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
@@ -4479,6 +5174,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testResetTextDirection() {
         LinearLayout ll = (LinearLayout) mActivity.findViewById(R.id.layout_textviewtest);
         TextView tv = (TextView) mActivity.findViewById(R.id.textview_rtl);
@@ -4497,6 +5193,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testTextDirectionFirstStrongLtr() {
         {
             // The first directional character is LTR, the paragraph direction is LTR.
@@ -4547,6 +5244,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testTextDirectionFirstStrongRtl() {
         {
             // The first directional character is LTR, the paragraph direction is LTR.
@@ -4596,6 +5294,8 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testTextLocales() {
         TextView tv = new TextView(mActivity);
         assertEquals(Locale.getDefault(), tv.getTextLocale());
@@ -4631,6 +5331,8 @@
         }
     }
 
+    @UiThreadTest
+    @Test
     public void testAllCapsLocalization() {
         String testString = "abcdefghijklmnopqrstuvwxyz";
 
@@ -4652,16 +5354,18 @@
     }
 
     @UiThreadTest
+    @Test
     public void testTextAlignmentDefault() {
-        TextView tv = new TextView(getActivity());
+        TextView tv = new TextView(mActivity);
         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
         // resolved default text alignment is GRAVITY
         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
     }
 
     @UiThreadTest
+    @Test
     public void testSetGetTextAlignment() {
-        TextView tv = new TextView(getActivity());
+        TextView tv = new TextView(mActivity);
 
         tv.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
@@ -4683,8 +5387,9 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextAlignment() {
-        TextView tv = new TextView(getActivity());
+        TextView tv = new TextView(mActivity);
 
         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
 
@@ -4710,11 +5415,12 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetResolvedTextAlignmentWithInheritance() {
-        LinearLayout ll = new LinearLayout(getActivity());
+        LinearLayout ll = new LinearLayout(mActivity);
         ll.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
 
-        TextView tv = new TextView(getActivity());
+        TextView tv = new TextView(mActivity);
         ll.addView(tv);
 
         // check defaults
@@ -4760,11 +5466,10 @@
     }
 
     @UiThreadTest
+    @Test
     public void testResetTextAlignment() {
-        TextViewCtsActivity activity = getActivity();
-
-        LinearLayout ll = (LinearLayout) activity.findViewById(R.id.layout_textviewtest);
-        TextView tv = (TextView) activity.findViewById(R.id.textview_rtl);
+        LinearLayout ll = (LinearLayout) mActivity.findViewById(R.id.layout_textviewtest);
+        TextView tv = (TextView) mActivity.findViewById(R.id.textview_rtl);
 
         ll.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
         tv.setTextAlignment(View.TEXT_ALIGNMENT_INHERIT);
@@ -4781,233 +5486,166 @@
     }
 
     @UiThreadTest
+    @Test
     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
+    @Test
     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();
-
-        WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
-                ((BitmapDrawable) drawables[LEFT]).getBitmap());
-        assertNull(drawables[RIGHT]);
-        assertNull(drawables[TOP]);
-        assertNull(drawables[BOTTOM]);
-
-        tv = (TextView) activity.findViewById(R.id.textview_ltr);
-        drawables = tv.getCompoundDrawables();
-
-        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]);
+        tv.setCompoundDrawablesRelative(TestUtils.getDrawable(mActivity, R.drawable.icon_yellow),
+                null, null, null);
+        TestUtils.verifyCompoundDrawables(tv, R.drawable.icon_yellow, -1, -1, -1);
     }
 
+    @Test
+    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);
+
+        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());
+
+        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());
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetGetBreakStrategy() {
         TextView tv = new TextView(mActivity);
 
-        final PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+        final PackageManager pm = mInstrumentation.getTargetContext().getPackageManager();
 
         // The default value is from the theme, here the default is BREAK_STRATEGY_HIGH_QUALITY for
         // TextView except for Android Wear. The default value for Android Wear is
@@ -5045,6 +5683,8 @@
         assertEquals(Layout.BREAK_STRATEGY_BALANCED, et.getBreakStrategy());
     }
 
+    @UiThreadTest
+    @Test
     public void testSetGetHyphenationFrequency() {
         TextView tv = new TextView(mActivity);
 
@@ -5060,163 +5700,1002 @@
         assertEquals(Layout.HYPHENATION_FREQUENCY_FULL, tv.getHyphenationFrequency());
     }
 
-    public void testSetAndGetCustomSelectionActionModeCallback() {
+    @Test
+    public void testSetAndGetCustomSelectionActionModeCallback() throws Throwable {
         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);
-            }
+        mActivityRule.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);
-            }
+        mActivityRule.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);
-            }
+        mActivityRule.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);
+        mActivityRule.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);
-            }
+        mActivityRule.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
+    @Test
+    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;
+    @Test
+    public void testTextShadows() throws Throwable {
+        final TextView textViewWithConfiguredShadow =
+                (TextView) mActivity.findViewById(R.id.textview_with_shadow);
+        assertEquals(1.0f, textViewWithConfiguredShadow.getShadowDx(), 0.0f);
+        assertEquals(2.0f, textViewWithConfiguredShadow.getShadowDy(), 0.0f);
+        assertEquals(3.0f, textViewWithConfiguredShadow.getShadowRadius(), 0.0f);
+        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(), 0.0f);
+        assertEquals(0.0f, textView.getShadowDy(), 0.0f);
+        assertEquals(0.0f, textView.getShadowRadius(), 0.0f);
 
-        public int getCreateCount() {
-            return mCreateCount;
-        }
+        mActivityRule.runOnUiThread(() -> textView.setShadowLayer(5.0f, 3.0f, 4.0f, Color.RED));
+        mInstrumentation.waitForIdleSync();
+        assertEquals(3.0f, textView.getShadowDx(), 0.0f);
+        assertEquals(4.0f, textView.getShadowDy(), 0.0f);
+        assertEquals(5.0f, textView.getShadowRadius(), 0.0f);
+        assertEquals(Color.RED, textView.getShadowColor());
+    }
 
-        public int getDestroyCount() {
-            return mDestroyCount;
+    @Test
+    public void testFontFeatureSettings() throws Throwable {
+        final TextView textView = (TextView) mActivity.findViewById(R.id.textview_text);
+        assertTrue(TextUtils.isEmpty(textView.getFontFeatureSettings()));
+
+        mActivityRule.runOnUiThread(() -> textView.setFontFeatureSettings("smcp"));
+        mInstrumentation.waitForIdleSync();
+        assertEquals("smcp", textView.getFontFeatureSettings());
+
+        mActivityRule.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);
-            }
+    @Test
+    public void testAccessShowSoftInputOnFocus() throws Throwable {
+        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);
+        mActivityRule.runOnUiThread(() -> scrollView.fullScroll(View.FOCUS_DOWN));
+        mInstrumentation.waitForIdleSync();
+
+        // Mark it to show soft input on focus
+        mActivityRule.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
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+
+        // Reconfigure our edit text to not show soft input on focus
+        mActivityRule.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
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+    }
+
+    @Test
+    public void testIsSuggestionsEnabled() throws Throwable {
+        mTextView = findTextView(R.id.textview_text);
+
+        // Anything without InputType.TYPE_CLASS_TEXT doesn't have suggestions enabled
+        mActivityRule.runOnUiThread(() -> mTextView.setInputType(InputType.TYPE_CLASS_DATETIME));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(() -> mTextView.setInputType(InputType.TYPE_CLASS_PHONE));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(() -> 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
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL |
+                                InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> 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
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT));
+        assertTrue(mTextView.isSuggestionsEnabled());
+
+        // and not on any other type variation
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT |
+                                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT |
+                                InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS));
+        assertFalse(mTextView.isSuggestionsEnabled());
+
+        mActivityRule.runOnUiThread(
+                () -> mTextView.setInputType(
+                        InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD));
+        assertFalse(mTextView.isSuggestionsEnabled());
+    }
+
+    @Test
+    public void testAccessLetterSpacing() throws Throwable {
+        mTextView = findTextView(R.id.textview_text);
+        assertEquals(0.0f, mTextView.getLetterSpacing(), 0.0f);
+
+        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(mActivityRule, mTextView,
+                () -> mTextView.setLetterSpacing(1.0f));
+        assertEquals(1.0f, mTextView.getLetterSpacing(), 0.0f);
+        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(mActivityRule, mTextView,
+                () -> mTextView.setLetterSpacing(2.0f));
+        assertEquals(2.0f, mTextView.getLetterSpacing(), 0.0f);
+        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);
+        }
+    }
+
+    @Test
+    public void testTextIsSelectableFocusAndOnClick() throws Throwable {
+        // Prepare a focusable TextView with an onClickListener attached.
+        final View.OnClickListener mockOnClickListener = mock(View.OnClickListener.class);
+        final int safeDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout() + 1;
+        mActivityRule.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);
+        SystemClock.sleep(safeDoubleTapTimeout);
+        assertTrue(mTextView.isInTouchMode());
+        assertFalse(mTextView.isFocused());
+        verify(mockOnClickListener, times(1)).onClick(mTextView);
+        reset(mockOnClickListener);
+        // So does the second tap.
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        SystemClock.sleep(safeDoubleTapTimeout);
+        assertTrue(mTextView.isInTouchMode());
+        assertFalse(mTextView.isFocused());
+        verify(mockOnClickListener, times(1)).onClick(mTextView);
+
+        mActivityRule.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);
+        SystemClock.sleep(safeDoubleTapTimeout);
+        assertTrue(mTextView.isInTouchMode());
+        assertTrue(mTextView.isFocused());
+        verify(mockOnClickListener, never()).onClick(mTextView);
+        reset(mockOnClickListener);
+        // The second tap triggers onClick() and keeps the focus.
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mTextView);
+        SystemClock.sleep(safeDoubleTapTimeout);
+        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);
+    }
+
+    @Test
+    public void testGetOffsetForPosition() throws Throwable {
+        mTextView = findTextView(R.id.textview_text);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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
+    @Test
+    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));
+    }
+
+    @Test
+    public void testClickableSpanOnClickSingleTapInside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        CtsTouchUtils.emulateTapOnView(mInstrumentation, mTextView, spanDetails.mXPosInside,
+                spanDetails.mYPosInside);
+        SystemClock.sleep(ViewConfiguration.getDoubleTapTimeout() + 1);
+        verify(spanDetails.mClickableSpan, times(1)).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickDoubleTapInside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        CtsTouchUtils.emulateDoubleTapOnView(mInstrumentation, mTextView, spanDetails.mXPosInside,
+                spanDetails.mYPosInside);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickSingleTapOutside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        CtsTouchUtils.emulateTapOnView(mInstrumentation, mTextView, spanDetails.mXPosOutside,
+                spanDetails.mYPosOutside);
+        SystemClock.sleep(ViewConfiguration.getDoubleTapTimeout() + 1);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickDragOutside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        final int[] viewOnScreenXY = new int[2];
+        mTextView.getLocationOnScreen(viewOnScreenXY);
+
+        SparseArray<Point> swipeCoordinates = new SparseArray<>();
+        swipeCoordinates.put(0, new Point(viewOnScreenXY[0] + spanDetails.mXPosOutside,
+                viewOnScreenXY[1] + spanDetails.mYPosOutside));
+        swipeCoordinates.put(1, new Point(viewOnScreenXY[0] + spanDetails.mXPosOutside + 50,
+                viewOnScreenXY[1] + spanDetails.mYPosOutside + 50));
+        CtsTouchUtils.emulateDragGesture(mInstrumentation, swipeCoordinates);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickDragInsideFromOutside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        final int[] viewOnScreenXY = new int[2];
+        mTextView.getLocationOnScreen(viewOnScreenXY);
+
+        SparseArray<Point> swipeCoordinates = new SparseArray<>();
+        swipeCoordinates.put(0, new Point(viewOnScreenXY[0] + spanDetails.mXPosOutside,
+                viewOnScreenXY[1] + spanDetails.mYPosOutside));
+        swipeCoordinates.put(1, new Point(viewOnScreenXY[0] + spanDetails.mXPosInside,
+                viewOnScreenXY[1] + spanDetails.mYPosInside));
+        CtsTouchUtils.emulateDragGesture(mInstrumentation, swipeCoordinates);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickDragInsideOutsideInside() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        final int[] viewOnScreenXY = new int[2];
+        mTextView.getLocationOnScreen(viewOnScreenXY);
+
+        // Drag outside from within the clickable span and come back within the clickable span
+        // (without lifting the finger)
+        SparseArray<Point> swipeCoordinates = new SparseArray<>();
+        swipeCoordinates.put(0, new Point(viewOnScreenXY[0] + spanDetails.mXPosInside,
+                viewOnScreenXY[1] + spanDetails.mYPosInside));
+        swipeCoordinates.put(1, new Point(viewOnScreenXY[0] + spanDetails.mXPosOutside,
+                viewOnScreenXY[1] + spanDetails.mYPosOutside));
+        swipeCoordinates.put(2, new Point(viewOnScreenXY[0] + spanDetails.mXPosInside,
+                viewOnScreenXY[1] + spanDetails.mYPosInside));
+        CtsTouchUtils.emulateDragGesture(mInstrumentation, swipeCoordinates);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testClickableSpanOnClickLongPress() throws Throwable {
+        ClickableSpanTestDetails spanDetails = prepareAndRetrieveClickableSpanDetails();
+        CtsTouchUtils.emulateLongPressOnView(mInstrumentation, mTextView, spanDetails.mXPosInside,
+                spanDetails.mYPosInside);
+        verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
+    }
+
+    @Test
+    public void testAutoSizeCallers_setCompoundDrawables() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 20, 20);
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setCompoundDrawables(drawable, drawable, drawable, drawable));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setCompoundDrawablesRelative() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 20, 20);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setCompoundDrawablesRelative(
+                drawable, drawable, drawable, drawable));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setCompoundDrawablePadding() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+        // Setup the drawables before setting their padding in order to modify the available
+        // space and trigger a resize.
+        Drawable drawable = TestUtils.getDrawable(mActivity, R.drawable.red);
+        drawable.setBounds(0, 0, 20, 20);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setCompoundDrawables(
+                drawable, drawable, drawable, drawable));
+        mInstrumentation.waitForIdleSync();
+        reset(autoSizeTextView);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setCompoundDrawablePadding(50));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setPadding() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setPadding(10, 20, 30, 40));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setPaddingRelative() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setPaddingRelative(10, 20, 30, 40));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setTextScaleX() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setTextScaleX(autoSizeTextView.getTextScaleX() + 0.1f));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setTextScaleX(autoSizeTextView.getTextScaleX()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setTypeface() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setTypeface(Typeface.MONOSPACE));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setTypeface(autoSizeTextView.getTypeface()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setLetterSpacing() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setLetterSpacing(autoSizeTextView.getLetterSpacing() + 0.1f));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setLetterSpacing(autoSizeTextView.getLetterSpacing()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setFontFeatureSettings() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setFontFeatureSettings("smcp"));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() ->
+                autoSizeTextView.setFontFeatureSettings(autoSizeTextView.getFontFeatureSettings()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setHorizontallyScrolling() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
+                !autoSizeTextView.getHorizontallyScrolling()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
+                autoSizeTextView.getHorizontallyScrolling()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setMinLines() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMinLines(11));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setMinHeight() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMinHeight(666));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setMaxLines() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxLines(1));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setMaxHeight() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxHeight(99));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setHeight() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHeight(666));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setLines() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setLines(5));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setMaxWidth() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+        // Do not force exact width only.
+        final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT,
+                100);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setLayoutParams(layoutParams));
+        mInstrumentation.waitForIdleSync();
+        reset(autoSizeTextView);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setMaxWidth(100));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setWidth() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, true);
+
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setWidth(666));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeCallers_setLineSpacing() throws Throwable {
+        TextView autoSizeTextView = prepareAndRetrieveAutoSizeTextView(
+                R.id.textview_autosize_xy, false);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setLineSpacing(
+                autoSizeTextView.getLineSpacingExtra() * 2,
+                autoSizeTextView.getLineSpacingMultiplier() * 2));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, times(1))
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+        reset(autoSizeTextView);
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setLineSpacing(
+                autoSizeTextView.getLineSpacingExtra(),
+                autoSizeTextView.getLineSpacingMultiplier()));
+        mInstrumentation.waitForIdleSync();
+        verify(autoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+    }
+
+    @Test
+    public void testAutoSizeXY_obtainStyledAttributes() {
+        DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+        TextView autoSizeTextViewXY = (TextView) mActivity.findViewById(R.id.textview_autosize_xy);
+
+        // The size has been set to 50dp in the layout but this being an AUTO_SIZE_TYPE_XY TextView,
+        // the size is considered max size thus the value returned by getSize() in this case should
+        // be lower than the one set (given that there is not much available space and the font size
+        // is very high). In theory the values could be equal for a different TextView
+        // configuration.
+        final float sizeSetInPixels = TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 50f, metrics);
+        assertTrue(autoSizeTextViewXY.getTextSize() < sizeSetInPixels);
+    }
+
+    /**
+     * Removes all existing views from the layout and makes a spied copy of the requested view,
+     * attaches it to the layout and returns it after resetting. Some TextView attributes require
+     * non-fixed width and layout height.
+     *
+     * @param viewId The id of the view to spy, reset and return.
+     * @param shouldWrapLayoutContent Specifies if the layout params should wrap content
+     *
+     * @return a spied version of the view ready to test.
+     */
+    private TextView prepareAndRetrieveAutoSizeTextView(final int viewId,
+            final boolean shouldWrapLayoutContent) throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            LinearLayout ll = (LinearLayout) mActivity.findViewById(R.id.layout_textviewtest);
+            TextView textView = (TextView) mActivity.findViewById(viewId);
+            ll.removeAllViews();
+            ll.addView(spy(textView));
+        });
+        mInstrumentation.waitForIdleSync();
+        TextView spiedAutoSizeTextView = (TextView) mActivity.findViewById(viewId);
+        verify(spiedAutoSizeTextView, never())
+                .setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), any(Float.class));
+
+        if (shouldWrapLayoutContent) {
+            // Do not force exact width or height.
+            final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT);
+            mActivityRule.runOnUiThread(() -> spiedAutoSizeTextView.setLayoutParams(layoutParams));
+            mInstrumentation.waitForIdleSync();
+        }
+
+        reset(spiedAutoSizeTextView);
+
+        return spiedAutoSizeTextView;
+    }
+
+    /**
+     * Removes all existing views from the layout and adds a basic TextView (for exercising the
+     * ClickableSpan onClick() behavior) in order to prevent scrolling. Adds a ClickableSpan to the
+     * TextView and returns the ClickableSpan and position details about it to be used in individual
+     * tests.
+     */
+    private ClickableSpanTestDetails prepareAndRetrieveClickableSpanDetails() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            LinearLayout ll = (LinearLayout) mActivity.findViewById(R.id.layout_textviewtest);
+            ll.removeAllViews();
+            mTextView = new TextView(mActivity);
+            ll.addView(mTextView);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        ClickableSpan mockTextLink = mock(ClickableSpan.class);
+        StringBuilder textViewContent = new StringBuilder();
+        String clickableString = "clickMe!";
+        textViewContent.append(clickableString);
+        final int startPos = 0;
+
+        // Insert more characters to make some room for swiping.
+        for (int i = 0; i < 200; i++) {
+            textViewContent.append(" text");
+        }
+        SpannableString spannableString = new SpannableString(textViewContent);
+        final int endPos = clickableString.length();
+        spannableString.setSpan(mockTextLink, startPos, endPos, 0);
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setText(spannableString);
+            mTextView.setMovementMethod(LinkMovementMethod.getInstance());
+        });
+        mInstrumentation.waitForIdleSync();
+
+        return new ClickableSpanTestDetails(mockTextLink, mTextView, startPos, endPos);
+    }
+
+    private static final class ClickableSpanTestDetails {
+        ClickableSpan mClickableSpan;
+        int mXPosInside;
+        int mYPosInside;
+        int mXPosOutside;
+        int mYPosOutside;
+
+        private int mStartCharPos;
+        private int mEndCharPos;
+        private TextView mParent;
+
+        ClickableSpanTestDetails(ClickableSpan clickableSpan, TextView parent,
+                int startCharPos, int endCharPos) {
+            mClickableSpan = clickableSpan;
+            mParent = parent;
+            mStartCharPos = startCharPos;
+            mEndCharPos = endCharPos;
+
+            calculatePositions();
+        }
+
+        private void calculatePositions() {
+            int xStart = (int) mParent.getLayout().getPrimaryHorizontal(mStartCharPos, true);
+            int xEnd = (int) mParent.getLayout().getPrimaryHorizontal(mEndCharPos, true);
+            int line = mParent.getLayout().getLineForOffset(mEndCharPos);
+            int yTop = mParent.getLayout().getLineTop(line);
+            int yBottom = mParent.getLayout().getLineBottom(line);
+
+            mXPosInside = (xStart + xEnd) / 2;
+            mYPosInside = (yTop + yBottom) / 2;
+            mXPosOutside = xEnd + 1;
+            mYPosOutside = yBottom + 1;
+        }
+    }
+
+    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) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(textView));
+        mInstrumentation.waitForIdleSync();
     }
 
-    private void layout(final int layoutId) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mActivity.setContentView(layoutId);
-            }
-        });
+    private void layout(final int layoutId) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mActivity.setContentView(layoutId));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5228,56 +6707,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 setMaxWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxWidth(pixels);
-            }
-        });
+    private void setMaxLines(final int lines) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMaxLines(lines));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMinWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinWidth(pixels);
-            }
-        });
+    private void setMaxWidth(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMaxWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMaxHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxHeight(pixels);
-            }
-        });
+    private void setMinWidth(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMinWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMinHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinHeight(pixels);
-            }
-        });
+    private void setMaxHeight(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMaxHeight(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMinLines(final int minlines) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinLines(minlines);
-            }
-        });
+    private void setMinHeight(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMinHeight(pixels));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void setMinLines(final int minLines) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMinLines(minLines));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5288,84 +6744,48 @@
      * @param tv the text view
      * @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);
-            }
-        });
+    private void setSpannableText(final TextView tv, final String content) throws Throwable {
+        mActivityRule.runOnUiThread(() -> tv.setText(content, BufferType.SPANNABLE));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setLines(final int lines) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setLines(lines);
-            }
-        });
+    private void setLines(final int lines) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setLines(lines));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setHorizontallyScrolling(final boolean whether) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setHorizontallyScrolling(whether);
-            }
-        });
+    private void setHorizontallyScrolling(final boolean whether) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setHorizontallyScrolling(whether));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setWidth(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setWidth(pixels);
-            }
-        });
+    private void setWidth(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setWidth(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setHeight(final int pixels) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setHeight(pixels);
-            }
-        });
+    private void setHeight(final int pixels) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setHeight(pixels));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMinEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMinEms(ems);
-            }
-        });
+    private void setMinEms(final int ems) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMinEms(ems));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setMaxEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setMaxEms(ems);
-            }
-        });
+    private void setMaxEms(final int ems) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setMaxEms(ems));
         mInstrumentation.waitForIdleSync();
     }
 
-    private void setEms(final int ems) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setEms(ems);
-            }
-        });
+    private void setEms(final int ems) throws Throwable {
+        mActivityRule.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);
-            }
-        });
+    private void setLineSpacing(final float add, final float mult) throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTextView.setLineSpacing(add, mult));
         mInstrumentation.waitForIdleSync();
     }
 
@@ -5412,56 +6832,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;
@@ -5499,70 +6869,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/tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java
new file mode 100644
index 0000000..34fb8c0
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.TimePicker;
+
+/**
+ * A minimal application for {@link TimePicker} test.
+ */
+public class TimePickerCtsActivity extends Activity {
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.timepicker);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerDialogCtsActivity.java b/tests/tests/widget/src/android/widget/cts/TimePickerDialogCtsActivity.java
deleted file mode 100644
index f5c544b..0000000
--- a/tests/tests/widget/src/android/widget/cts/TimePickerDialogCtsActivity.java
+++ /dev/null
@@ -1,33 +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;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * A minimal application for TimePickerDialog test.
- */
-public class TimePickerDialogCtsActivity extends Activity {
-    /**
-     * Called with the activity is first created.
-     */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-}
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerDialogTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerDialogTest.java
deleted file mode 100644
index 73ddc04..0000000
--- a/tests/tests/widget/src/android/widget/cts/TimePickerDialogTest.java
+++ /dev/null
@@ -1,72 +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;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.DatePickerDialog;
-import android.app.TimePickerDialog;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.widget.TimePicker;
-
-/**
- * Test {@link TimePickerDialog}.
- */
-public class TimePickerDialogTest extends
-        ActivityInstrumentationTestCase2<TimePickerDialogCtsActivity> {
-
-    private Activity mActivity;
-
-    public TimePickerDialogTest() {
-        super(TimePickerDialogCtsActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
-    public void testConstructor() {
-        new TimePickerDialog(mActivity, null, 7, 0, true);
-
-        new TimePickerDialog(mActivity, AlertDialog.THEME_TRADITIONAL, null, 7, 0, true);
-
-        // Ensure the picker is shown using the Holo-style layout.
-        TimePickerDialog holoDialog = new TimePickerDialog(mActivity, AlertDialog.THEME_HOLO_DARK,
-                null, 7, 0, true);
-        assertEquals(TimePicker.MODE_SPINNER, holoDialog.getTimePicker().getMode());
-
-        // Ensure the picker is shown using the Material-style layout where available.
-        TimePickerDialog holoClockDialog = new TimePickerDialog(mActivity,
-                R.style.Theme_Holo_With_Material_Pickers, null, 7, 0, true);
-        final int expectedMode = mActivity.getResources().getInteger(R.integer.time_picker_mode);
-        assertEquals(expectedMode, holoClockDialog.getTimePicker().getMode());
-
-        new TimePickerDialog(mActivity,
-                android.R.style.Theme_Material_Dialog_Alert, null, 7, 0, true);
-
-        try {
-            new TimePickerDialog(null, null, 7, 0, true);
-            fail("should throw NullPointerException");
-        } catch (Exception e) {
-        }
-    }
-
-}
diff --git a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
index 39554bb..7f5d3e3 100644
--- a/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TimePickerTest.java
@@ -16,76 +16,100 @@
 
 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.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.os.Parcelable;
-import android.test.ActivityInstrumentationTestCase2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
 import android.widget.TimePicker;
-import android.widget.TimePicker.OnTimeChangedListener;
+
+import com.android.compatibility.common.util.CtsKeyEventUtil;
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * Test {@link TimePicker}.
  */
-public class TimePickerTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TimePickerTest {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
     private TimePicker mTimePicker;
 
-    private Activity mActivity;
+    @Rule
+    public ActivityTestRule<TimePickerCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TimePickerCtsActivity.class);
 
-    private Context mContext;
-
-    private Instrumentation mInstrumentation;
-
-    public TimePickerTest() {
-        super("android.widget.cts", CtsActivity.class);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_clock);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mInstrumentation = getInstrumentation();
-        mContext = mInstrumentation.getTargetContext();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructors() {
-        AttributeSet attrs =
-            mContext.getResources().getLayout(android.widget.cts.R.layout.timepicker);
+        AttributeSet attrs = mActivity.getResources().getLayout(R.layout.timepicker);
         assertNotNull(attrs);
 
-        new TimePicker(mContext);
-        try {
-            new TimePicker(null);
-            fail("did not throw NullPointerException when param context is null.");
-        } catch (NullPointerException e) {
-            // expected
-        }
+        new TimePicker(mActivity);
 
-        new TimePicker(mContext, 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, attrs);
+        new TimePicker(mActivity, null);
 
-        new TimePicker(mContext, 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, attrs, 0);
+        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);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext1() {
+        new TimePicker(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext2() {
+        AttributeSet attrs = mActivity.getResources().getLayout(R.layout.timepicker);
+        new TimePicker(null, attrs);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext3() {
+        AttributeSet attrs = mActivity.getResources().getLayout(R.layout.timepicker);
+        new TimePicker(null, attrs, 0);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetEnabled() {
-        mTimePicker = new TimePicker(mContext);
         assertTrue(mTimePicker.isEnabled());
 
         mTimePicker.setEnabled(false);
@@ -95,50 +119,63 @@
         assertTrue(mTimePicker.isEnabled());
     }
 
+    @UiThreadTest
+    @Test
     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());
+        mTimePicker.setHour(initialHour);
+        mTimePicker.setMinute(initialMinute);
+
+        // Now register the listener
+        TimePicker.OnTimeChangedListener mockOnTimeChangeListener =
+                mock(TimePicker.OnTimeChangedListener.class);
+        mTimePicker.setOnTimeChangedListener(mockOnTimeChangeListener);
+        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);
+        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());
+        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);
+        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);
+        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);
+        mTimePicker.setIs24HourView(!mTimePicker.is24HourView());
+        verifyZeroInteractions(mockOnTimeChangeListener);
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessCurrentHour() {
-        mTimePicker = new TimePicker(mContext);
-
         // AM/PM mode
         mTimePicker.setIs24HourView(false);
 
@@ -167,9 +204,9 @@
         assertEquals(Integer.valueOf(23), mTimePicker.getCurrentHour());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessHour() {
-        mTimePicker = new TimePicker(mContext);
-
         // AM/PM mode
         mTimePicker.setIs24HourView(false);
 
@@ -198,8 +235,9 @@
         assertEquals(23, mTimePicker.getHour());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessIs24HourView() {
-        mTimePicker = new TimePicker(mContext);
         assertFalse(mTimePicker.is24HourView());
 
         mTimePicker.setIs24HourView(true);
@@ -209,9 +247,9 @@
         assertFalse(mTimePicker.is24HourView());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessCurrentMinute() {
-        mTimePicker = new TimePicker(mContext);
-
         mTimePicker.setCurrentMinute(0);
         assertEquals(Integer.valueOf(0), mTimePicker.getCurrentMinute());
 
@@ -225,9 +263,9 @@
         assertEquals(Integer.valueOf(59), mTimePicker.getCurrentMinute());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessMinute() {
-        mTimePicker = new TimePicker(mContext);
-
         mTimePicker.setMinute(0);
         assertEquals(0, mTimePicker.getMinute());
 
@@ -241,14 +279,15 @@
         assertEquals(59, mTimePicker.getMinute());
     }
 
+    @Test
     public void testGetBaseline() {
-        mTimePicker = new TimePicker(mContext);
         assertEquals(-1, mTimePicker.getBaseline());
     }
 
+    @Test
     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 +300,484 @@
         assertEquals(Integer.valueOf(expectMinute), dest.getCurrentMinute());
     }
 
-    private class MockOnTimeChangeListener implements OnTimeChangedListener {
-        private TimePicker mNotifiedView;
+    @Test
+    public void testKeyboardTabTraversalModeClock() throws Throwable {
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_clock);
 
-        private boolean mHasCalledOnTimeChanged;
+        mActivityRule.runOnUiThread(() -> mTimePicker.setIs24HourView(false));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                false /* is24HourView */,
+                false /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                false /* is24HourView */,
+                false /* isSpinner */);
 
-        private int mNotifiedHourOfDay;
+        mActivityRule.runOnUiThread(() -> mTimePicker.setIs24HourView(true));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                true /* is24HourView */,
+                false /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                true /* is24HourView */,
+                false /* isSpinner */);
+    }
 
-        private int mNotifiedMinute;;
+    @Test
+    public void testKeyboardTabTraversalModeSpinner() throws Throwable {
+        mTimePicker = (TimePicker) mActivity.findViewById(R.id.timepicker_spinner);
 
-        public boolean hasCalledOnTimeChanged() {
-            return mHasCalledOnTimeChanged;
+        mActivityRule.runOnUiThread(() -> mTimePicker.setIs24HourView(false));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                false /* is24HourView */,
+                true /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                false /* is24HourView */,
+                true /* isSpinner */);
+
+        mActivityRule.runOnUiThread(() -> mTimePicker.setIs24HourView(true));
+        mInstrumentation.waitForIdleSync();
+        verifyTimePickerKeyboardTraversal(
+                true /* goForward */,
+                true /* is24HourView */,
+                true /* isSpinner */);
+        verifyTimePickerKeyboardTraversal(
+                false /* goForward */,
+                true /* is24HourView */,
+                true /* isSpinner */);
+    }
+
+    @Test
+    public void testKeyboardInputModeClockAmPm() throws Throwable {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, false /* is24hFormat */,
+                true /* isClockMode */);
+
+        // 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.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        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();
+    }
+
+    @Test
+    public void testKeyboardInputModeClock24H() throws Throwable {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, true /* is24hFormat */,
+                true /* isClockMode */);
+
+        // 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();
+    }
+
+    @Test
+    public void testKeyboardInputModeSpinnerAmPm() throws Throwable {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, false /* is24hFormat */,
+                false /* isClockMode */);
+
+        assertEquals(initialHour, mTimePicker.getHour());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getHourView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+
+        // Input invalid hour.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        // None of the keys below should be accepted after 1 was pressed.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        // Since only 0, 1 or 2 are accepted for AM/PM hour mode after pressing 1, we expect the
+        // hour value to be 1.
+        assertEquals(1, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        //  Go back to hour view and input valid hour.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_1);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(11, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // Go back to hour view and exercise UP and DOWN keys.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(12, mTimePicker.getHour());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(10, mTimePicker.getHour());
+
+        // Minute input testing.
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        verifyModeSpinnerMinuteInput();
+
+        // Reset to values preparing to test the AM/PM picker.
+        mActivityRule.runOnUiThread(() -> {
+            mTimePicker.setHour(6);
+            mTimePicker.setMinute(initialMinute);
+        });
+        mInstrumentation.waitForIdleSync();
+        // In spinner mode the AM view and PM view are the same.
+        assertEquals(mTimePicker.getAmView(), mTimePicker.getPmView());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getAmView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTimePicker.getAmView().hasFocus());
+        assertEquals(6, mTimePicker.getHour());
+        // Pressing A changes nothing.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_A);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(6, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        // Pressing P switches to PM.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_P);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(18, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        // Pressing P again changes nothing.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_P);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(18, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        // Pressing A switches to AM.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_A);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(6, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        // Given that we are already set to AM, pressing UP changes nothing.
+        mActivityRule.runOnUiThread(() -> mTimePicker.getAmView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(6, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getAmView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        // Pressing down switches to PM.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(18, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getAmView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        // Given that we are set to PM, pressing DOWN again changes nothing.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(18, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getAmView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        // Pressing UP switches to AM.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(6, mTimePicker.getHour());
+        assertEquals(initialMinute, mTimePicker.getMinute());
+    }
+
+    @Test
+    public void testKeyboardInputModeSpinner24H() throws Throwable {
+        final int initialHour = 6;
+        final int initialMinute = 59;
+        prepareForKeyboardInput(initialHour, initialMinute, true /* is24hFormat */,
+                false /* isClockMode */);
+
+        assertEquals(initialHour, mTimePicker.getHour());
+        mActivityRule.runOnUiThread(() -> mTimePicker.getHourView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+
+        // Input invalid hour.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_2);
+        // None of the keys below should be accepted after 2 was pressed.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_6);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        // Only 2 is accepted (as the only 0, 1, 2, and 3 can form valid hours after pressing 2).
+        assertEquals(2, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        //  Go back to hour view and input valid hour.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_2);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(23, mTimePicker.getHour());
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // Go back to hour view and exercise UP and DOWN keys.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getHourView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(0 /* 24 */, mTimePicker.getHour());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(22, mTimePicker.getHour());
+
+        // Minute input testing.
+        assertEquals(initialMinute, mTimePicker.getMinute());
+        verifyModeSpinnerMinuteInput();
+    }
+
+    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 verifyModeSpinnerMinuteInput() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTimePicker.getMinuteView().requestFocus());
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+
+        // Input invalid minute.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_6);
+        // None of the keys below should be accepted after 6 was pressed.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_3);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_5);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        // Only 6 is accepted (as the only valid minute value that starts with 6 is 6 itself).
+        assertEquals(6, mTimePicker.getMinute());
+
+        // Go back to minute view and input valid minute.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_4);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_8);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_TAB);
+        assertEquals(48, mTimePicker.getMinute());
+
+        // Go back to minute view and exercise UP and DOWN keys.
+        CtsKeyEventUtil.sendKeyWhileHoldingModifier(mInstrumentation, mTimePicker,
+                KeyEvent.KEYCODE_TAB, KeyEvent.KEYCODE_SHIFT_LEFT);
+        assertTrue(mTimePicker.getMinuteView().hasFocus());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(49, mTimePicker.getMinute());
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTimePicker, KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(47, mTimePicker.getMinute());
+    }
+
+    private void prepareForKeyboardInput(int initialHour, int initialMinute, boolean is24hFormat,
+            boolean isClockMode) throws Throwable {
+        mTimePicker = isClockMode
+                ? (TimePicker) mActivity.findViewById(R.id.timepicker_clock)
+                : (TimePicker) mActivity.findViewById(R.id.timepicker_spinner);
+
+        mActivityRule.runOnUiThread(() -> {
+            mTimePicker.setIs24HourView(is24hFormat);
+            mTimePicker.setHour(initialHour);
+            mTimePicker.setMinute(initialMinute);
+            mTimePicker.requestFocus();
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void verifyTimePickerKeyboardTraversal(boolean goForward, boolean is24HourView,
+            boolean isSpinner) throws Throwable {
+        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.
+                mActivityRule.runOnUiThread(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..f2426e8 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -16,16 +16,22 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-
-import android.app.Activity;
 import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
+import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -33,68 +39,60 @@
 import android.widget.ImageView;
 import android.widget.Toast;
 
-public class ToastTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ToastTest {
     private static final String TEST_TOAST_TEXT = "test toast";
     private static final long TIME_FOR_UI_OPERATION  = 1000L;
     private static final long TIME_OUT = 5000L;
     private Toast mToast;
-    private Activity mActivity;
+    private Context mContext;
     private Instrumentation mInstrumentation;
     private boolean mLayoutDone;
     private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener;
 
-    public ToastTest() {
-        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();
-        mInstrumentation = getInstrumentation();
-        mLayoutDone = false;
-        mLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
-            public void onGlobalLayout() {
-                mLayoutDone = true;
-            }
-        };
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = InstrumentationRegistry.getTargetContext();
+        mLayoutListener = () -> mLayoutDone = true;
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
-        new Toast(mActivity);
-
-        try {
-            new Toast(null);
-            fail("did not throw NullPointerException when context is null.");
-        } catch (NullPointerException e) {
-            // expected, test success
-        }
+        new Toast(mContext);
     }
 
-    private void assertShowToast(final View view) {
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return null != view.getParent();
-            }
-        }.run();
+    @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new Toast(null);
     }
 
-    private void assertShowAndHide(final View view) {
+    private static void assertShowToast(final View view) {
+        PollingCheck.waitFor(TIME_OUT, () -> null != view.getParent());
+    }
+
+    private static 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 {
+    private static void assertNotShowToast(final View view) {
         // sleep a while and then make sure do not show toast
-        Thread.sleep(TIME_FOR_UI_OPERATION);
+        SystemClock.sleep(TIME_FOR_UI_OPERATION);
         assertNull(view.getParent());
     }
 
@@ -104,25 +102,18 @@
     }
 
     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);
     }
 
-    private void makeToast() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast = Toast.makeText(mActivity, TEST_TOAST_TEXT, Toast.LENGTH_LONG);
-            }
-        });
+    private void makeToast() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> mToast = Toast.makeText(mContext, TEST_TOAST_TEXT, Toast.LENGTH_LONG));
         mInstrumentation.waitForIdleSync();
     }
 
-    public void testShow() {
+    @Test
+    public void testShow() throws Throwable {
         makeToast();
 
         final View view = mToast.getView();
@@ -131,11 +122,7 @@
         assertNull(view.getParent());
         assertEquals(View.VISIBLE, view.getVisibility());
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.show();
-            }
-        });
+        mActivityRule.runOnUiThread(mToast::show);
         mInstrumentation.waitForIdleSync();
 
         // view will be attached to screen when show it
@@ -144,63 +131,54 @@
     }
 
     @UiThreadTest
+    @Test(expected=RuntimeException.class)
     public void testShowFailure() {
-        Toast toast = new Toast(mActivity);
+        Toast toast = new Toast(mContext);
         // do not have any views.
         assertNull(toast.getView());
-        try {
-            toast.show();
-            fail("did not throw RuntimeException when did not set any views.");
-        } catch (RuntimeException e) {
-            // expected, test success.
-        }
+        toast.show();
     }
 
-    public void testCancel() throws InterruptedException {
+    @Test
+    public void testCancel() throws Throwable {
         makeToast();
 
         final View view = mToast.getView();
 
         // view has not been attached to screen yet
         assertNull(view.getParent());
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.show();
-                mToast.cancel();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.show();
+            mToast.cancel();
         });
         mInstrumentation.waitForIdleSync();
 
         assertNotShowToast(view);
     }
 
-    public void testAccessView() {
+    @Test
+    public void testAccessView() throws Throwable {
         makeToast();
         assertFalse(mToast.getView() instanceof ImageView);
 
-        final ImageView imageView = new ImageView(mActivity);
-        Drawable drawable = mActivity.getResources().getDrawable(R.drawable.pass);
+        final ImageView imageView = new ImageView(mContext);
+        Drawable drawable = mContext.getResources().getDrawable(R.drawable.pass);
         imageView.setImageDrawable(drawable);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setView(imageView);
-                mToast.show();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setView(imageView);
+            mToast.show();
         });
         mInstrumentation.waitForIdleSync();
         assertSame(imageView, mToast.getView());
         assertShowAndHide(imageView);
     }
 
-    public void testAccessDuration() {
+    @Test
+    public void testAccessDuration() throws Throwable {
         long start = SystemClock.uptimeMillis();
         makeToast();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.show();
-            }
-        });
+        mActivityRule.runOnUiThread(mToast::show);
         mInstrumentation.waitForIdleSync();
         assertEquals(Toast.LENGTH_LONG, mToast.getDuration());
 
@@ -209,11 +187,9 @@
         long longDuration = SystemClock.uptimeMillis() - start;
 
         start = SystemClock.uptimeMillis();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setDuration(Toast.LENGTH_SHORT);
-                mToast.show();
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setDuration(Toast.LENGTH_SHORT);
+            mToast.show();
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(Toast.LENGTH_SHORT, mToast.getDuration());
@@ -225,28 +201,27 @@
         assertTrue(longDuration > shortDuration);
     }
 
-    public void testAccessMargin() {
+    @Test
+    public void testAccessMargin() throws Throwable {
         makeToast();
         View view = mToast.getView();
         assertFalse(view.getLayoutParams() instanceof WindowManager.LayoutParams);
 
         final float horizontal1 = 1.0f;
         final float vertical1 = 1.0f;
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setMargin(horizontal1, vertical1);
-                mToast.show();
-                registerLayoutListener(mToast.getView());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setMargin(horizontal1, vertical1);
+            mToast.show();
+            registerLayoutListener(mToast.getView());
         });
         mInstrumentation.waitForIdleSync();
         assertShowToast(view);
 
-        assertEquals(horizontal1, mToast.getHorizontalMargin());
-        assertEquals(vertical1, mToast.getVerticalMargin());
+        assertEquals(horizontal1, mToast.getHorizontalMargin(), 0.0f);
+        assertEquals(vertical1, mToast.getVerticalMargin(), 0.0f);
         WindowManager.LayoutParams params1 = (WindowManager.LayoutParams) view.getLayoutParams();
-        assertEquals(horizontal1, params1.horizontalMargin);
-        assertEquals(vertical1, params1.verticalMargin);
+        assertEquals(horizontal1, params1.horizontalMargin, 0.0f);
+        assertEquals(vertical1, params1.verticalMargin, 0.0f);
         assertLayoutDone(view);
         int[] xy1 = new int[2];
         view.getLocationOnScreen(xy1);
@@ -254,21 +229,19 @@
 
         final float horizontal2 = 0.1f;
         final float vertical2 = 0.1f;
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setMargin(horizontal2, vertical2);
-                mToast.show();
-                registerLayoutListener(mToast.getView());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setMargin(horizontal2, vertical2);
+            mToast.show();
+            registerLayoutListener(mToast.getView());
         });
         mInstrumentation.waitForIdleSync();
         assertShowToast(view);
 
-        assertEquals(horizontal2, mToast.getHorizontalMargin());
-        assertEquals(vertical2, mToast.getVerticalMargin());
+        assertEquals(horizontal2, mToast.getHorizontalMargin(), 0.0f);
+        assertEquals(vertical2, mToast.getVerticalMargin(), 0.0f);
         WindowManager.LayoutParams params2 = (WindowManager.LayoutParams) view.getLayoutParams();
-        assertEquals(horizontal2, params2.horizontalMargin);
-        assertEquals(vertical2, params2.verticalMargin);
+        assertEquals(horizontal2, params2.horizontalMargin, 0.0f);
+        assertEquals(vertical2, params2.verticalMargin, 0.0f);
 
         assertLayoutDone(view);
         int[] xy2 = new int[2];
@@ -279,14 +252,13 @@
         assertTrue(xy1[1] < xy2[1]);
     }
 
-    public void testAccessGravity() {
+    @Test
+    public void testAccessGravity() throws Throwable {
         makeToast();
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setGravity(Gravity.CENTER, 0, 0);
-                mToast.show();
-                registerLayoutListener(mToast.getView());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setGravity(Gravity.CENTER, 0, 0);
+            mToast.show();
+            registerLayoutListener(mToast.getView());
         });
         mInstrumentation.waitForIdleSync();
         View view = mToast.getView();
@@ -299,12 +271,10 @@
         view.getLocationOnScreen(centerXY);
         assertShowAndHide(view);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setGravity(Gravity.BOTTOM, 0, 0);
-                mToast.show();
-                registerLayoutListener(mToast.getView());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setGravity(Gravity.BOTTOM, 0, 0);
+            mToast.show();
+            registerLayoutListener(mToast.getView());
         });
         mInstrumentation.waitForIdleSync();
         view = mToast.getView();
@@ -324,12 +294,10 @@
 
         final int xOffset = 20;
         final int yOffset = 10;
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mToast.setGravity(Gravity.BOTTOM, xOffset, yOffset);
-                mToast.show();
-                registerLayoutListener(mToast.getView());
-            }
+        mActivityRule.runOnUiThread(() -> {
+            mToast.setGravity(Gravity.BOTTOM, xOffset, yOffset);
+            mToast.show();
+            registerLayoutListener(mToast.getView());
         });
         mInstrumentation.waitForIdleSync();
         view = mToast.getView();
@@ -347,90 +315,92 @@
     }
 
     @UiThreadTest
-    public void testMakeText1() {
-        Toast toast = Toast.makeText(mActivity, "android", Toast.LENGTH_SHORT);
+    @Test
+    public void testMakeTextFromString() {
+        Toast toast = Toast.makeText(mContext, "android", Toast.LENGTH_SHORT);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
         View view = toast.getView();
         assertNotNull(view);
 
-        toast = Toast.makeText(mActivity, "cts", Toast.LENGTH_LONG);
+        toast = Toast.makeText(mContext, "cts", Toast.LENGTH_LONG);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         view = toast.getView();
         assertNotNull(view);
 
-        toast = Toast.makeText(mActivity, null, Toast.LENGTH_LONG);
+        toast = Toast.makeText(mContext, null, Toast.LENGTH_LONG);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         view = toast.getView();
         assertNotNull(view);
-
-        try {
-            toast = Toast.makeText(null, "test", Toast.LENGTH_LONG);
-            fail("did not throw NullPointerException when context is null.");
-        } catch (NullPointerException e) {
-            //expected, test success.
-        }
     }
 
     @UiThreadTest
-    public void testMakeText2() {
-        Toast toast = Toast.makeText(mActivity, R.string.hello_world, Toast.LENGTH_LONG);
+    @Test(expected=NullPointerException.class)
+    public void testMaketTextFromStringNullContext() {
+        Toast.makeText(null, "test", Toast.LENGTH_LONG);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testMakeTextFromResource() {
+        Toast toast = Toast.makeText(mContext, R.string.hello_world, Toast.LENGTH_LONG);
 
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_LONG, toast.getDuration());
         View view = toast.getView();
         assertNotNull(view);
 
-        toast = Toast.makeText(mActivity, R.string.hello_android, Toast.LENGTH_SHORT);
+        toast = Toast.makeText(mContext, R.string.hello_android, Toast.LENGTH_SHORT);
         assertNotNull(toast);
         assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
         view = toast.getView();
         assertNotNull(view);
-
-        try {
-            toast = Toast.makeText(null, R.string.hello_android, Toast.LENGTH_SHORT);
-            fail("did not throw NullPointerException when context is null.");
-        } catch (NullPointerException e) {
-            //expected, test success.
-        }
     }
 
     @UiThreadTest
-    public void testSetText1() {
-        Toast toast = Toast.makeText(mActivity, R.string.text, Toast.LENGTH_LONG);
+    @Test(expected=NullPointerException.class)
+    public void testMaketTextFromResourceNullContext() {
+        Toast.makeText(null, R.string.hello_android, Toast.LENGTH_SHORT);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetTextFromResource() {
+        Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
 
         toast.setText(R.string.hello_world);
         // TODO: how to getText to assert?
 
         toast.setText(R.string.hello_android);
         // TODO: how to getText to assert?
-
-        try {
-            toast.setText(-1);
-            fail("did not throw RuntimeException when resource id is negative.");
-        } catch (RuntimeException e) {
-            //expected, test success.
-        }
     }
 
     @UiThreadTest
-    public void testSetText2() {
-        Toast toast = Toast.makeText(mActivity, R.string.text, Toast.LENGTH_LONG);
+    @Test(expected=RuntimeException.class)
+    public void testSetTextFromInvalidResource() {
+        Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
+        toast.setText(-1);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetTextFromString() {
+        Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
 
         toast.setText("cts");
         // TODO: how to getText to assert?
 
         toast.setText("android");
         // TODO: how to getText to assert?
+    }
 
-        try {
-            toast.setView(null);
-            toast.setText(null);
-            fail("did not throw RuntimeException when view is null.");
-        } catch (RuntimeException e) {
-            //expected, test success.
-        }
+    @UiThreadTest
+    @Test(expected=RuntimeException.class)
+    public void testSetTextFromStringNullView() {
+        Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
+        toast.setView(null);
+        toast.setText(null);
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java
new file mode 100644
index 0000000..3640957
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ToggleButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os.Bundle;
+import android.widget.ToggleButton;
+
+/**
+ * A minimal application for {@link ToggleButton} test.
+ */
+public class ToggleButtonCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    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..a473983 100644
--- a/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToggleButtonTest.java
@@ -16,92 +16,121 @@
 
 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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
+import android.app.Activity;
 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.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
-import android.util.Xml;
 import android.widget.ToggleButton;
 
-import android.widget.cts.R;
-
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link ToggleButton}.
  */
-public class ToggleButtonTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ToggleButtonTest {
     private static final String TEXT_OFF = "text off";
     private static final String TEXT_ON = "text on";
-    ToggleButton mToggleButton;
-    Context mContext;
-    AttributeSet mAttrSet;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    private Activity mActivity;
 
-        mContext = getInstrumentation().getTargetContext();
-        XmlPullParser parser = mContext.getResources().getXml(R.layout.togglebutton_layout);
-        mAttrSet = Xml.asAttributeSet(parser);
-        mToggleButton = new ToggleButton(mContext, mAttrSet);
+    @Rule
+    public ActivityTestRule<ToggleButtonCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ToggleButtonCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
+    @Test
     public void testConstructor() {
-        new ToggleButton(mContext, mAttrSet, 0);
-        new ToggleButton(mContext, mAttrSet);
-        new ToggleButton(mContext);
-
-        try {
-            new ToggleButton(null, null, -1);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new ToggleButton(null, null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
-
-        try {
-            new ToggleButton(null);
-            fail("There should be a NullPointerException thrown out.");
-        } catch (NullPointerException e) {
-            // expected, test success.
-        }
+        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);
     }
 
-    public void testAccessTextOff() {
-        mToggleButton.setTextOff("android");
-        assertEquals("android", mToggleButton.getTextOff());
-        mToggleButton.setChecked(false);
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new ToggleButton(null);
+    }
 
-        mToggleButton.setTextOff(null);
-        assertNull(mToggleButton.getTextOff());
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new ToggleButton(null, null);
+    }
 
-        mToggleButton.setTextOff("");
-        assertEquals("", mToggleButton.getTextOff());
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new ToggleButton(null, null, -1);
+    }
+
+    @Test
+    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());
+    }
+
+    @Test
+    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());
     }
 
     @UiThreadTest
+    @Test
+    public void testAccessTextOff() {
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        toggleButton.setTextOff("android");
+        assertEquals("android", toggleButton.getTextOff());
+        toggleButton.setChecked(false);
+
+        toggleButton.setTextOff(null);
+        assertNull(toggleButton.getTextOff());
+
+        toggleButton.setTextOff("");
+        assertEquals("", toggleButton.getTextOff());
+    }
+
+    @UiThreadTest
+    @Test
     public void testDrawableStateChanged() {
-        MockToggleButton toggleButton = new MockToggleButton(mContext);
+        final MockToggleButton toggleButton =
+                (MockToggleButton) mActivity.findViewById(R.id.toggle_custom);
 
         // drawableStateChanged without any drawable.
         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);
@@ -113,80 +142,97 @@
         assertEquals(toggleButton.getDrawableState(), drawable.getState());
     }
 
+    @UiThreadTest
+    @Test
     public void testOnFinishInflate() {
-        MockToggleButton toggleButton = new MockToggleButton(mContext);
+        final MockToggleButton toggleButton =
+                (MockToggleButton) mActivity.findViewById(R.id.toggle_custom);
         toggleButton.onFinishInflate();
     }
 
     @UiThreadTest
+    @Test
     public void testSetChecked() {
-        assertFalse(mToggleButton.isChecked());
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        assertFalse(toggleButton.isChecked());
 
-        mToggleButton.setChecked(true);
-        assertTrue(mToggleButton.isChecked());
+        toggleButton.setChecked(true);
+        assertTrue(toggleButton.isChecked());
 
-        mToggleButton.setChecked(false);
-        assertFalse(mToggleButton.isChecked());
+        toggleButton.setChecked(false);
+        assertFalse(toggleButton.isChecked());
     }
 
     @UiThreadTest
+    @Test
     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);
+        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());
+        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());
+        toggleButton.setTextOn(TEXT_ON);
+        toggleButton.setChecked(true);
+        toggleButton.setTextOff(null);
+        toggleButton.setChecked(false);
+        assertEquals(TEXT_ON, toggleButton.getText().toString());
     }
 
+    @UiThreadTest
+    @Test
     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());
+        toggleButton.setBackgroundDrawable(drawable);
+        assertSame(drawable, toggleButton.getBackground());
 
         // remove the background
-        mToggleButton.setBackgroundDrawable(null);
-        assertNull(mToggleButton.getBackground());
+        toggleButton.setBackgroundDrawable(null);
+        assertNull(toggleButton.getBackground());
     }
 
+    @UiThreadTest
+    @Test
     public void testAccessTextOn() {
-        mToggleButton.setTextOn("cts");
-        assertEquals("cts", mToggleButton.getTextOn());
+        final ToggleButton toggleButton = (ToggleButton) mActivity.findViewById(R.id.toggle1);
+        toggleButton.setTextOn("cts");
+        assertEquals("cts", toggleButton.getTextOn());
 
-        mToggleButton.setTextOn(null);
-        assertNull(mToggleButton.getTextOn());
+        toggleButton.setTextOn(null);
+        assertNull(toggleButton.getTextOn());
 
-        mToggleButton.setTextOn("");
-        assertEquals("", mToggleButton.getTextOn());
+        toggleButton.setTextOn("");
+        assertEquals("", toggleButton.getTextOn());
     }
 
     /**
      * MockToggleButton class for testing.
      */
-    private static final class MockToggleButton extends ToggleButton {
+    public static final class MockToggleButton extends ToggleButton {
         public MockToggleButton(Context context) {
             super(context);
         }
 
+        public MockToggleButton(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         @Override
         protected void drawableStateChanged() {
             super.drawableStateChanged();
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
index 7f9690c..f341d8b 100644
--- a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -16,40 +16,56 @@
 
 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.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.verifyNoMoreInteractions;
+
 import android.app.Instrumentation;
-import android.content.Context;
-import android.content.res.TypedArray;
 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.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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.*;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
-public class ToolbarTest extends ActivityInstrumentationTestCase2<ToolbarCtsActivity> {
-    private Toolbar mMainToolbar;
+@RunWith(AndroidJUnit4.class)
+public class ToolbarTest {
+    private Instrumentation mInstrumentation;
     private ToolbarCtsActivity mActivity;
+    private Toolbar mMainToolbar;
 
-    public ToolbarTest() {
-        super("android.widget.cts", ToolbarCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ToolbarCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ToolbarCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
         mMainToolbar = mActivity.getMainToolbar();
     }
 
+    @Test
     public void testConstructor() {
         new Toolbar(mActivity);
 
@@ -60,57 +76,56 @@
         new Toolbar(mActivity, null, 0, android.R.style.Widget_Material_Toolbar);
     }
 
-    public void testTitleAndSubtitleContent() {
+    @Test
+    public void testTitleAndSubtitleContent() throws Throwable {
         // Note that this method is *not* annotated to run on the UI thread, and every
         // call to setTitle / setSubtitle is wrapped to wait until the next draw pass
         // of our main toolbar. While this is not strictly necessary to check the result
         // 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(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setTitle(R.string.toolbar_title));
         assertEquals(mActivity.getString(R.string.toolbar_title), mMainToolbar.getTitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setTitle("New title"));
         assertEquals("New title", mMainToolbar.getTitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
         assertEquals(mActivity.getString(R.string.toolbar_subtitle), mMainToolbar.getSubtitle());
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setSubtitle("New subtitle"));
         assertEquals("New subtitle", mMainToolbar.getSubtitle());
     }
 
-    public void testTitleAndSubtitleAppearance() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+    @Test
+    public void testTitleAndSubtitleAppearance() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setTitle(R.string.toolbar_title));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setTitleTextColor(Color.RED));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setSubtitleTextColor(Color.BLUE));
 
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setTitleTextAppearance(
                         mActivity, R.style.TextAppearance_NotColors));
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.setSubtitleTextAppearance(
                         mActivity, R.style.TextAppearance_WithColor));
     }
 
     @UiThreadTest
+    @Test
     public void testGetTitleMargins() {
         assertEquals(5, mMainToolbar.getTitleMarginStart());
         assertEquals(10, mMainToolbar.getTitleMarginTop());
@@ -119,6 +134,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetTitleMargins() {
         Toolbar toolbar = (Toolbar) mActivity.findViewById(R.id.toolbar2);
 
@@ -138,10 +154,9 @@
         assertEquals(40, toolbar.getTitleMarginBottom());
     }
 
-    public void testMenuContent() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+    @Test
+    public void testMenuContent() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
 
         final Menu menu = mMainToolbar.getMenu();
@@ -169,35 +184,33 @@
                 menu.findItem(R.id.action_share));
     }
 
-    public void testMenuOverflowShowHide() {
-        final Instrumentation instrumentation = getInstrumentation();
-
+    @Test
+    public void testMenuOverflowShowHide() throws Throwable {
         // Inflate menu and check that we're not showing overflow menu yet
-        instrumentation.runOnMainSync(() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(() -> mMainToolbar.hideOverflowMenu());
+        mInstrumentation.waitForIdleSync();
         assertFalse(mMainToolbar.isOverflowMenuShowing());
     }
 
-    public void testMenuOverflowSubmenu() {
-        final Instrumentation instrumentation = getInstrumentation();
-
+    @Test
+    public void testMenuOverflowSubmenu() throws Throwable {
         // Inflate menu and check that we're not showing overflow menu yet
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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();
+        mActivityRule.runOnUiThread(mMainToolbar::showOverflowMenu);
+        mInstrumentation.waitForIdleSync();
         assertTrue(mMainToolbar.isOverflowMenuShowing());
 
         // Register a mock menu item click listener on the toolbar
@@ -209,129 +222,126 @@
 
         // 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));
+        mActivityRule.runOnUiThread(() -> 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();
+        mActivityRule.runOnUiThread(mMainToolbar::dismissPopupMenus);
+        mInstrumentation.waitForIdleSync();
         assertFalse(mMainToolbar.isOverflowMenuShowing());
     }
 
-    public void testMenuOverflowIcon() {
-        final Instrumentation instrumentation = getInstrumentation();
-
+    @Test
+    public void testMenuOverflowIcon() throws Throwable {
         // Inflate menu and check that we're not showing overflow menu yet
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mMainToolbar,
                 () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
 
         final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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();
-
+    @Test
+    public void testActionView() throws Throwable {
         // Inflate menu and check that we don't have an expanded action view
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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();
+        mActivityRule.runOnUiThread(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();
+        mActivityRule.runOnUiThread(searchMenuItem::collapseActionView);
+        mInstrumentation.waitForIdleSync();
         assertFalse(searchMenuItem.isActionViewExpanded());
         assertFalse(mMainToolbar.hasExpandedActionView());
 
         // Expand search menu item's action view again
-        instrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
-        instrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(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();
+        mActivityRule.runOnUiThread(mMainToolbar::collapseActionView);
+        mInstrumentation.waitForIdleSync();
         assertFalse(searchMenuItem.isActionViewExpanded());
         assertFalse(mMainToolbar.hasExpandedActionView());
     }
 
-    public void testNavigationConfiguration() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+    @Test
+    public void testNavigationConfiguration() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(
+        mActivityRule.runOnUiThread(
                 () -> mMainToolbar.setNavigationContentDescription(R.string.toolbar_navigation));
         assertEquals(mActivity.getResources().getString(R.string.toolbar_navigation),
                 mMainToolbar.getNavigationContentDescription());
 
-        instrumentation.runOnMainSync(
+        mActivityRule.runOnUiThread(
                 () -> mMainToolbar.setNavigationContentDescription("Navigation legend"));
         assertEquals("Navigation legend", mMainToolbar.getNavigationContentDescription());
     }
 
-    public void testLogoConfiguration() {
-        final Instrumentation instrumentation = getInstrumentation();
-
-        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+    @Test
+    public void testLogoConfiguration() throws Throwable {
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, 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(mActivityRule, 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(
+        mActivityRule.runOnUiThread(
                 () -> mMainToolbar.setLogoDescription(R.string.toolbar_logo));
         assertEquals(mActivity.getResources().getString(R.string.toolbar_logo),
                 mMainToolbar.getLogoDescription());
 
-        instrumentation.runOnMainSync(
+        mActivityRule.runOnUiThread(
                 () -> mMainToolbar.setLogoDescription("Logo legend"));
         assertEquals("Logo legend", mMainToolbar.getLogoDescription());
     }
 
     @UiThreadTest
+    @Test
     public void testContentInsetsLtr() {
         mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
 
@@ -349,6 +359,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testContentInsetsRtl() {
         mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
 
@@ -365,19 +376,126 @@
         assertEquals(20, mMainToolbar.getContentInsetEnd());
     }
 
+    @Test
+    public void testCurrentContentInsetsLtr() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+
+        mActivityRule.runOnUiThread(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+        assertEquals(20, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mActivityRule.runOnUiThread(() -> 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(mActivityRule, 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());
+
+        mActivityRule.runOnUiThread(() -> 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(mActivityRule, 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());
+    }
+
+    @Test
+    public void testCurrentContentInsetsRtl() throws Throwable {
+        mActivityRule.runOnUiThread(
+                () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
+
+        mActivityRule.runOnUiThread(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+        assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+        assertEquals(20, mMainToolbar.getCurrentContentInsetRight());
+        assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+        mActivityRule.runOnUiThread(() -> 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(mActivityRule, 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());
+
+        mActivityRule.runOnUiThread(() -> 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(mActivityRule, 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
+    @Test
     public void testPopupTheme() {
         mMainToolbar.setPopupTheme(R.style.ToolbarPopupTheme_Test);
         assertEquals(R.style.ToolbarPopupTheme_Test, mMainToolbar.getPopupTheme());
     }
 
+    @UiThreadTest
+    @Test
     public void testNavigationOnClickListener() {
         View.OnClickListener mockListener = mock(View.OnClickListener.class);
         mMainToolbar.setNavigationOnClickListener(mockListener);
 
         verify(mockListener, never()).onClick(any(View.class));
 
-        getInstrumentation().runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
+        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..f931a63 100644
--- a/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TwoLineListItemTest.java
@@ -16,65 +16,77 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Resources;
-import android.test.ActivityInstrumentationTestCase;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
+import android.widget.RelativeLayout.LayoutParams;
 import android.widget.TextView;
 import android.widget.TwoLineListItem;
-import android.widget.RelativeLayout.LayoutParams;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link TwoLineListItem}.
  */
-public class TwoLineListItemTest extends
-        ActivityInstrumentationTestCase<TwoLineListItemCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TwoLineListItemTest {
     private Activity mActivity;
 
-    public TwoLineListItemTest() {
-        super("android.widget.cts", TwoLineListItemCtsActivity.class);
+    @Rule
+    public ActivityTestRule<TwoLineListItemCtsActivity> mActivityRule =
+            new ActivityTestRule<>(TwoLineListItemCtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
+    @Test
     public void testConstructor() {
         AttributeSet attrs = mActivity.getResources().getLayout(R.layout.twolinelistitem);
         assertNotNull(attrs);
 
         new TwoLineListItem(mActivity);
-        try {
-            new TwoLineListItem(null);
-            fail("The constructor should throw NullPointerException when param Context is null.");
-        } catch (NullPointerException e) {
-        }
-
         new TwoLineListItem(mActivity, attrs);
-        try {
-            new TwoLineListItem(null, attrs);
-            fail("The constructor should throw NullPointerException when param Context is null.");
-        } catch (NullPointerException e) {
-        }
         new TwoLineListItem(mActivity, null);
-
         new TwoLineListItem(mActivity, attrs, 0);
-        try {
-            new TwoLineListItem(null, attrs, 0);
-            fail("The constructor should throw NullPointerException when param Context is null.");
-        } catch (NullPointerException e) {
-        }
         new TwoLineListItem(mActivity, null, 0);
         new TwoLineListItem(mActivity, attrs, Integer.MAX_VALUE);
         new TwoLineListItem(mActivity, attrs, Integer.MIN_VALUE);
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new TwoLineListItem(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        AttributeSet attrs = mActivity.getResources().getLayout(R.layout.twolinelistitem);
+        new TwoLineListItem(null, attrs);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        AttributeSet attrs = mActivity.getResources().getLayout(R.layout.twolinelistitem);
+        new TwoLineListItem(null, attrs, 0);
+    }
+
+    @Test
     public void testGetTexts() {
         TwoLineListItem twoLineListItem =
             (TwoLineListItem) mActivity.findViewById(R.id.twoLineListItem);
@@ -88,6 +100,8 @@
                 twoLineListItem.getText2().getText().toString());
     }
 
+    @UiThreadTest
+    @Test
     public void testOnFinishInflate() {
         MockTwoLineListItem twoLineListItem = new MockTwoLineListItem(mActivity);
         TextView text1 = new TextView(mActivity);
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..78eebf4 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
@@ -16,26 +16,40 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
+import static com.android.compatibility.common.util.CtsMockitoUtils.within;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 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.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.view.View.MeasureSpec;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import com.android.compatibility.common.util.MediaUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -43,7 +57,9 @@
 /**
  * Test {@link VideoView}.
  */
-public class VideoViewTest extends ActivityInstrumentationTestCase2<VideoViewCtsActivity> {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class VideoViewTest {
     /** Debug TAG. **/
     private static final String TAG = "VideoViewTest";
     /** The maximum time to wait for an operation. */
@@ -58,122 +74,51 @@
         hardware that report a duration that's different by a few milliseconds */
     private static final int DURATION_DELTA = 100;
 
-    private VideoView mVideoView;
-    private Activity mActivity;
     private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private VideoView mVideoView;
     private String mVideoPath;
 
-    private static class MockListener {
-        private boolean mTriggered;
+    @Rule
+    public ActivityTestRule<VideoViewCtsActivity> mActivityRule =
+            new ActivityTestRule<>(VideoViewCtsActivity.class);
 
-        MockListener() {
-            mTriggered = false;
-        }
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mVideoView = (VideoView) mActivity.findViewById(R.id.videoview);
 
-        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();
-        }
+        mVideoPath = prepareSampleVideo();
+        assertNotNull(mVideoPath);
     }
 
     private boolean hasCodec() {
         return MediaUtils.hasCodecsForResource(mActivity, R.raw.testvideo);
     }
 
-    /**
-     * Instantiates a new video view test.
-     */
-    public VideoViewTest() {
-        super("android.widget.cts", VideoViewCtsActivity.class);
-    }
-
-    /**
-     * Find the video view specified by id.
-     *
-     * @param id the id
-     * @return the video view
-     */
-    private VideoView findVideoViewById(int id) {
-        return (VideoView) mActivity.findViewById(id);
-    }
-
     private String prepareSampleVideo() throws IOException {
-        InputStream source = null;
-        OutputStream target = null;
-
-        try {
-            source = mActivity.getResources().openRawResource(R.raw.testvideo);
-            target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE);
-
+        try (InputStream source = mActivity.getResources().openRawResource(R.raw.testvideo);
+             OutputStream target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE)) {
             final byte[] buffer = new byte[1024];
             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
                 target.write(buffer, 0, len);
             }
-        } finally {
-            if (source != null) {
-                source.close();
-            }
-            if (target != null) {
-                target.close();
-            }
         }
 
         return mActivity.getFileStreamPath(VIDEO_NAME).getAbsolutePath();
     }
 
-    /**
-     * Wait for an asynchronous media operation complete.
-     * @throws InterruptedException
-     */
-    private void waitForOperationComplete() throws InterruptedException {
-        Thread.sleep(OPERATION_INTERVAL);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mVideoPath = prepareSampleVideo();
-        assertNotNull(mVideoPath);
-        mVideoView = findVideoViewById(R.id.videoview);
-    }
-
-    private void makeVideoView() {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                MediaController mediaController = new MediaController(mActivity);
-                mVideoView.setMediaController(mediaController);
-            }
+    private void makeVideoView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            MediaController mediaController = new MediaController(mActivity);
+            mVideoView.setMediaController(mediaController);
         });
         mInstrumentation.waitForIdleSync();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new VideoView(mActivity);
 
@@ -182,7 +127,8 @@
         new VideoView(mActivity, null, 0);
     }
 
-    public void testPlayVideo1() throws Throwable {
+    @Test
+    public void testPlayVideo() throws Throwable {
         makeVideoView();
         // Don't run the test if the codec isn't supported.
         if (!hasCodec()) {
@@ -190,60 +136,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);
+        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);
+        mVideoView.setOnCompletionListener(mockCompletionListener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.start();
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
+        verify(mockPreparedListener, within(TIME_OUT)).onPrepared(any(MediaPlayer.class));
+        verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class));
+        verifyZeroInteractions(mockCompletionListener);
+
+        mActivityRule.runOnUiThread(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();
+        verify(mockCompletionListener, within(TIME_OUT)).onCompletion(any(MediaPlayer.class));
+        verify(mockCompletionListener, times(1)).onCompletion(any(MediaPlayer.class));
     }
 
+    @Test
     public void testSetOnErrorListener() throws Throwable {
         makeVideoView();
-        final MockOnErrorListener listener = new MockOnErrorListener();
-        mVideoView.setOnErrorListener(listener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                String path = "unknown path";
-                mVideoView.setVideoPath(path);
-                mVideoView.start();
-            }
+        final MediaPlayer.OnErrorListener mockErrorListener =
+                mock(MediaPlayer.OnErrorListener.class);
+        mVideoView.setOnErrorListener(mockErrorListener);
+
+        mActivityRule.runOnUiThread(() -> {
+            String path = "unknown path";
+            mVideoView.setVideoPath(path);
+            mVideoView.start();
         });
         mInstrumentation.waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return listener.isTriggered();
-            }
-        }.run();
+        verify(mockErrorListener, within(TIME_OUT)).onError(
+                any(MediaPlayer.class), anyInt(), anyInt());
+        verify(mockErrorListener, times(1)).onError(any(MediaPlayer.class), anyInt(), anyInt());
     }
 
+    @Test
     public void testGetBufferPercentage() throws Throwable {
         makeVideoView();
         // Don't run the test if the codec isn't supported.
@@ -252,27 +184,21 @@
             return;
         }
 
-        final MockOnPreparedListener prepareListener = new MockOnPreparedListener();
-        mVideoView.setOnPreparedListener(prepareListener);
+        final MediaPlayer.OnPreparedListener mockPreparedListener =
+                mock(MediaPlayer.OnPreparedListener.class);
+        mVideoView.setOnPreparedListener(mockPreparedListener);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.setVideoPath(mVideoPath);
-            }
-        });
+        mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
         mInstrumentation.waitForIdleSync();
 
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return prepareListener.isTriggered();
-            }
-        }.run();
+        verify(mockPreparedListener, within(TIME_OUT)).onPrepared(any(MediaPlayer.class));
+        verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class));
         int percent = mVideoView.getBufferPercentage();
         assertTrue(percent >= 0 && percent <= 100);
     }
 
     @UiThreadTest
+    @Test
     public void testResolveAdjustedSize() {
         mVideoView = new VideoView(mActivity);
 
@@ -288,6 +214,7 @@
         assertEquals(specSize, resolvedSize);
     }
 
+    @Test
     public void testGetDuration() throws Throwable {
         // Don't run the test if the codec isn't supported.
         if (!hasCodec()) {
@@ -295,16 +222,13 @@
             return;
         }
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mVideoView.setVideoPath(mVideoPath);
-            }
-        });
-        waitForOperationComplete();
+        mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath));
+        SystemClock.sleep(OPERATION_INTERVAL);
         assertTrue(Math.abs(mVideoView.getDuration() - TEST_VIDEO_DURATION) < DURATION_DELTA);
     }
 
     @UiThreadTest
+    @Test
     public void testSetMediaController() {
         final MediaController ctlr = new MediaController(mActivity);
         mVideoView.setMediaController(ctlr);
diff --git a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
index 696761b..7710dcc 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewAnimatorTest.java
@@ -16,15 +16,16 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -35,38 +36,39 @@
 import android.widget.RelativeLayout;
 import android.widget.ViewAnimator;
 
-public class ViewAnimatorTest extends
-        ActivityInstrumentationTestCase2<ViewAnimatorCtsActivity> {
-    private ViewAnimator mViewAnimator;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewAnimatorTest {
     private Activity mActivity;
-    private Instrumentation mInstrumentation;
+    private ViewAnimator mViewAnimator;
     private AttributeSet mAttributeSet;
 
-    public ViewAnimatorTest() {
-        super("android.widget.cts", ViewAnimatorCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewAnimatorCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewAnimatorCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
 
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.viewanimator_layout);
         mAttributeSet = Xml.asAttributeSet(parser);
         mViewAnimator = new ViewAnimator(mActivity, mAttributeSet);
-
-        assertNotNull(mActivity);
-        assertNotNull(mInstrumentation);
-        assertNotNull(mViewAnimator);
     }
 
+    @Test
     public void testConstructor() {
         new ViewAnimator(mActivity);
         new ViewAnimator(mActivity, mAttributeSet);
     }
 
+    @Test
     public void testAccessInAnimation() {
         AnimationSet expected = new AnimationSet(mActivity, mAttributeSet);
         assertNull(mViewAnimator.getInAnimation());
@@ -85,6 +87,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testShowNext() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -122,6 +125,7 @@
         assertEquals(0, mViewAnimator.getChildCount());
     }
 
+    @Test
     public void testSetAnimateFirstView() {
         mViewAnimator.setAnimateFirstView(true);
         mViewAnimator.setAnimateFirstView(false);
@@ -130,6 +134,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessDisplayedChild() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -164,6 +169,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAccessDisplayedChildBoundary() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -192,6 +198,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetBaseline() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -218,6 +225,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testShowPrevious() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -257,6 +265,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testGetCurrentView() {
         final View v = mActivity.findViewById(R.id.label);
         final RelativeLayout parent = (RelativeLayout) v.getParent();
@@ -276,6 +285,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testAddView() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
@@ -299,6 +309,7 @@
         assertEquals(0, mViewAnimator.getChildCount());
     }
 
+    @Test
     public void testAccessOutAnimation() {
         AnimationSet expected = new AnimationSet(mActivity, mAttributeSet);
         assertNull(mViewAnimator.getOutAnimation());
@@ -316,6 +327,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testRemoveViews() {
         final View v1 = mActivity.findViewById(R.id.ok);
         final View v2 = mActivity.findViewById(R.id.cancel);
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..b135745 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewFlipperTest.java
@@ -16,37 +16,53 @@
 
 package android.widget.cts;
 
-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.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
 import android.widget.TextView;
 import android.widget.ViewFlipper;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * Test {@link ViewFlipper}.
  */
-public class ViewFlipperTest extends ActivityInstrumentationTestCase<ViewFlipperCtsActivity> {
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewFlipperTest {
+    private Instrumentation mInstrumentation;
     private Activity mActivity;
 
-    public ViewFlipperTest() {
-        super("android.widget.cts", ViewFlipperCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ViewFlipperCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ViewFlipperCtsActivity.class);
 
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        assertNotNull(mActivity);
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new ViewFlipper(mActivity);
 
@@ -55,87 +71,75 @@
         XmlPullParser parser = mActivity.getResources().getXml(R.layout.viewflipper_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
         new ViewFlipper(mActivity, attrs);
-
-        try {
-            new ViewFlipper(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
     @UiThreadTest
+    @Test(expected=NullPointerException.class)
+    public void testConstructorNullContext() {
+        new ViewFlipper(null, null);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetFlipInterval() {
         ViewFlipper viewFlipper = new ViewFlipper(mActivity);
         viewFlipper.setFlipInterval(0);
         viewFlipper.setFlipInterval(-1);
     }
 
+    @LargeTest
+    @Test
     public void testViewFlipper() throws Throwable {
-        // NOTE: This value needs to be kept in sync with the value set in
-        // layout/viewflipper_layout.xml
-        final int FLIP_INTERVAL = 1000;
+        final int flipInterval = mActivity.getResources().getInteger(
+                R.integer.view_flipper_interval);
 
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ViewFlipper viewFlipper =
-                        (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
+        mActivityRule.runOnUiThread(() -> {
+            ViewFlipper viewFlipper =
+                    (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
 
-                TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
-                TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
+            TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
+            TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
 
-                assertFalse(viewFlipper.isFlipping());
-                assertSame(iv1, viewFlipper.getCurrentView());
+            assertFalse(viewFlipper.isFlipping());
+            assertSame(iv1, viewFlipper.getCurrentView());
 
-                viewFlipper.startFlipping();
-                assertTrue(viewFlipper.isFlipping());
-                assertSame(iv1, viewFlipper.getCurrentView());
-                assertEquals(View.VISIBLE, iv1.getVisibility());
-                assertEquals(View.GONE, iv2.getVisibility());
-            }
+            viewFlipper.startFlipping();
+            assertTrue(viewFlipper.isFlipping());
+            assertSame(iv1, viewFlipper.getCurrentView());
+            assertEquals(View.VISIBLE, iv1.getVisibility());
+            assertEquals(View.GONE, iv2.getVisibility());
         });
 
         // wait for a longer time to make sure the view flipping is completed.
-        waitForViewFlipping(FLIP_INTERVAL + 200);
-        getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ViewFlipper viewFlipper =
-                        (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
+        SystemClock.sleep(flipInterval + 200);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> {
+            ViewFlipper viewFlipper =
+                    (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
 
-                TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
-                TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
+            TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
+            TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
 
-                assertSame(iv2, viewFlipper.getCurrentView());
-                assertEquals(View.GONE, iv1.getVisibility());
-                assertEquals(View.VISIBLE, iv2.getVisibility());
-            }
+            assertSame(iv2, viewFlipper.getCurrentView());
+            assertEquals(View.GONE, iv1.getVisibility());
+            assertEquals(View.VISIBLE, iv2.getVisibility());
         });
 
-        waitForViewFlipping(FLIP_INTERVAL + 200);
-        getInstrumentation().waitForIdleSync();
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                ViewFlipper viewFlipper =
-                        (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
+        SystemClock.sleep(flipInterval + 200);
+        mInstrumentation.waitForIdleSync();
+        mActivityRule.runOnUiThread(() -> {
+            ViewFlipper viewFlipper =
+                    (ViewFlipper) mActivity.findViewById(R.id.viewflipper_test);
 
-                TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
-                TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
+            TextView iv1 = (TextView) mActivity.findViewById(R.id.viewflipper_textview1);
+            TextView iv2 = (TextView) mActivity.findViewById(R.id.viewflipper_textview2);
 
-                assertSame(iv1, viewFlipper.getCurrentView());
-                assertEquals(View.VISIBLE, iv1.getVisibility());
-                assertEquals(View.GONE, iv2.getVisibility());
+            assertSame(iv1, viewFlipper.getCurrentView());
+            assertEquals(View.VISIBLE, iv1.getVisibility());
+            assertEquals(View.GONE, iv2.getVisibility());
 
-                viewFlipper.stopFlipping();
-                assertFalse(viewFlipper.isFlipping());
-            }
+            viewFlipper.stopFlipping();
+            assertFalse(viewFlipper.isFlipping());
         });
     }
-
-    private void waitForViewFlipping(int timeout) {
-        try {
-            Thread.sleep(timeout);
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
-    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java
deleted file mode 100644
index f3b3a3e..0000000
--- a/tests/tests/widget/src/android/widget/cts/ViewGroupCtsActivity.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-package android.widget.cts;
-
-import android.app.Activity;
-import android.cts.util.CTSResult;
-import android.os.Bundle;
-import android.os.Handler;
-import android.widget.TextView;
-
-public class ViewGroupCtsActivity extends Activity {
-
-    public static final String ACTION_INVALIDATE_CHILD = "invalidateChild";
-
-    private final Handler mHandler = new Handler();
-    private static CTSResult sResult;
-    public static void setResult(CTSResult result) {
-        sResult = result;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(android.widget.cts.R.layout.viewgrouptest_stub);
-        TextView textView = (TextView)findViewById(android.widget.cts.R.id.viewgrouptest_stub);
-        textView.setText("test");
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-
-        String action = getIntent().getAction();
-        if (action.equals(ACTION_INVALIDATE_CHILD)) {
-            mHandler.postDelayed(new Runnable() {
-                public void run() {
-                    MockLinearLayout mll =
-                        (MockLinearLayout) findViewById(android.widget.cts.R.id.
-                                                                        mocklinearlayout);
-                    if (!mll.mIsInvalidateChildInParentCalled) {
-                        fail();
-                        return;
-                    }
-                    sResult.setResult(CTSResult.RESULT_OK);
-                    finish();
-                }
-            }, 2000);
-        }
-    }
-
-    private void fail() {
-        sResult.setResult(CTSResult.RESULT_FAIL);
-        finish();
-    }
-}
-
diff --git a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
index 7828570..9088ba0 100644
--- a/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ViewSwitcherTest.java
@@ -16,10 +16,16 @@
 
 package android.widget.cts;
 
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
@@ -28,73 +34,80 @@
 import android.widget.ViewSwitcher;
 import android.widget.ViewSwitcher.ViewFactory;
 
-import android.widget.cts.R;
-
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
 
 /**
  * Test {@link ViewSwitcher}.
  */
-public class ViewSwitcherTest extends AndroidTestCase {
-    private ViewSwitcher mViewSwitcher;
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewSwitcherTest {
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mViewSwitcher = null;
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
+    @Test
     public void testConstructor() {
-        new ViewSwitcher(getContext());
+        new ViewSwitcher(mContext);
 
-        new ViewSwitcher(getContext(), null);
+        new ViewSwitcher(mContext, null);
 
-        XmlPullParser parser = getContext().getResources().getXml(R.layout.viewswitcher_layout);
+        XmlPullParser parser = mContext.getResources().getXml(R.layout.viewswitcher_layout);
         AttributeSet attrs = Xml.asAttributeSet(parser);
-        new ViewSwitcher(getContext(), attrs);
+        new ViewSwitcher(mContext, attrs);
     }
 
+    @Test
     public void testSetFactory() {
-        mViewSwitcher = new ViewSwitcher(getContext());
+        final ViewSwitcher viewSwitcher = new ViewSwitcher(mContext);
 
         MockViewFactory factory = new MockViewFactory();
-        mViewSwitcher.setFactory(factory);
+        viewSwitcher.setFactory(factory);
         assertTrue(factory.hasMakeViewCalled());
     }
 
+    @Test
     public void testReset() {
-        mViewSwitcher = new ViewSwitcher(getContext());
+        final ViewSwitcher viewSwitcher = new ViewSwitcher(mContext);
 
-        ListView lv1 = new ListView(getContext());
-        ListView lv2 = new ListView(getContext());
+        ListView lv1 = new ListView(mContext);
+        ListView lv2 = new ListView(mContext);
         assertEquals(View.VISIBLE, lv1.getVisibility());
         assertEquals(View.VISIBLE, lv2.getVisibility());
-        mViewSwitcher.addView(lv1, 0);
-        mViewSwitcher.addView(lv2, 1);
+        viewSwitcher.addView(lv1, 0);
+        viewSwitcher.addView(lv2, 1);
 
-        mViewSwitcher.reset();
+        viewSwitcher.reset();
         assertEquals(View.GONE, lv1.getVisibility());
         assertEquals(View.GONE, lv2.getVisibility());
     }
 
+    @Test
     public void testGetNextView() {
-        mViewSwitcher = new ViewSwitcher(getContext());
+        final ViewSwitcher viewSwitcher = new ViewSwitcher(mContext);
 
-        ListView lv1 = new ListView(getContext());
-        ListView lv2 = new ListView(getContext());
-        mViewSwitcher.addView(lv1, 0, new ViewGroup.LayoutParams(20, 25));
-        assertSame(lv1, mViewSwitcher.getChildAt(0));
-        assertNull(mViewSwitcher.getNextView());
+        ListView lv1 = new ListView(mContext);
+        ListView lv2 = new ListView(mContext);
+        viewSwitcher.addView(lv1, 0, new ViewGroup.LayoutParams(20, 25));
+        assertSame(lv1, viewSwitcher.getChildAt(0));
+        assertNull(viewSwitcher.getNextView());
 
-        mViewSwitcher.addView(lv2, 1, new ViewGroup.LayoutParams(20, 25));
-        assertSame(lv2, mViewSwitcher.getChildAt(1));
-        assertSame(lv2, mViewSwitcher.getNextView());
+        viewSwitcher.addView(lv2, 1, new ViewGroup.LayoutParams(20, 25));
+        assertSame(lv2, viewSwitcher.getChildAt(1));
+        assertSame(lv2, viewSwitcher.getNextView());
 
-        mViewSwitcher.setDisplayedChild(1);
-        assertSame(lv1, mViewSwitcher.getNextView());
+        viewSwitcher.setDisplayedChild(1);
+        assertSame(lv1, viewSwitcher.getNextView());
 
         try {
-            ListView lv3 = new ListView(getContext());
-            mViewSwitcher.addView(lv3, 2, null);
+            ListView lv3 = new ListView(mContext);
+            viewSwitcher.addView(lv3, 2, null);
             fail("Should throw IllegalStateException here.");
         } catch (IllegalStateException e) {
         }
@@ -105,7 +118,7 @@
 
         public View makeView() {
             mMakeViewCalled = true;
-            return new ListView(getContext());
+            return new ListView(mContext);
         }
 
         public boolean hasMakeViewCalled() {
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..84eba18 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
@@ -16,71 +16,92 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 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;
 
-public class ZoomButtonTest extends ActivityInstrumentationTestCase2<ZoomButtonCtsActivity> {
+import com.android.compatibility.common.util.CtsTouchUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZoomButtonTest {
+    private static long NANOS_IN_MILLI = 1000000;
+
+    private Instrumentation mInstrumentation;
     private ZoomButton mZoomButton;
     private Activity mActivity;
 
-    public ZoomButtonTest() {
-        super("android.widget.cts", ZoomButtonCtsActivity.class);
-    }
+    @Rule
+    public ActivityTestRule<ZoomButtonCtsActivity> mActivityRule =
+            new ActivityTestRule<>(ZoomButtonCtsActivity.class);
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mZoomButton = (ZoomButton) getActivity().findViewById(R.id.zoombutton_test);
-        mActivity = getActivity();
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mZoomButton = (ZoomButton) mActivity.findViewById(R.id.zoombutton_test);
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new ZoomButton(mActivity);
 
         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);
         assertNotNull(attrs);
         new ZoomButton(mActivity, attrs);
         new ZoomButton(mActivity, attrs, 0);
-
-        try {
-            new ZoomButton(null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ZoomButton(null, null);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            new ZoomButton(null, null, 0);
-            fail("should throw NullPointerException.");
-        } catch (NullPointerException e) {
-        }
     }
 
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext1() {
+        new ZoomButton(null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext2() {
+        new ZoomButton(null, null);
+    }
+
+    @Test(expected=NullPointerException.class)
+    public void testConstructorWithNullContext3() {
+        new ZoomButton(null, null, 0);
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetEnabled() {
         assertFalse(mZoomButton.isPressed());
         mZoomButton.setEnabled(true);
@@ -99,53 +120,94 @@
     }
 
     @UiThreadTest
+    @Test
     public void testDispatchUnhandledMove() {
         assertFalse(mZoomButton.dispatchUnhandledMove(new ListView(mActivity), View.FOCUS_DOWN));
 
         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.emulateLongPressOnViewCenter(mInstrumentation, 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);
             }
-        };
+        }
     }
 
-    public void testOnTouchEvent() {
-        // Do not test. Implementation details.
+    @LargeTest
+    @Test
+    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 testOnKeyUp() {
-        // Do not test. Implementation details.
-    }
-
+    @LargeTest
+    @Test
     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/ZoomControlsTest.java b/tests/tests/widget/src/android/widget/cts/ZoomControlsTest.java
index 9b3ffba..ab0f940 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomControlsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomControlsTest.java
@@ -16,27 +16,37 @@
 
 package android.widget.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.test.InstrumentationTestCase;
-import android.test.UiThreadTest;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.ZoomControls;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 /**
  * Test {@link ZoomControls}.
  */
-public class ZoomControlsTest extends InstrumentationTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZoomControlsTest {
     private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getContext();
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
     @UiThreadTest
+    @Test
     public void testConstructor() {
         new ZoomControls(mContext);
 
@@ -44,29 +54,25 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetOnZoomInClickListener() {
         ZoomControls zoomControls = new ZoomControls(mContext);
 
         // normal parameters
-        final MockOnClickListener clickListener = new MockOnClickListener();
+        final View.OnClickListener clickListener = (View view) -> {};
         zoomControls.setOnZoomInClickListener(clickListener);
 
         // exceptional parameters
         zoomControls.setOnZoomInClickListener(null);
     }
 
-    private class MockOnClickListener implements OnClickListener {
-        public void onClick(View v) {
-            // ignore
-        }
-    }
-
     @UiThreadTest
+    @Test
     public void testSetOnZoomOutClickListener() {
         ZoomControls zoomControls = new ZoomControls(mContext);
 
         // normal parameters
-        final MockOnClickListener clickListener = new MockOnClickListener();
+        final View.OnClickListener clickListener = (View view) -> {};
         zoomControls.setOnZoomOutClickListener(clickListener);
 
         // exceptional parameters
@@ -74,6 +80,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetZoomSpeed() {
         ZoomControls zoomControls = new ZoomControls(mContext);
 
@@ -82,11 +89,8 @@
         // TODO: how to check?
     }
 
-    public void testOnTouchEvent() {
-        // onTouchEvent() is implementation details, do NOT test
-    }
-
     @UiThreadTest
+    @Test
     public void testShowAndHide() {
         final ZoomControls zoomControls = new ZoomControls(mContext);
         assertEquals(View.VISIBLE, zoomControls.getVisibility());
@@ -99,6 +103,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetIsZoomInEnabled() {
         ZoomControls zoomControls = new ZoomControls(mContext);
         zoomControls.setIsZoomInEnabled(false);
@@ -106,6 +111,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testSetIsZoomOutEnabled() {
         ZoomControls zoomControls = new ZoomControls(mContext);
         zoomControls.setIsZoomOutEnabled(false);
@@ -113,6 +119,7 @@
     }
 
     @UiThreadTest
+    @Test
     public void testHasFocus() {
         ZoomControls zoomControls = new ZoomControls(mContext);
         assertFalse(zoomControls.hasFocus());
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..a0711e2
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/appwidget/MyAppWidgetProvider.java
@@ -0,0 +1,178 @@
+/*
+ * 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.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.widget.RemoteViews;
+import android.widget.cts.R;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+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..e70b4c2 100644
--- a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
@@ -16,18 +16,35 @@
 
 package android.widget.cts.util;
 
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.argThat;
+
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.ColorStateList;
 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 com.android.compatibility.common.util.WidgetTestUtils;
+
 import junit.framework.Assert;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 public class TestUtils {
@@ -100,7 +117,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 +127,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 +155,7 @@
         view.draw(canvas);
 
         try {
-            assertAllPixelsOfColor(failMessagePrefix, bitmap, view.getWidth(), view.getHeight(),
+            assertAllPixelsOfColor(failMessagePrefix, bitmap, region,
                     color, allowedComponentVariance, throwExceptionIfFails);
         } finally {
             bitmap.recycle();
@@ -126,7 +163,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 +174,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 +200,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 +242,248 @@
             }
         }
     }
-}
\ No newline at end of file
+
+    /**
+     * 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());
+        }
+    }
+
+}
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/tests/tvprovider/Android.mk b/tests/tvprovider/Android.mk
index 1b90a79..2ac45a2 100644
--- a/tests/tvprovider/Android.mk
+++ b/tests/tvprovider/Android.mk
@@ -18,7 +18,7 @@
 # don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tvprovider/AndroidTest.xml b/tests/tvprovider/AndroidTest.xml
index 36c423d..633ebef 100644
--- a/tests/tvprovider/AndroidTest.xml
+++ b/tests/tvprovider/AndroidTest.xml
@@ -22,5 +22,6 @@
         <option name="package" value="android.tvprovider.cts" />
         <!-- test-timeout unit is ms, value = 30 min -->
         <option name="test-timeout" value="1800000" />
+        <option name="runtime-hint" value="8m" />
     </test>
 </configuration>
diff --git a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
index 411bd24..e9c7ae0 100644
--- a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
+++ b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
@@ -24,7 +24,6 @@
 import android.content.ContentValues;
 import android.content.OperationApplicationException;
 import android.content.pm.PackageManager;
-import android.cts.util.CtsAndroidTestCase;
 import android.database.Cursor;
 import android.media.tv.TvContract;
 import android.media.tv.TvContract.Channels;
@@ -32,6 +31,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.MeasureRun;
 import com.android.compatibility.common.util.MeasureTime;
diff --git a/tests/ui/Android.mk b/tests/ui/Android.mk
index 3d13489..0ad32d1 100644
--- a/tests/ui/Android.mk
+++ b/tests/ui/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/ui/AndroidTest.xml b/tests/ui/AndroidTest.xml
index 3953e79..ca0b63e 100644
--- a/tests/ui/AndroidTest.xml
+++ b/tests/ui/AndroidTest.xml
@@ -20,7 +20,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.ui.cts" />
-        <option name="runtime-hint" value="5m" />
+        <option name="runtime-hint" value="12m" />
         <!-- test-timeout unit is ms, value = 30 min -->
         <option name="test-timeout" value="1800000" />
     </test>
diff --git a/tests/video/Android.mk b/tests/video/Android.mk
index 5348731..d7b91d9 100644
--- a/tests/video/Android.mk
+++ b/tests/video/Android.mk
@@ -23,7 +23,7 @@
 # include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil compatibility-device-util ctstestrunner
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libnativehelper_compat_libc++
 
diff --git a/tests/video/AndroidTest.xml b/tests/video/AndroidTest.xml
index 647ef31..30b1160 100644
--- a/tests/video/AndroidTest.xml
+++ b/tests/video/AndroidTest.xml
@@ -22,5 +22,6 @@
         <option name="package" value="android.video.cts" />
         <!-- test-timeout unit is ms, value = 10 min -->
         <option name="test-timeout" value="600000" />
+        <option name="runtime-hint" value="42m45s" />
     </test>
 </configuration>
diff --git a/tests/video/src/android/video/cts/CodecInfo.java b/tests/video/src/android/video/cts/CodecInfo.java
index e1ed78f..4309a96 100644
--- a/tests/video/src/android/video/cts/CodecInfo.java
+++ b/tests/video/src/android/video/cts/CodecInfo.java
@@ -16,7 +16,7 @@
 
 package android.video.cts;
 
-import android.cts.util.MediaUtils;
+import com.android.compatibility.common.util.MediaUtils;
 
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
diff --git a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
index 9bd1fcf..7b1dc11 100644
--- a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
+++ b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
@@ -16,8 +16,6 @@
 
 package android.video.cts;
 
-import android.cts.util.MediaPerfUtils;
-import android.cts.util.MediaUtils;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
 import android.media.Image;
@@ -34,8 +32,10 @@
 import android.util.Pair;
 import android.util.Range;
 
-import android.cts.util.CtsAndroidTestCase;
+import com.android.compatibility.common.util.CtsAndroidTestCase;
 import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.MediaPerfUtils;
+import com.android.compatibility.common.util.MediaUtils;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
diff --git a/tests/vr/AndroidTest.xml b/tests/vr/AndroidTest.xml
index a687370..dc6d5fa 100644
--- a/tests/vr/AndroidTest.xml
+++ b/tests/vr/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -19,5 +20,6 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.vr.cts" />
+        <option name="runtime-hint" value="13m" />
     </test>
 </configuration>
diff --git a/tools/cts-api-coverage/src/MANIFEST.mf b/tools/cts-api-coverage/src/MANIFEST.mf
index 63d6674..16533b5 100644
--- a/tools/cts-api-coverage/src/MANIFEST.mf
+++ b/tools/cts-api-coverage/src/MANIFEST.mf
@@ -1,3 +1,3 @@
 Manifest-Version: 1.0
 Main-Class: com.android.cts.apicoverage.CtsApiCoverage
-Class-Path: tradefed-prebuilt.jar
+Class-Path: tradefed.jar
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 3e935ca..16a9e5f 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -80,10 +80,14 @@
 fi;
 
 JAR_DIR=${CTS_ROOT}/android-cts/tools
-JARS="tradefed-prebuilt
+JARS="tradefed
   hosttestlib
   compatibility-host-util
-  cts-tradefed"
+  compatibility-host-util-tests
+  cts-tradefed
+  cts-tradefed-tests
+  compatibility-common-util-tests
+  compatibility-tradefed-tests"
 
 for JAR in $JARS; do
     checkFile ${JAR_DIR}/${JAR}.jar
@@ -96,7 +100,7 @@
   google-tf-prod-tests"
 
 for JAR in $OPTIONAL_JARS; do
-    if [ -f "$JAR.jar" ]; then
+    if [ -f "${JAR_DIR}/${JAR}.jar" ]; then
         JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
     fi;
 done
diff --git a/tools/cts-tradefed/res/config/collect-tests-only.xml b/tools/cts-tradefed/res/config/collect-tests-only.xml
index fea3f3d..7a2f913 100644
--- a/tools/cts-tradefed/res/config/collect-tests-only.xml
+++ b/tools/cts-tradefed/res/config/collect-tests-only.xml
@@ -22,7 +22,7 @@
          them as passed.
          Obviously no one would modify the report before uploading to falsify this
          information, as that would be dishonest, and dishonesty kills kittens :'( -->
-    <option name="compatibility:plan" value="collect-tests-only" />
+    <option name="plan" value="collect-tests-only" />
 
     <option name="skip-preconditions" value="true" />
     <option name="skip-connectivity-check" value="true" />
diff --git a/tools/cts-tradefed/res/config/cts-automated.xml b/tools/cts-tradefed/res/config/cts-automated.xml
index c42b97b..bedfb15 100644
--- a/tools/cts-tradefed/res/config/cts-automated.xml
+++ b/tools/cts-tradefed/res/config/cts-automated.xml
@@ -17,15 +17,16 @@
 
     <include name="cts" />
 
-    <option name="compatibility:plan" value="cts" />
+    <option name="plan" value="cts" />
 
     <option name="skip-preconditions" value="false" />
     <option name="skip-connectivity-check" value="false" />
 
-    <!-- Tell all AndroidJUnitTests to only list the tests -->
+    <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
 
-    <!-- Tell all HostTests to only list the tests -->
+    <!-- Tell all HostTests to exclude certain annotations -->
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
+    <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
 
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-camera.xml b/tools/cts-tradefed/res/config/cts-camera.xml
index 5bc395d..47377b4 100644
--- a/tools/cts-tradefed/res/config/cts-camera.xml
+++ b/tools/cts-tradefed/res/config/cts-camera.xml
@@ -17,7 +17,7 @@
 
     <include name="cts" />
 
-    <option name="compatibility:plan" value="cts-camera" />
+    <option name="plan" value="cts-camera" />
 
     <!-- All camera CTS tests -->
     <option name="compatibility:include-filter" value="CtsCameraTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-dev.xml b/tools/cts-tradefed/res/config/cts-dev.xml
index 0cf53ca..97c3cdd 100644
--- a/tools/cts-tradefed/res/config/cts-dev.xml
+++ b/tools/cts-tradefed/res/config/cts-dev.xml
@@ -21,7 +21,7 @@
     <option name="skip-preconditions" value="true" />
     <option name="skip-device-info" value="true" />
 
-    <option name="compatibility:plan" value="cts-dev" />
+    <option name="plan" value="cts-dev" />
     <option name="compatibility:skip-all-system-status-check" value="true" />
     <option name="compatibility:primary-abi-only" value="true" />
 
diff --git a/tools/cts-tradefed/res/config/cts-filtered-sample.xml b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
index 73b98c5..eb4c99a 100644
--- a/tools/cts-tradefed/res/config/cts-filtered-sample.xml
+++ b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
@@ -17,7 +17,7 @@
 
     <include name="common-compatibility-config" />
 
-    <option name="compatibility:plan" value="cts-filtered-sample" />
+    <option name="plan" value="cts-filtered-sample" />
 
     <!-- Tell all AndroidJUnitTests to only run the medium sized tests -->
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:size:medium" />
diff --git a/tools/cts-tradefed/res/config/cts-java.xml b/tools/cts-tradefed/res/config/cts-java.xml
index 52c25c9..722d8f7 100644
--- a/tools/cts-tradefed/res/config/cts-java.xml
+++ b/tools/cts-tradefed/res/config/cts-java.xml
@@ -17,7 +17,7 @@
 
     <include name="cts" />
 
-    <option name="compatibility:plan" value="cts-java" />
+    <option name="plan" value="cts-java" />
 
     <!-- Include CtsLibcoreTestCases -->
     <option name="compatibility:include-filter" value="CtsLibcoreTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 2f66e0e..72b65e0 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -23,12 +23,6 @@
     <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText" />
     <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend" />
 
-    <!-- b/23776083 -->
-    <option name="compatibility:exclude-filter" value="CtsAlarmClockTestCases" />
-
-    <!-- b/31156007 will need framework fix https://android.googlesource.com/platform/frameworks/base/+/20488d97cdc9aa7e98f6fd75c2890ba18781654a -->
-    <option name="compatibility:exclude-filter" value="CtsAppSecurityHostTestCases android.appsecurity.cts.ScopedDirectoryAccessTest#testDeniesOnceForAllClearedWhenPackageRemoved" />
-
     <!-- b/17993121 -->
     <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks" />
     <option name="compatibility:exclude-filter" value="CtsAppWidgetTestCases android.appwidget.cts.AppWidgetTest#testBindAppWidget" />
@@ -45,17 +39,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" />
 
@@ -67,64 +50,68 @@
     <!-- b/23008511 -->
     <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.cts.CameraTest#testPreviewFpsRange" />
 
+    <!-- These test cases are only applicable to Android Auto Embedded targets.-->
     <option name="compatibility:exclude-filter" value="CtsCarTestCases" />
 
     <!-- b/23776893 -->
     <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput" />
     <option name="compatibility:exclude-filter" value="CtsDumpsysHostTestCases android.dumpsys.cts.DumpsysHostTest#testGfxinfoFramestats" />
 
-    <!-- b/31199016 will need platform fix https://android.googlesource.com/platform/frameworks/base/+/11a84b8429c2cf395b99c852d232a490ba1c9975 to pass -->
-    <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.drawable.cts.ThemedDrawableTest#testLayerDrawable" />
-
-    <!-- b/31306911 will need platform fixes
-         https://android.googlesource.com/platform/frameworks/base/+/0a815bb94fa2aad016a10fe23633efc5682d2a7c and
-         https://android.googlesource.com/platform/frameworks/base/+/0c03664fa6acbe5c3fd11d54ab9a6792f43dda07 to pass -->
-    <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.drawable.cts.CustomAnimationScaleListDrawableTest#testNonZeroDurationScale" />
-    <option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.drawable.cts.CustomAnimationScaleListDrawableTest#testZeroDurationScale" />
-
     <!-- b/22922206 b/27534791 -->
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGravity_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGravity_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_flush" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testPressure_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testPressure_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_flush" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_fastest_batching" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorIntegrationTests#testSensorsMovingRates" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorIntegrationTests#testSensorsWithSeveralClients" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorTest#testBatchAndFlush" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SensorTest#testSensorTimeStamps" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testGyroscope_15hz" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testGyroscope_1hz" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticField_1hz" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticField_50hz" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testMagneticFieldUncalibrated_200hz" />
-    <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.SingleSensorTests#testOrientation_5hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testAccelerometer_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testGravity_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testGravity_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_50hz_flush" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testGyroscope_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testLinearAcceleration_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testMagneticField_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testMagneticFieldUncalibrated_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testPressure_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testPressure_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_50hz_flush" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorBatchingTests#testRotationVector_fastest_batching" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorIntegrationTests#testSensorsMovingRates" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorIntegrationTests#testSensorsWithSeveralClients" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorTest#testBatchAndFlush" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorTest#testSensorTimeStamps" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testGyroscope_15hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testGyroscope_1hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testMagneticField_1hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testMagneticField_50hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testMagneticFieldUncalibrated_200hz" />
+    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SingleSensorTests#testOrientation_5hz" />
 
-    <!-- b/31153233 will need platform fix https://android.googlesource.com/platform/external/apache-harmony/+/5617ae1cb798e58748946c0fa4299f5d982c7b8b to pass -->
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayArgConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayCharsetConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayIntIntCharsetConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayIntIntConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayIntIntStringConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_ByteArrayStringConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_CharArrayConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_CharArrayIntIntConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_IntArrayIntIntConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_StringBufferConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_StringBuilderConstructor" />
-    <option name="compatibility:exclude-filter" value="CtsJdwpTestCases org.apache.harmony.jpda.tests.jdwp.ClassType.NewInstanceStringTest#testNewInstanceString_StringConstructor" />
+    <!-- b/16720689 -->
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch002" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch003" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch004" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger001#testDebugger002" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger002#testDebugger" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTest#testClassUnloadEvent" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnteredTest#testMonitorContendedEnteredForClassMatch" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnterTest#testMonitorContendedEnterForClassMatch" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassExclude" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchExact" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchFirst" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchSecond" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassOnly" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassExclude" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchExact" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchFirst" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchSecond" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassOnly" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.ClassFileVersionTest#testClassFileVersion001" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ReferenceType.NestedTypesTest#testNestedTypes001" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.ThreadReference.StopTest#testStop001" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.HoldEventsTest#testHoldEvents001" />
+    <option name="compatibility:exclude-filter" value="CtsJdwp org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ReleaseEventsTest#testReleaseEvents001" />
 
     <!-- b/18117279 b/21262226 b/23144425 -->
     <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withMobile" />
@@ -133,24 +120,6 @@
     <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintFails_withMobile" />
     <option name="compatibility:exclude-filter" value="CtsJobSchedulerTestCases android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline" />
 
-    <!-- b/31157079 will need platform fix https://android.googlesource.com/platform/libcore/+/4149edc81ea22ef954aa443e0c70e5d3cb55341b to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases libcore.java.util.TimeZoneTest#testDisplayNamesWithScript" />
-
-    <!-- b/31157557 will need platform fix https://android.googlesource.com/platform/libcore/+/7b7ce9368f104eef4cf337a8a2067e5cf345ccc0 to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases libcore.java.net.SocketTest#testSocketTestAllAddresses" />
-
-    <!-- b/31305368 will need platform fix https://android.googlesource.com/platform/external/conscrypt/+/f24631e45c6bef8135cd9e82bfb30cf56fd8acb6 to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases libcore.javax.crypto.MacTest#testMac_correctAlias" />
-
-    <!-- b/31151341 will need platform fix https://android.googlesource.com/platform/libcore/+/4a2b94a98213fcf628f6d4de034a109695d908cc to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases libcore.net.MimeUtilsTest#test_30793548" />
-
-    <!-- b/31155940 will need platform fix https://android.googlesource.com/platform/libcore/+/08e9e364940586cb242839c8f0e303b82438f58b to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLibcoreTestCases org.apache.harmony.tests.java.util.VectorTest#test_listIterator_addAndPrevious" />
-
-    <!-- b/31535558 will need platform fix https://android.googlesource.com/platform/frameworks/base/+/4e82fe51207bbd8ceaec356b4215e338ec63a31e to pass -->
-    <option name="compatibility:exclude-filter" value="CtsLocationTestCases android.location.cts.GnssStatusTest#testGnssStatusChanges" />
-
     <!-- b/25850508 -->
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testCopyMediaFiles" />
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testMediaFilesExistOnDeviceFalse" />
@@ -164,6 +133,22 @@
     <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW" />
     <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW" />
 
+    <!-- b/30932589 -->
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromExifByteOrderIIJpeg" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromExifByteOrderMMJpeg" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromLgG4Iso800Dng" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testDoNotFailOnCorruptedImage" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromVolantisJpg" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromSonyRX100Arw" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromCanonG7XCr2" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromFujiX20Raf" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromNikon1AW1Nef" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromNikonP330Nrw" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromOlympusEPL3Orf" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromPanasonicGM5Rw2" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromPentaxK5Pef" />
+    <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.ExifInterfaceTest#testReadExifDataFromSamsungNX3000Srw" />
+
     <!-- b/25651805 -->
     <option name="compatibility:exclude-filter" value="CtsNetTestCases android.net.cts.ConnectivityManagerTest#testRestrictedNetworks" />
     <!-- b/18682315 -->
@@ -179,9 +164,6 @@
     <!-- b/18091590 -->
     <option name="compatibility:exclude-filter" value="CtsOpenGlPerfTestCases android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers" />
 
-    <!-- b/31306874 will need platform fix https://android.googlesource.com/platform/frameworks/base/+/5eb91a437c551ed0c66b38299f988f8159ada207 to pass -->
-    <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.AsyncTaskTest#testCancellationWithException" />
-
     <!-- b/23192492 -->
     <option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts" />
 
@@ -202,9 +184,6 @@
     <!-- b/26150806 -->
     <option name="compatibility:exclude-filter" value="CtsSignatureTestCases android.signature.cts.tests" />
 
-    <!-- b/23427621 -->
-    <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases" />
-
     <!-- b/27873815 -->
     <option name="compatibility:exclude-filter" value="arm64-v8a CtsRenderscriptLegacyTestCases" />
     <option name="compatibility:exclude-filter" value="x86_64 CtsRenderscriptLegacyTestCases" />
@@ -223,9 +202,6 @@
     <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testPackageUsageStatsIntervals" />
     <option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.UsageStatsTest#testUsageEventsParceling" />
 
-    <!-- b/31469490 -->
-    <option name="compatibility:exclude-filter" value="CtsViewTestCases android.view.cts.DragDropTest" />
-
     <!-- b/23238984 -->
     <option name="compatibility:exclude-filter" value="CtsVoiceSettingsTestCases android.voicesettings.cts.ZenModeTest#testAll" />
 
diff --git a/tools/cts-tradefed/res/config/cts-pdk.xml b/tools/cts-tradefed/res/config/cts-pdk.xml
index 32dcecc..f403b8b 100644
--- a/tools/cts-tradefed/res/config/cts-pdk.xml
+++ b/tools/cts-tradefed/res/config/cts-pdk.xml
@@ -17,7 +17,7 @@
 
     <include name="cts" />
 
-    <option name="compatibility:plan" value="cts-pdk" />
+    <option name="plan" value="cts-pdk" />
 
     <!-- Include test modules -->
     <option name="compatibility:include-filter" value="CtsAadbHostTestCases" />
@@ -30,6 +30,7 @@
     <option name="compatibility:include-filter" value="CtsDeqpTestCases" />
     <option name="compatibility:include-filter" value="CtsRenderscriptTestCases" />
     <option name="compatibility:include-filter" value="CtsRenderscriptLegacyTestCases" />
+    <option name="compatibility:include-filter" value="CtsSensorTestCases" />
     <option name="compatibility:include-filter" value="CtsTelephonyTestCases" />
     <option name="compatibility:include-filter" value="CtsTelephony2TestCases" />
     <option name="compatibility:include-filter" value="CtsRsBlasTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-preconditions.xml b/tools/cts-tradefed/res/config/cts-preconditions.xml
index 3430576..372c272 100644
--- a/tools/cts-tradefed/res/config/cts-preconditions.xml
+++ b/tools/cts-tradefed/res/config/cts-preconditions.xml
@@ -15,7 +15,7 @@
 -->
 <configuration description="CTS precondition configs">
 
-    <option name="compatibility:plan" value="cts-preconditions" />
+    <option name="plan" value="cts-preconditions" />
 
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="host" />
diff --git a/tools/cts-tradefed/res/config/cts-presubmit.xml b/tools/cts-tradefed/res/config/cts-presubmit.xml
new file mode 100644
index 0000000..3f721f1
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-presubmit.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.
+-->
+<configuration description="Runs CTS presubmit test cases">
+
+    <include name="cts-automated" />
+
+    <option name="plan" value="cts" />
+
+    <!-- Include modules with presubmit test cases. -->
+    <option name="compatibility:include-filter" value="CtsAccountManagerTestCases" />
+
+    <!-- Only run tests with @Presubmit annotation. -->
+    <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+    <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.Presubmit" />
+    <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-virtual-device.xml b/tools/cts-tradefed/res/config/cts-virtual-device.xml
new file mode 100644
index 0000000..10945f0
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-virtual-device.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.
+-->
+<configuration description="Runs CTS with common options set for an automated run on userdebug/eng builds, and per module rules suitable for virtual devices">
+
+    <include name="cts-automated" />
+
+    <!-- add per module rules for virtual devices below -->
+    <option name="compatibility:module-arg" value="CtsDevicePolicyManagerTestCases:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+    <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES2.functional.prerequisite#*" />
+    <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-EGL.*" />
+    <option name="compatibility:module-arg" value="CtsLibcoreTestCases:core-expectation:/virtualdeviceknownfailures.txt" />
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
index 2eb0c3e..8ce1f26 100644
--- a/tools/cts-tradefed/res/config/cts.xml
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -19,7 +19,8 @@
     <include name="cts-preconditions" />
     <include name="cts-known-failures" />
 
-    <option name="compatibility:plan" value="cts" />
+    <option name="plan" value="cts" />
+    <option name="test-tag" value="cts" />
 
     <option name="enable-root" value="false" />
 
diff --git a/tools/cts-tradefed/tests/Android.mk b/tools/cts-tradefed/tests/Android.mk
index 280cdfb..2a391c0 100644
--- a/tools/cts-tradefed/tests/Android.mk
+++ b/tools/cts-tradefed/tests/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_MODULE := cts-tradefed-tests
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed
+# We ship the Deqp Runner tests with the CTS one to validate them.
+LOCAL_STATIC_JAVA_LIBRARIES := CtsDeqpRunnerTests
 
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
index 47e4837..68cc2fd 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
@@ -18,6 +18,7 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.util.FileUtil;
 
 import junit.framework.TestCase;
@@ -34,7 +35,6 @@
     private static final String SUITE_NAME = "CTS";
     private static final String SUITE_PLAN = "cts";
     private static final String DYNAMIC_CONFIG_URL = "";
-    private static final long START_TIME = 123456L;
 
     public void testSuiteInfoLoad() throws Exception {
         // Test the values in the manifest can be loaded
@@ -45,9 +45,11 @@
         File tests = new File(base, "testcases");
         tests.mkdirs();
         CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", DYNAMIC_CONFIG_URL);
         IBuildInfo info = provider.getBuild();
         CompatibilityBuildHelper helper = new CompatibilityBuildHelper(info);
-        helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
         assertEquals("Incorrect suite full name", SUITE_FULL_NAME, helper.getSuiteFullName());
         assertEquals("Incorrect suite name", SUITE_NAME, helper.getSuiteName());
         FileUtil.recursiveDelete(root);
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index f1219c1..31ee446 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,7 +18,8 @@
 
 package android.cts.security;
 
-import com.android.cts.migration.MigrationHelper;
+import android.platform.test.annotations.RestrictedBuildTest;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -63,7 +64,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */
@@ -77,6 +79,7 @@
 """
 
 src_method = """
+    @RestrictedBuildTest
     public void testNeverallowRules() throws Exception {
         String neverallowRule = "$NEVERALLOW_RULE_HERE$";
 
diff --git a/tools/utils/Android.mk b/tools/utils/Android.mk
index ef2e1bb..6b01e57 100644
--- a/tools/utils/Android.mk
+++ b/tools/utils/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
-LOCAL_JAVA_LIBRARIES := junit-host
+LOCAL_JAVA_LIBRARIES := junit-host tradefed
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-host-util vogarexpectlib
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/utils/CollectAllTests.java b/tools/utils/CollectAllTests.java
index 8003f4d..cd85e0c 100644
--- a/tools/utils/CollectAllTests.java
+++ b/tools/utils/CollectAllTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.util.AbiUtils;
 
 import org.junit.runner.RunWith;
 import org.w3c.dom.Document;
diff --git a/tools/utils/VogarUtils.java b/tools/utils/VogarUtils.java
index 77c62da..8657aa6 100644
--- a/tools/utils/VogarUtils.java
+++ b/tools/utils/VogarUtils.java
@@ -19,7 +19,7 @@
 import vogar.ModeId;
 import vogar.Result;
 
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.util.AbiUtils;
 
 import java.io.File;
 import java.io.FilenameFilter;
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',
       ],
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 1aac2f6..6d47303 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -86,8 +86,8 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_JACK_VERSION := $(LOCAL_JACK_VERSION)
 oj_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj,,COMMON)/classes.jack
 libart_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)/classes.jack
-$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
-$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar | setup-jack-server
+$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar
+$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar | setup-jack-server
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
 	# generated and compile the host side junit tests
diff --git a/tools/vm-tests-tf/AndroidTest.xml b/tools/vm-tests-tf/AndroidTest.xml
index 35db3ad..b703d0c 100644
--- a/tools/vm-tests-tf/AndroidTest.xml
+++ b/tools/vm-tests-tf/AndroidTest.xml
@@ -17,5 +17,6 @@
     <target_preparer class="android.core.vm.targetprep.VmTestPreparer" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="android.core.vm-tests-tf.jar" />
+        <option name="runtime-hint" value="51m" />
     </test>
 </configuration>
diff --git a/tools/vm-tests-tf/targetprep/Android.mk b/tools/vm-tests-tf/targetprep/Android.mk
index 8abde93..a05b658 100644
--- a/tools/vm-tests-tf/targetprep/Android.mk
+++ b/tools/vm-tests-tf/targetprep/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 LOCAL_MODULE_TAGS := optional